mirror of
https://github.com/smallmain/cocos-enhance-kit.git
synced 2025-10-09 12:45:23 +00:00
初始化
This commit is contained in:
31
cocos2d-x/cocos/platform/android/Android.mk
Normal file
31
cocos2d-x/cocos/platform/android/Android.mk
Normal file
@@ -0,0 +1,31 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := cocos2dxandroid_static
|
||||
|
||||
LOCAL_MODULE_FILENAME := libcocos2dandroid
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
CCDevice-android.cpp \
|
||||
CCFileUtils-android.cpp \
|
||||
CCApplication-android.cpp \
|
||||
CCCanvasRenderingContext2D-android.cpp \
|
||||
jni/JniImp.cpp \
|
||||
jni/JniHelper.cpp \
|
||||
|
||||
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
|
||||
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH) \
|
||||
$(LOCAL_PATH)/.. \
|
||||
$(LOCAL_PATH)/../.. \
|
||||
$(LOCAL_PATH)/../../..
|
||||
|
||||
LOCAL_EXPORT_LDLIBS := -lGLESv2 \
|
||||
-lEGL \
|
||||
-llog \
|
||||
-landroid
|
||||
|
||||
LOCAL_STATIC_LIBRARIES := v8_static
|
||||
|
||||
include $(BUILD_STATIC_LIBRARY)
|
307
cocos2d-x/cocos/platform/android/CCApplication-android.cpp
Normal file
307
cocos2d-x/cocos/platform/android/CCApplication-android.cpp
Normal file
@@ -0,0 +1,307 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2010-2012 cocos2d-x.org
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
#include "platform/CCApplication.h"
|
||||
#include <EGL/egl.h>
|
||||
#include <cstring>
|
||||
#include <jni.h>
|
||||
#include "platform/android/jni/JniImp.h"
|
||||
#include "platform/android/CCGL-android.h"
|
||||
#include "base/CCScheduler.h"
|
||||
#include "base/CCConfiguration.h"
|
||||
#include "audio/include/AudioEngine.h"
|
||||
#include "scripting/js-bindings/jswrapper/SeApi.h"
|
||||
#include "scripting/js-bindings/event/EventDispatcher.h"
|
||||
|
||||
#define LOG_APP_TAG "CCApplication_android Debug"
|
||||
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_APP_TAG,__VA_ARGS__)
|
||||
|
||||
// IDEA: using ndk-r10c will cause the next function could not be found. It may be a bug of ndk-r10c.
|
||||
// Here is the workaround method to fix the problem.
|
||||
#ifdef __aarch64__
|
||||
extern "C" size_t __ctype_get_mb_cur_max(void)
|
||||
{
|
||||
return (size_t) sizeof(wchar_t);
|
||||
}
|
||||
#endif
|
||||
|
||||
PFNGLGENVERTEXARRAYSOESPROC glGenVertexArraysOESEXT = 0;
|
||||
PFNGLBINDVERTEXARRAYOESPROC glBindVertexArrayOESEXT = 0;
|
||||
PFNGLDELETEVERTEXARRAYSOESPROC glDeleteVertexArraysOESEXT = 0;
|
||||
|
||||
NS_CC_BEGIN
|
||||
|
||||
void Application::updateViewSize(int width, int height)
|
||||
{
|
||||
_viewSize.x = width;
|
||||
_viewSize.y = height;
|
||||
|
||||
// handle resize event
|
||||
Application::getInstance()->getScheduler()->performFunctionInCocosThread([=]() {
|
||||
EventDispatcher::dispatchResizeEvent(width, height);
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
void Java_org_cocos2dx_lib_Cocos2dxGLSurfaceView_nativeOnSizeChanged(JNIEnv * env, jobject obj, jint width, jint height) {
|
||||
auto inst = Application::getInstance();
|
||||
// nativeOnSizeChanged is firstly called before Application initiating.
|
||||
if (inst != nullptr) {
|
||||
inst->updateViewSize(width, height);
|
||||
}
|
||||
}
|
||||
void Java_org_cocos2dx_lib_Cocos2dxOrientationHelper_nativeOnOrientationChanged(JNIEnv * env, jobject obj, jint rotation) {
|
||||
auto inst = Application::getInstance();
|
||||
// nativeOnSizeChanged is firstly called before Application initiating.
|
||||
if (inst != nullptr) {
|
||||
// handle orientation change event
|
||||
inst->getScheduler()->performFunctionInCocosThread([=]() {
|
||||
EventDispatcher::dispatchOrientationChangeEvent(rotation);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Application* Application::_instance = nullptr;
|
||||
std::shared_ptr<Scheduler> Application::_scheduler = nullptr;
|
||||
|
||||
Application::Application(const std::string& name, int width, int height)
|
||||
{
|
||||
Application::_instance = this;
|
||||
Configuration::getInstance();
|
||||
|
||||
_scheduler = std::make_shared<Scheduler>();
|
||||
|
||||
PFNGLGENVERTEXARRAYSOESPROC glGenVertexArraysOESEXT = (PFNGLGENVERTEXARRAYSOESPROC)eglGetProcAddress("glGenVertexArraysOES");
|
||||
PFNGLBINDVERTEXARRAYOESPROC glBindVertexArrayOESEXT = (PFNGLBINDVERTEXARRAYOESPROC)eglGetProcAddress("glBindVertexArrayOES");
|
||||
PFNGLDELETEVERTEXARRAYSOESPROC glDeleteVertexArraysOESEXT = (PFNGLDELETEVERTEXARRAYSOESPROC)eglGetProcAddress("glDeleteVertexArraysOES");
|
||||
|
||||
_renderTexture = new RenderTexture(width, height);
|
||||
updateViewSize(width, height);
|
||||
}
|
||||
|
||||
Application::~Application()
|
||||
{
|
||||
#if USE_AUDIO
|
||||
AudioEngine::end();
|
||||
#endif
|
||||
|
||||
EventDispatcher::destroy();
|
||||
se::ScriptEngine::destroyInstance();
|
||||
|
||||
delete _renderTexture;
|
||||
_renderTexture = nullptr;
|
||||
|
||||
Application::_instance = nullptr;
|
||||
}
|
||||
|
||||
void Application::start()
|
||||
{
|
||||
if(!applicationDidFinishLaunching())
|
||||
return;
|
||||
}
|
||||
|
||||
void Application::restart()
|
||||
{
|
||||
restartJSVM();
|
||||
}
|
||||
|
||||
void Application::end()
|
||||
{
|
||||
exitApplication();
|
||||
}
|
||||
|
||||
void Application::setMultitouch(bool /*value*/)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool Application::applicationDidFinishLaunching()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void Application::onPause()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Application::onResume()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Application::setPreferredFramesPerSecond(int fps)
|
||||
{
|
||||
_fps = fps;
|
||||
setPreferredFramesPerSecondJNI(_fps);
|
||||
}
|
||||
|
||||
std::string Application::getCurrentLanguageCode() const
|
||||
{
|
||||
return getCurrentLanguageCodeJNI();
|
||||
}
|
||||
|
||||
bool Application::isDisplayStats() {
|
||||
se::AutoHandleScope hs;
|
||||
se::Value ret;
|
||||
char commandBuf[100] = "cc.debug.isDisplayStats();";
|
||||
se::ScriptEngine::getInstance()->evalString(commandBuf, 100, &ret);
|
||||
return ret.toBoolean();
|
||||
}
|
||||
|
||||
void Application::setDisplayStats(bool isShow) {
|
||||
se::AutoHandleScope hs;
|
||||
char commandBuf[100] = {0};
|
||||
sprintf(commandBuf, "cc.debug.setDisplayStats(%s);", isShow ? "true" : "false");
|
||||
se::ScriptEngine::getInstance()->evalString(commandBuf);
|
||||
}
|
||||
|
||||
Application::LanguageType Application::getCurrentLanguage() const
|
||||
{
|
||||
std::string languageName = getCurrentLanguageJNI();
|
||||
const char* pLanguageName = languageName.c_str();
|
||||
LanguageType ret = LanguageType::ENGLISH;
|
||||
|
||||
if (0 == strcmp("zh", pLanguageName))
|
||||
{
|
||||
ret = LanguageType::CHINESE;
|
||||
}
|
||||
else if (0 == strcmp("en", pLanguageName))
|
||||
{
|
||||
ret = LanguageType::ENGLISH;
|
||||
}
|
||||
else if (0 == strcmp("fr", pLanguageName))
|
||||
{
|
||||
ret = LanguageType::FRENCH;
|
||||
}
|
||||
else if (0 == strcmp("it", pLanguageName))
|
||||
{
|
||||
ret = LanguageType::ITALIAN;
|
||||
}
|
||||
else if (0 == strcmp("de", pLanguageName))
|
||||
{
|
||||
ret = LanguageType::GERMAN;
|
||||
}
|
||||
else if (0 == strcmp("es", pLanguageName))
|
||||
{
|
||||
ret = LanguageType::SPANISH;
|
||||
}
|
||||
else if (0 == strcmp("ru", pLanguageName))
|
||||
{
|
||||
ret = LanguageType::RUSSIAN;
|
||||
}
|
||||
else if (0 == strcmp("nl", pLanguageName))
|
||||
{
|
||||
ret = LanguageType::DUTCH;
|
||||
}
|
||||
else if (0 == strcmp("ko", pLanguageName))
|
||||
{
|
||||
ret = LanguageType::KOREAN;
|
||||
}
|
||||
else if (0 == strcmp("ja", pLanguageName))
|
||||
{
|
||||
ret = LanguageType::JAPANESE;
|
||||
}
|
||||
else if (0 == strcmp("hu", pLanguageName))
|
||||
{
|
||||
ret = LanguageType::HUNGARIAN;
|
||||
}
|
||||
else if (0 == strcmp("pt", pLanguageName))
|
||||
{
|
||||
ret = LanguageType::PORTUGUESE;
|
||||
}
|
||||
else if (0 == strcmp("ar", pLanguageName))
|
||||
{
|
||||
ret = LanguageType::ARABIC;
|
||||
}
|
||||
else if (0 == strcmp("nb", pLanguageName))
|
||||
{
|
||||
ret = LanguageType::NORWEGIAN;
|
||||
}
|
||||
else if (0 == strcmp("pl", pLanguageName))
|
||||
{
|
||||
ret = LanguageType::POLISH;
|
||||
}
|
||||
else if (0 == strcmp("tr", pLanguageName))
|
||||
{
|
||||
ret = LanguageType::TURKISH;
|
||||
}
|
||||
else if (0 == strcmp("uk", pLanguageName))
|
||||
{
|
||||
ret = LanguageType::UKRAINIAN;
|
||||
}
|
||||
else if (0 == strcmp("ro", pLanguageName))
|
||||
{
|
||||
ret = LanguageType::ROMANIAN;
|
||||
}
|
||||
else if (0 == strcmp("bg", pLanguageName))
|
||||
{
|
||||
ret = LanguageType::BULGARIAN;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
Application::Platform Application::getPlatform() const
|
||||
{
|
||||
return Platform::ANDROIDOS;
|
||||
}
|
||||
|
||||
float Application::getScreenScale() const
|
||||
{
|
||||
return 1.f;
|
||||
}
|
||||
|
||||
GLint Application::getMainFBO() const
|
||||
{
|
||||
return _mainFBO;
|
||||
}
|
||||
|
||||
void Application::onCreateView(PixelFormat& /*pixelformat*/, DepthFormat& /*depthFormat*/, int& /*multisamplingCount*/)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool Application::openURL(const std::string &url)
|
||||
{
|
||||
return openURLJNI(url);
|
||||
}
|
||||
|
||||
void Application::copyTextToClipboard(const std::string &text)
|
||||
{
|
||||
copyTextToClipboardJNI(text);
|
||||
}
|
||||
|
||||
std::string Application::getSystemVersion()
|
||||
{
|
||||
return getSystemVersionJNI();
|
||||
}
|
||||
|
||||
const cocos2d::Vec2& Application::getViewSize() const
|
||||
{
|
||||
return _viewSize;
|
||||
}
|
||||
|
||||
NS_CC_END
|
@@ -0,0 +1,619 @@
|
||||
#include "platform/CCCanvasRenderingContext2D.h"
|
||||
#include "base/ccTypes.h"
|
||||
#include "base/csscolorparser.hpp"
|
||||
|
||||
#include "cocos/scripting/js-bindings/jswrapper/SeApi.h"
|
||||
#include "platform/android/jni/JniHelper.h"
|
||||
#include "platform/android/jni/JniImp.h"
|
||||
|
||||
#include <regex>
|
||||
|
||||
#ifndef JCLS_CANVASIMPL
|
||||
#define JCLS_CANVASIMPL "org/cocos2dx/lib/CanvasRenderingContext2DImpl"
|
||||
#endif
|
||||
|
||||
using namespace cocos2d;
|
||||
|
||||
enum class CanvasTextAlign {
|
||||
LEFT,
|
||||
CENTER,
|
||||
RIGHT
|
||||
};
|
||||
|
||||
enum class CanvasTextBaseline {
|
||||
TOP,
|
||||
MIDDLE,
|
||||
BOTTOM
|
||||
};
|
||||
|
||||
class CanvasRenderingContext2DImpl
|
||||
{
|
||||
public:
|
||||
CanvasRenderingContext2DImpl()
|
||||
{
|
||||
jobject obj = JniHelper::newObject(JCLS_CANVASIMPL);
|
||||
_obj = JniHelper::getEnv()->NewGlobalRef(obj);
|
||||
JniHelper::getEnv()->DeleteLocalRef(obj);
|
||||
}
|
||||
|
||||
~CanvasRenderingContext2DImpl()
|
||||
{
|
||||
JniHelper::getEnv()->DeleteGlobalRef(_obj);
|
||||
}
|
||||
|
||||
void recreateBuffer(float w, float h)
|
||||
{
|
||||
_bufferWidth = w;
|
||||
_bufferHeight = h;
|
||||
if (_bufferWidth < 1.0f || _bufferHeight < 1.0f)
|
||||
return;
|
||||
JniHelper::callObjectVoidMethod(_obj, JCLS_CANVASIMPL, "recreateBuffer", w, h);
|
||||
fillData();
|
||||
}
|
||||
|
||||
void beginPath()
|
||||
{
|
||||
JniHelper::callObjectVoidMethod(_obj, JCLS_CANVASIMPL, "beginPath");
|
||||
}
|
||||
|
||||
void closePath()
|
||||
{
|
||||
JniHelper::callObjectVoidMethod(_obj, JCLS_CANVASIMPL, "closePath");
|
||||
}
|
||||
|
||||
void moveTo(float x, float y)
|
||||
{
|
||||
JniHelper::callObjectVoidMethod(_obj, JCLS_CANVASIMPL, "moveTo", x, y);
|
||||
}
|
||||
|
||||
void lineTo(float x, float y)
|
||||
{
|
||||
JniHelper::callObjectVoidMethod(_obj, JCLS_CANVASIMPL, "lineTo", x, y);
|
||||
}
|
||||
|
||||
void stroke()
|
||||
{
|
||||
if (_bufferWidth < 1.0f || _bufferHeight < 1.0f)
|
||||
return;
|
||||
|
||||
JniHelper::callObjectVoidMethod(_obj, JCLS_CANVASIMPL, "stroke");
|
||||
fillData();
|
||||
}
|
||||
|
||||
void fill()
|
||||
{
|
||||
if (_bufferWidth < 1.0f || _bufferHeight < 1.0f)
|
||||
return;
|
||||
|
||||
JniHelper::callObjectVoidMethod(_obj, JCLS_CANVASIMPL, "fill");
|
||||
fillData();
|
||||
}
|
||||
|
||||
void saveContext()
|
||||
{
|
||||
JniHelper::callObjectVoidMethod(_obj, JCLS_CANVASIMPL, "saveContext");
|
||||
}
|
||||
|
||||
void restoreContext()
|
||||
{
|
||||
JniHelper::callObjectVoidMethod(_obj, JCLS_CANVASIMPL, "restoreContext");
|
||||
}
|
||||
|
||||
void rect(float x, float y, float w, float h)
|
||||
{
|
||||
if (_bufferWidth < 1.0f || _bufferHeight < 1.0f)
|
||||
return;
|
||||
JniHelper::callObjectVoidMethod(_obj, JCLS_CANVASIMPL, "rect", x, y, w, h);
|
||||
fillData();
|
||||
}
|
||||
|
||||
void clearRect(float x, float y, float w, float h)
|
||||
{
|
||||
if (_bufferWidth < 1.0f || _bufferHeight < 1.0f)
|
||||
return;
|
||||
if (x >= _bufferWidth || y >= _bufferHeight)
|
||||
return;
|
||||
if (x + w > _bufferWidth)
|
||||
w = _bufferWidth - x;
|
||||
if (y + h > _bufferHeight)
|
||||
h = _bufferHeight - y;
|
||||
JniHelper::callObjectVoidMethod(_obj, JCLS_CANVASIMPL, "clearRect", x, y, w, h);
|
||||
fillData();
|
||||
}
|
||||
|
||||
void fillRect(float x, float y, float w, float h)
|
||||
{
|
||||
if (_bufferWidth < 1.0f || _bufferHeight < 1.0f)
|
||||
return;
|
||||
if (x >= _bufferWidth || y >= _bufferHeight)
|
||||
return;
|
||||
if (x + w > _bufferWidth)
|
||||
w = _bufferWidth - x;
|
||||
if (y + h > _bufferHeight)
|
||||
h = _bufferHeight - y;
|
||||
JniHelper::callObjectVoidMethod(_obj, JCLS_CANVASIMPL, "fillRect", x, y, w, h);
|
||||
fillData();
|
||||
}
|
||||
|
||||
void fillText(const std::string& text, float x, float y, float maxWidth)
|
||||
{
|
||||
if (text.empty() || _bufferWidth < 1.0f || _bufferHeight < 1.0f)
|
||||
return;
|
||||
JniHelper::callObjectVoidMethod(_obj, JCLS_CANVASIMPL, "fillText", text, x, y, maxWidth);
|
||||
fillData();
|
||||
}
|
||||
|
||||
void strokeText(const std::string& text, float x, float y, float maxWidth)
|
||||
{
|
||||
if (text.empty() || _bufferWidth < 1.0f || _bufferHeight < 1.0f)
|
||||
return;
|
||||
JniHelper::callObjectVoidMethod(_obj, JCLS_CANVASIMPL, "strokeText", text, x, y, maxWidth);
|
||||
fillData();
|
||||
}
|
||||
|
||||
float measureText(const std::string& text)
|
||||
{
|
||||
if (text.empty())
|
||||
return 0.0f;
|
||||
return JniHelper::callObjectFloatMethod(_obj, JCLS_CANVASIMPL, "measureText", text);
|
||||
}
|
||||
|
||||
void updateFont(const std::string& fontName, float fontSize, bool bold, bool italic, bool oblique, bool smallCaps)
|
||||
{
|
||||
JniHelper::callObjectVoidMethod(_obj, JCLS_CANVASIMPL, "updateFont", fontName, fontSize, bold, italic, oblique, smallCaps);
|
||||
}
|
||||
|
||||
void setLineCap(const std::string& lineCap) {
|
||||
JniHelper::callObjectVoidMethod(_obj, JCLS_CANVASIMPL, "setLineCap", lineCap);
|
||||
}
|
||||
|
||||
void setLineJoin(const std::string& lineJoin) {
|
||||
JniHelper::callObjectVoidMethod(_obj, JCLS_CANVASIMPL, "setLineJoin", lineJoin);
|
||||
}
|
||||
|
||||
void setTextAlign(CanvasTextAlign align)
|
||||
{
|
||||
JniHelper::callObjectVoidMethod(_obj, JCLS_CANVASIMPL, "setTextAlign", (int)align);
|
||||
}
|
||||
|
||||
void setTextBaseline(CanvasTextBaseline baseline)
|
||||
{
|
||||
JniHelper::callObjectVoidMethod(_obj, JCLS_CANVASIMPL, "setTextBaseline", (int)baseline);
|
||||
}
|
||||
|
||||
void setFillStyle(float r, float g, float b, float a)
|
||||
{
|
||||
JniHelper::callObjectVoidMethod(_obj, JCLS_CANVASIMPL, "setFillStyle", r, g, b, a);
|
||||
}
|
||||
|
||||
void setStrokeStyle(float r, float g, float b, float a)
|
||||
{
|
||||
JniHelper::callObjectVoidMethod(_obj, JCLS_CANVASIMPL, "setStrokeStyle", r, g, b, a);
|
||||
}
|
||||
|
||||
void setLineWidth(float lineWidth)
|
||||
{
|
||||
JniHelper::callObjectVoidMethod(_obj, JCLS_CANVASIMPL, "setLineWidth", lineWidth);
|
||||
}
|
||||
|
||||
void _fillImageData(const Data &imageData, float imageWidth, float imageHeight, float offsetX, float offsetY) {
|
||||
if (_bufferWidth < 1.0f || _bufferHeight < 1.0f)
|
||||
return;
|
||||
|
||||
jbyteArray arr = JniHelper::getEnv()->NewByteArray(imageData.getSize());
|
||||
JniHelper::getEnv()->SetByteArrayRegion(arr, 0, imageData.getSize(),
|
||||
(const jbyte *) imageData.getBytes());
|
||||
JniHelper::callObjectVoidMethod(_obj, JCLS_CANVASIMPL, "_fillImageData", arr, imageWidth,
|
||||
imageHeight, offsetX, offsetY);
|
||||
JniHelper::getEnv()->DeleteLocalRef(arr);
|
||||
|
||||
fillData();
|
||||
}
|
||||
|
||||
const Data& getDataRef() const
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
|
||||
void setPremultiply(bool multiply)
|
||||
{
|
||||
_premultiply = multiply;
|
||||
}
|
||||
|
||||
#define CLAMP(V, HI) std::min( (V), (HI) )
|
||||
void unMultiplyAlpha(unsigned char* ptr, ssize_t size)
|
||||
{
|
||||
// Android source data is not premultiplied alpha when API >= 19
|
||||
// please refer CanvasRenderingContext2DImpl::recreateBuffer(float w, float h)
|
||||
// in CanvasRenderingContext2DImpl.java
|
||||
// if (getAndroidSDKInt() >= 19)
|
||||
// return;
|
||||
|
||||
float alpha;
|
||||
for (int i = 0; i < size; i += 4)
|
||||
{
|
||||
alpha = (float)ptr[i + 3];
|
||||
if (alpha > 0)
|
||||
{
|
||||
ptr[i] = CLAMP((int)((float)ptr[i] / alpha * 255), 255);
|
||||
ptr[i+1] = CLAMP((int)((float)ptr[i+1] / alpha * 255), 255);
|
||||
ptr[i+2] = CLAMP((int)((float)ptr[i+2] / alpha * 255), 255);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void fillData()
|
||||
{
|
||||
jbyteArray arr = JniHelper::callObjectByteArrayMethod(_obj, JCLS_CANVASIMPL, "getDataRef");
|
||||
jsize len = JniHelper::getEnv()->GetArrayLength(arr);
|
||||
jbyte* jbarray = (jbyte *)malloc(len * sizeof(jbyte));
|
||||
JniHelper::getEnv()->GetByteArrayRegion(arr,0,len,jbarray);
|
||||
if (!_premultiply)
|
||||
{
|
||||
unMultiplyAlpha( (unsigned char*) jbarray, len);
|
||||
}
|
||||
_data.fastSet((unsigned char*) jbarray, len); //IDEA: DON'T create new jbarray every time.
|
||||
JniHelper::getEnv()->DeleteLocalRef(arr);
|
||||
}
|
||||
|
||||
private:
|
||||
jobject _obj = nullptr;
|
||||
Data _data;
|
||||
float _bufferWidth = 0.0f;
|
||||
float _bufferHeight = 0.0f;
|
||||
bool _premultiply = true;
|
||||
};
|
||||
|
||||
namespace {
|
||||
void fillRectWithColor(uint8_t* buf, uint32_t totalWidth, uint32_t totalHeight, uint32_t x, uint32_t y, uint32_t width, uint32_t height, uint8_t r, uint8_t g, uint8_t b)
|
||||
{
|
||||
assert(x + width <= totalWidth);
|
||||
assert(y + height <= totalHeight);
|
||||
|
||||
uint32_t y0 = totalHeight - (y + height);
|
||||
uint32_t y1 = totalHeight - y;
|
||||
uint8_t* p;
|
||||
for (uint32_t offsetY = y0; offsetY < y1; ++offsetY)
|
||||
{
|
||||
for (uint32_t offsetX = x; offsetX < (x + width); ++offsetX)
|
||||
{
|
||||
p = buf + (totalWidth * offsetY + offsetX) * 3;
|
||||
*p++ = r;
|
||||
*p++ = g;
|
||||
*p++ = b;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NS_CC_BEGIN
|
||||
|
||||
CanvasGradient::CanvasGradient()
|
||||
{
|
||||
// SE_LOGD("CanvasGradient constructor: %p\n", this);
|
||||
}
|
||||
|
||||
CanvasGradient::~CanvasGradient()
|
||||
{
|
||||
// SE_LOGD("CanvasGradient destructor: %p\n", this);
|
||||
}
|
||||
|
||||
void CanvasGradient::addColorStop(float offset, const std::string& color)
|
||||
{
|
||||
// SE_LOGD("CanvasGradient::addColorStop: %p\n", this);
|
||||
}
|
||||
|
||||
// CanvasRenderingContext2D
|
||||
|
||||
CanvasRenderingContext2D::CanvasRenderingContext2D(float width, float height)
|
||||
: __width(width)
|
||||
, __height(height)
|
||||
{
|
||||
// SE_LOGD("CanvasRenderingContext2D constructor: %p, width: %f, height: %f\n", this, width, height);
|
||||
_impl = new CanvasRenderingContext2DImpl();
|
||||
recreateBufferIfNeeded();
|
||||
}
|
||||
|
||||
CanvasRenderingContext2D::~CanvasRenderingContext2D()
|
||||
{
|
||||
// SE_LOGD("CanvasRenderingContext2D destructor: %p\n", this);
|
||||
delete _impl;
|
||||
}
|
||||
|
||||
void CanvasRenderingContext2D::recreateBufferIfNeeded()
|
||||
{
|
||||
if (_isBufferSizeDirty)
|
||||
{
|
||||
_isBufferSizeDirty = false;
|
||||
// SE_LOGD("Recreate buffer %p, w: %f, h:%f\n", this, __width, __height);
|
||||
_impl->recreateBuffer(__width, __height);
|
||||
if (_canvasBufferUpdatedCB != nullptr)
|
||||
_canvasBufferUpdatedCB(_impl->getDataRef());
|
||||
}
|
||||
}
|
||||
|
||||
void CanvasRenderingContext2D::rect(float x, float y, float width, float height)
|
||||
{
|
||||
// SE_LOGD("CanvasRenderingContext2D::rect: %p, %f, %f, %f, %f\n", this, x, y, width, height);
|
||||
recreateBufferIfNeeded();
|
||||
_impl->rect(x, y, width, height);
|
||||
}
|
||||
|
||||
void CanvasRenderingContext2D::clearRect(float x, float y, float width, float height)
|
||||
{
|
||||
// SE_LOGD("CanvasRenderingContext2D::clearRect: %p, %f, %f, %f, %f\n", this, x, y, width, height);
|
||||
recreateBufferIfNeeded();
|
||||
_impl->clearRect(x, y, width, height);
|
||||
}
|
||||
|
||||
void CanvasRenderingContext2D::fillRect(float x, float y, float width, float height)
|
||||
{
|
||||
recreateBufferIfNeeded();
|
||||
_impl->fillRect(x, y, width, height);
|
||||
|
||||
if (_canvasBufferUpdatedCB != nullptr)
|
||||
_canvasBufferUpdatedCB(_impl->getDataRef());
|
||||
}
|
||||
|
||||
void CanvasRenderingContext2D::fillText(const std::string& text, float x, float y, float maxWidth)
|
||||
{
|
||||
// SE_LOGD("CanvasRenderingContext2D::fillText: %s, %f, %f, %f\n", text.c_str(), x, y, maxWidth);
|
||||
if (text.empty())
|
||||
return;
|
||||
recreateBufferIfNeeded();
|
||||
|
||||
_impl->fillText(text, x, y, maxWidth);
|
||||
if (_canvasBufferUpdatedCB != nullptr)
|
||||
_canvasBufferUpdatedCB(_impl->getDataRef());
|
||||
}
|
||||
|
||||
void CanvasRenderingContext2D::strokeText(const std::string& text, float x, float y, float maxWidth)
|
||||
{
|
||||
// SE_LOGD("CanvasRenderingContext2D::strokeText: %s, %f, %f, %f\n", text.c_str(), x, y, maxWidth);
|
||||
if (text.empty())
|
||||
return;
|
||||
recreateBufferIfNeeded();
|
||||
|
||||
_impl->strokeText(text, x, y, maxWidth);
|
||||
|
||||
if (_canvasBufferUpdatedCB != nullptr)
|
||||
_canvasBufferUpdatedCB(_impl->getDataRef());
|
||||
}
|
||||
|
||||
cocos2d::Size CanvasRenderingContext2D::measureText(const std::string& text)
|
||||
{
|
||||
// SE_LOGD("CanvasRenderingContext2D::measureText: %s\n", text.c_str());
|
||||
return cocos2d::Size(_impl->measureText(text), 0);
|
||||
}
|
||||
|
||||
CanvasGradient* CanvasRenderingContext2D::createLinearGradient(float x0, float y0, float x1, float y1)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void CanvasRenderingContext2D::save()
|
||||
{
|
||||
_impl->saveContext();
|
||||
}
|
||||
|
||||
void CanvasRenderingContext2D::beginPath()
|
||||
{
|
||||
_impl->beginPath();
|
||||
}
|
||||
|
||||
void CanvasRenderingContext2D::closePath()
|
||||
{
|
||||
_impl->closePath();
|
||||
}
|
||||
|
||||
void CanvasRenderingContext2D::moveTo(float x, float y)
|
||||
{
|
||||
_impl->moveTo(x, y);
|
||||
}
|
||||
|
||||
void CanvasRenderingContext2D::lineTo(float x, float y)
|
||||
{
|
||||
_impl->lineTo(x, y);
|
||||
}
|
||||
|
||||
void CanvasRenderingContext2D::stroke()
|
||||
{
|
||||
_impl->stroke();
|
||||
|
||||
if (_canvasBufferUpdatedCB != nullptr)
|
||||
_canvasBufferUpdatedCB(_impl->getDataRef());
|
||||
}
|
||||
|
||||
void CanvasRenderingContext2D::fill()
|
||||
{
|
||||
_impl->fill();
|
||||
|
||||
if (_canvasBufferUpdatedCB != nullptr)
|
||||
_canvasBufferUpdatedCB(_impl->getDataRef());
|
||||
}
|
||||
|
||||
void CanvasRenderingContext2D::restore()
|
||||
{
|
||||
_impl->restoreContext();
|
||||
}
|
||||
|
||||
void CanvasRenderingContext2D::setCanvasBufferUpdatedCallback(const CanvasBufferUpdatedCallback& cb)
|
||||
{
|
||||
_canvasBufferUpdatedCB = cb;
|
||||
}
|
||||
|
||||
void CanvasRenderingContext2D::setPremultiply(bool multiply)
|
||||
{
|
||||
_impl->setPremultiply(multiply);
|
||||
}
|
||||
|
||||
void CanvasRenderingContext2D::set__width(float width)
|
||||
{
|
||||
// SE_LOGD("CanvasRenderingContext2D::set__width: %f\n", width);
|
||||
__width = width;
|
||||
_isBufferSizeDirty = true;
|
||||
recreateBufferIfNeeded();
|
||||
}
|
||||
|
||||
void CanvasRenderingContext2D::set__height(float height)
|
||||
{
|
||||
// SE_LOGD("CanvasRenderingContext2D::set__height: %f\n", height);
|
||||
__height = height;
|
||||
_isBufferSizeDirty = true;
|
||||
recreateBufferIfNeeded();
|
||||
}
|
||||
|
||||
void CanvasRenderingContext2D::set_lineWidth(float lineWidth)
|
||||
{
|
||||
_lineWidth = lineWidth;
|
||||
_impl->setLineWidth(lineWidth);
|
||||
}
|
||||
|
||||
void CanvasRenderingContext2D::set_lineJoin(const std::string& lineJoin)
|
||||
{
|
||||
if(lineJoin.empty()) return ;
|
||||
_impl->setLineJoin(lineJoin);
|
||||
}
|
||||
|
||||
void CanvasRenderingContext2D::set_lineCap(const std::string& lineCap)
|
||||
{
|
||||
if(lineCap.empty()) return ;
|
||||
_impl->setLineCap(lineCap);
|
||||
}
|
||||
|
||||
/*
|
||||
* support format e.g.: "oblique bold small-caps 18px Arial"
|
||||
* "italic bold small-caps 25px Arial"
|
||||
* "italic 25px Arial"
|
||||
* */
|
||||
void CanvasRenderingContext2D::set_font(const std::string& font)
|
||||
{
|
||||
if (_font != font)
|
||||
{
|
||||
_font = font;
|
||||
std::string fontName = "sans-serif";
|
||||
std::string fontSizeStr = "30";
|
||||
std::regex re("\\s*((\\d+)([\\.]\\d+)?)px\\s+([^\\r\\n]*)");
|
||||
std::match_results<std::string::const_iterator> results;
|
||||
if (std::regex_search(_font.cbegin(), _font.cend(), results, re))
|
||||
{
|
||||
fontSizeStr = results[2].str();
|
||||
// support get font name from `60px American` or `60px "American abc-abc_abc"`
|
||||
// support get font name contain space,example `times new roman`
|
||||
// if regex rule that does not conform to the rules,such as Chinese,it defaults to sans-serif
|
||||
std::match_results<std::string::const_iterator> fontResults;
|
||||
std::regex fontRe("([\\w\\s-]+|\"[\\w\\s-]+\"$)");
|
||||
if(std::regex_match(results[4].str(), fontResults, fontRe))
|
||||
{
|
||||
fontName = results[4].str();
|
||||
}
|
||||
}
|
||||
|
||||
float fontSize = atof(fontSizeStr.c_str());
|
||||
bool isBold = font.find("bold", 0) != std::string::npos;
|
||||
bool isItalic = font.find("italic", 0) != std::string::npos;
|
||||
bool isSmallCaps = font.find("small-caps", 0) != std::string::npos;
|
||||
bool isOblique = font.find("oblique", 0) != std::string::npos;
|
||||
//font-style: italic, oblique, normal
|
||||
//font-weight: normal, bold
|
||||
//font-variant: normal, small-caps
|
||||
_impl->updateFont(fontName, fontSize, isBold, isItalic, isOblique, isSmallCaps);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void CanvasRenderingContext2D::set_textAlign(const std::string& textAlign)
|
||||
{
|
||||
// SE_LOGD("CanvasRenderingContext2D::set_textAlign: %s\n", textAlign.c_str());
|
||||
if (textAlign == "left")
|
||||
{
|
||||
_impl->setTextAlign(CanvasTextAlign::LEFT);
|
||||
}
|
||||
else if (textAlign == "center" || textAlign == "middle")
|
||||
{
|
||||
_impl->setTextAlign(CanvasTextAlign::CENTER);
|
||||
}
|
||||
else if (textAlign == "right")
|
||||
{
|
||||
_impl->setTextAlign(CanvasTextAlign::RIGHT);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
void CanvasRenderingContext2D::set_textBaseline(const std::string& textBaseline)
|
||||
{
|
||||
// SE_LOGD("CanvasRenderingContext2D::set_textBaseline: %s\n", textBaseline.c_str());
|
||||
if (textBaseline == "top")
|
||||
{
|
||||
_impl->setTextBaseline(CanvasTextBaseline::TOP);
|
||||
}
|
||||
else if (textBaseline == "middle")
|
||||
{
|
||||
_impl->setTextBaseline(CanvasTextBaseline::MIDDLE);
|
||||
}
|
||||
else if (textBaseline == "bottom" || textBaseline == "alphabetic") //REFINE:, how to deal with alphabetic, currently we handle it as bottom mode.
|
||||
{
|
||||
_impl->setTextBaseline(CanvasTextBaseline::BOTTOM);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
void CanvasRenderingContext2D::set_fillStyle(const std::string& fillStyle)
|
||||
{
|
||||
CSSColorParser::Color color = CSSColorParser::parse(fillStyle);
|
||||
_impl->setFillStyle(color.r/255.0f, color.g/255.0f, color.b/255.0f, color.a);
|
||||
// SE_LOGD("CanvasRenderingContext2D::set_fillStyle: %s, (%d, %d, %d, %f)\n", fillStyle.c_str(), color.r, color.g, color.b, color.a);
|
||||
}
|
||||
|
||||
void CanvasRenderingContext2D::set_strokeStyle(const std::string& strokeStyle)
|
||||
{
|
||||
CSSColorParser::Color color = CSSColorParser::parse(strokeStyle);
|
||||
_impl->setStrokeStyle(color.r/255.0f, color.g/255.0f, color.b/255.0f, color.a);
|
||||
}
|
||||
|
||||
void CanvasRenderingContext2D::set_globalCompositeOperation(const std::string& globalCompositeOperation)
|
||||
{
|
||||
// SE_LOGE("%s isn't implemented!\n", __FUNCTION__);
|
||||
}
|
||||
|
||||
void CanvasRenderingContext2D::_fillImageData(const Data& imageData, float imageWidth, float imageHeight, float offsetX, float offsetY)
|
||||
{
|
||||
_impl->_fillImageData(imageData, imageWidth, imageHeight, offsetX, offsetY);
|
||||
if (_canvasBufferUpdatedCB != nullptr)
|
||||
_canvasBufferUpdatedCB(_impl->getDataRef());
|
||||
}
|
||||
// transform
|
||||
//REFINE:
|
||||
|
||||
void CanvasRenderingContext2D::translate(float x, float y)
|
||||
{
|
||||
// SE_LOGE("%s isn't implemented!\n", __FUNCTION__);
|
||||
}
|
||||
|
||||
void CanvasRenderingContext2D::scale(float x, float y)
|
||||
{
|
||||
// SE_LOGE("%s isn't implemented!\n", __FUNCTION__);
|
||||
}
|
||||
|
||||
void CanvasRenderingContext2D::rotate(float angle)
|
||||
{
|
||||
// SE_LOGE("%s isn't implemented!\n", __FUNCTION__);
|
||||
}
|
||||
|
||||
void CanvasRenderingContext2D::transform(float a, float b, float c, float d, float e, float f)
|
||||
{
|
||||
// SE_LOGE("%s isn't implemented!\n", __FUNCTION__);
|
||||
}
|
||||
|
||||
void CanvasRenderingContext2D::setTransform(float a, float b, float c, float d, float e, float f)
|
||||
{
|
||||
// SE_LOGE("%s isn't implemented!\n", __FUNCTION__);
|
||||
}
|
||||
|
||||
NS_CC_END
|
136
cocos2d-x/cocos/platform/android/CCDevice-android.cpp
Normal file
136
cocos2d-x/cocos/platform/android/CCDevice-android.cpp
Normal file
@@ -0,0 +1,136 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2010-2012 cocos2d-x.org
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "platform/CCPlatformConfig.h"
|
||||
#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
|
||||
|
||||
#include "platform/CCDevice.h"
|
||||
#include <string.h>
|
||||
#include <android/log.h>
|
||||
#include <jni.h>
|
||||
#include "base/ccTypes.h"
|
||||
#include "platform/android/jni/JniHelper.h"
|
||||
#include "platform/CCFileUtils.h"
|
||||
#include "base/ccUTF8.h"
|
||||
#include "platform/CCApplication.h"
|
||||
|
||||
#ifndef JCLS_HELPER
|
||||
#define JCLS_HELPER "org/cocos2dx/lib/Cocos2dxHelper"
|
||||
#endif
|
||||
|
||||
NS_CC_BEGIN
|
||||
|
||||
int Device::getDPI()
|
||||
{
|
||||
static int dpi = -1;
|
||||
if (dpi == -1)
|
||||
{
|
||||
dpi = JniHelper::callStaticIntMethod(JCLS_HELPER, "getDPI");
|
||||
}
|
||||
return dpi;
|
||||
}
|
||||
|
||||
void Device::setAccelerometerEnabled(bool isEnabled)
|
||||
{
|
||||
if (isEnabled)
|
||||
{
|
||||
JniHelper::callStaticVoidMethod(JCLS_HELPER, "enableAccelerometer");
|
||||
}
|
||||
else
|
||||
{
|
||||
JniHelper::callStaticVoidMethod(JCLS_HELPER, "disableAccelerometer");
|
||||
}
|
||||
}
|
||||
|
||||
void Device::setAccelerometerInterval(float interval)
|
||||
{
|
||||
JniHelper::callStaticVoidMethod(JCLS_HELPER, "setAccelerometerInterval", interval);
|
||||
}
|
||||
|
||||
const Device::MotionValue& Device::getDeviceMotionValue()
|
||||
{
|
||||
static MotionValue __motionValue;
|
||||
float* v = JniHelper::callStaticFloatArrayMethod(JCLS_HELPER, "getDeviceMotionValue");
|
||||
__motionValue.accelerationX = v[0];
|
||||
__motionValue.accelerationY = v[1];
|
||||
__motionValue.accelerationZ = v[2];
|
||||
|
||||
__motionValue.accelerationIncludingGravityX = v[3];
|
||||
__motionValue.accelerationIncludingGravityY = v[4];
|
||||
__motionValue.accelerationIncludingGravityZ = v[5];
|
||||
|
||||
__motionValue.rotationRateAlpha = v[6];
|
||||
__motionValue.rotationRateBeta = v[7];
|
||||
__motionValue.rotationRateGamma = v[8];
|
||||
|
||||
return __motionValue;
|
||||
}
|
||||
|
||||
Device::Rotation Device::getDeviceRotation()
|
||||
{
|
||||
int rotation = JniHelper::callStaticIntMethod(JCLS_HELPER, "getDeviceRotation");
|
||||
return (Device::Rotation)rotation;
|
||||
}
|
||||
|
||||
std::string Device::getDeviceModel()
|
||||
{
|
||||
return JniHelper::callStaticStringMethod(JCLS_HELPER, "getDeviceModel");
|
||||
}
|
||||
|
||||
void Device::setKeepScreenOn(bool value)
|
||||
{
|
||||
JniHelper::callStaticVoidMethod(JCLS_HELPER, "setKeepScreenOn", value);
|
||||
}
|
||||
|
||||
void Device::vibrate(float duration)
|
||||
{
|
||||
JniHelper::callStaticVoidMethod(JCLS_HELPER, "vibrate", duration);
|
||||
}
|
||||
|
||||
float Device::getBatteryLevel()
|
||||
{
|
||||
return JniHelper::callStaticFloatMethod(JCLS_HELPER, "getBatteryLevel");
|
||||
}
|
||||
|
||||
Device::NetworkType Device::getNetworkType()
|
||||
{
|
||||
return (Device::NetworkType)JniHelper::callStaticIntMethod(JCLS_HELPER, "getNetworkType");
|
||||
}
|
||||
|
||||
cocos2d::Vec4 Device::getSafeAreaEdge()
|
||||
{
|
||||
float *data = JniHelper::callStaticFloatArrayMethod(JCLS_HELPER, "getSafeArea");
|
||||
return cocos2d::Vec4(data[0], data[1], data[2],data[3]);
|
||||
}
|
||||
|
||||
int Device::getDevicePixelRatio()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
NS_CC_END
|
||||
|
||||
#endif // CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
|
333
cocos2d-x/cocos/platform/android/CCFileUtils-android.cpp
Normal file
333
cocos2d-x/cocos/platform/android/CCFileUtils-android.cpp
Normal file
@@ -0,0 +1,333 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2010-2012 cocos2d-x.org
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "platform/CCPlatformConfig.h"
|
||||
#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
|
||||
|
||||
#include "platform/android/CCFileUtils-android.h"
|
||||
#include "platform/android/jni/JniHelper.h"
|
||||
#include "platform/android/jni/JniImp.h"
|
||||
#include "android/asset_manager.h"
|
||||
#include "android/asset_manager_jni.h"
|
||||
#include "base/ZipUtils.h"
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#define LOG_TAG "CCFileUtils-android.cpp"
|
||||
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
|
||||
|
||||
#define ASSETS_FOLDER_NAME "@assets/"
|
||||
|
||||
#ifndef JCLS_HELPER
|
||||
#define JCLS_HELPER "org/cocos2dx/lib/Cocos2dxHelper"
|
||||
#endif
|
||||
|
||||
NS_CC_BEGIN
|
||||
|
||||
AAssetManager* FileUtilsAndroid::assetmanager = nullptr;
|
||||
ZipFile* FileUtilsAndroid::obbfile = nullptr;
|
||||
|
||||
void FileUtilsAndroid::setassetmanager(AAssetManager* a) {
|
||||
if (nullptr == a) {
|
||||
LOGD("setassetmanager : received unexpected nullptr parameter");
|
||||
return;
|
||||
}
|
||||
|
||||
cocos2d::FileUtilsAndroid::assetmanager = a;
|
||||
}
|
||||
|
||||
FileUtils* FileUtils::getInstance()
|
||||
{
|
||||
if (s_sharedFileUtils == nullptr)
|
||||
{
|
||||
s_sharedFileUtils = new FileUtilsAndroid();
|
||||
if (!s_sharedFileUtils->init())
|
||||
{
|
||||
delete s_sharedFileUtils;
|
||||
s_sharedFileUtils = nullptr;
|
||||
CCLOG("ERROR: Could not init CCFileUtilsAndroid");
|
||||
}
|
||||
}
|
||||
return s_sharedFileUtils;
|
||||
}
|
||||
|
||||
FileUtilsAndroid::FileUtilsAndroid()
|
||||
{
|
||||
}
|
||||
|
||||
FileUtilsAndroid::~FileUtilsAndroid()
|
||||
{
|
||||
if (obbfile)
|
||||
{
|
||||
delete obbfile;
|
||||
obbfile = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool FileUtilsAndroid::init()
|
||||
{
|
||||
_defaultResRootPath = ASSETS_FOLDER_NAME;
|
||||
|
||||
std::string assetsPath(getApkPathJNI());
|
||||
if (assetsPath.find("/obb/") != std::string::npos)
|
||||
{
|
||||
obbfile = new ZipFile(assetsPath);
|
||||
}
|
||||
|
||||
return FileUtils::init();
|
||||
}
|
||||
|
||||
std::string FileUtilsAndroid::getNewFilename(const std::string &filename) const
|
||||
{
|
||||
std::string newFileName = FileUtils::getNewFilename(filename);
|
||||
// ../xxx do not fix this path
|
||||
auto pos = newFileName.find("../");
|
||||
if (pos == std::string::npos || pos == 0)
|
||||
{
|
||||
return newFileName;
|
||||
}
|
||||
|
||||
std::vector<std::string> v(3);
|
||||
v.resize(0);
|
||||
auto change = false;
|
||||
size_t size = newFileName.size();
|
||||
size_t idx = 0;
|
||||
bool noexit = true;
|
||||
while (noexit)
|
||||
{
|
||||
pos = newFileName.find('/', idx);
|
||||
std::string tmp;
|
||||
if (pos == std::string::npos)
|
||||
{
|
||||
tmp = newFileName.substr(idx, size - idx);
|
||||
noexit = false;
|
||||
}else
|
||||
{
|
||||
tmp = newFileName.substr(idx, pos - idx + 1);
|
||||
}
|
||||
auto t = v.size();
|
||||
if (t > 0 && v[t-1].compare("../") != 0 &&
|
||||
(tmp.compare("../") == 0 || tmp.compare("..") == 0))
|
||||
{
|
||||
v.pop_back();
|
||||
change = true;
|
||||
}else
|
||||
{
|
||||
v.push_back(tmp);
|
||||
}
|
||||
idx = pos + 1;
|
||||
}
|
||||
|
||||
if (change)
|
||||
{
|
||||
newFileName.clear();
|
||||
for (auto &s : v)
|
||||
{
|
||||
newFileName.append(s);
|
||||
}
|
||||
}
|
||||
return newFileName;
|
||||
}
|
||||
|
||||
bool FileUtilsAndroid::isFileExistInternal(const std::string& strFilePath) const
|
||||
{
|
||||
if (strFilePath.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bFound = false;
|
||||
|
||||
// Check whether file exists in apk.
|
||||
if (strFilePath[0] != '/')
|
||||
{
|
||||
const char* s = strFilePath.c_str();
|
||||
|
||||
// Found "@assets/" at the beginning of the path and we don't want it
|
||||
if (strFilePath.find(ASSETS_FOLDER_NAME) == 0) s += strlen(ASSETS_FOLDER_NAME);
|
||||
if (obbfile && obbfile->fileExists(s))
|
||||
{
|
||||
bFound = true;
|
||||
}
|
||||
else if (FileUtilsAndroid::assetmanager)
|
||||
{
|
||||
AAsset* aa = AAssetManager_open(FileUtilsAndroid::assetmanager, s, AASSET_MODE_UNKNOWN);
|
||||
if (aa)
|
||||
{
|
||||
bFound = true;
|
||||
AAsset_close(aa);
|
||||
} else {
|
||||
// CCLOG("[AssetManager] ... in APK %s, found = false!", strFilePath.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FILE *fp = fopen(strFilePath.c_str(), "r");
|
||||
if (fp)
|
||||
{
|
||||
bFound = true;
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
return bFound;
|
||||
}
|
||||
|
||||
bool FileUtilsAndroid::isDirectoryExistInternal(const std::string& dirPath_) const
|
||||
{
|
||||
if (dirPath_.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string dirPath = dirPath_;
|
||||
if (dirPath[dirPath.length() - 1] == '/')
|
||||
{
|
||||
dirPath[dirPath.length() - 1] = '\0';
|
||||
}
|
||||
|
||||
// find absolute path in flash memory
|
||||
if (dirPath[0] == '/')
|
||||
{
|
||||
CCLOG("find in flash memory dirPath(%s)", dirPath.c_str());
|
||||
struct stat st;
|
||||
if (stat(dirPath.c_str(), &st) == 0)
|
||||
{
|
||||
return S_ISDIR(st.st_mode);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// find it in apk's assets dir
|
||||
// Found "@assets/" at the beginning of the path and we don't want it
|
||||
CCLOG("find in apk dirPath(%s)", dirPath.c_str());
|
||||
const char* s = dirPath.c_str();
|
||||
if (dirPath.find(_defaultResRootPath) == 0)
|
||||
{
|
||||
s += _defaultResRootPath.length();
|
||||
}
|
||||
if (FileUtilsAndroid::assetmanager)
|
||||
{
|
||||
AAssetDir* aa = AAssetManager_openDir(FileUtilsAndroid::assetmanager, s);
|
||||
if (aa && AAssetDir_getNextFileName(aa))
|
||||
{
|
||||
AAssetDir_close(aa);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FileUtilsAndroid::isAbsolutePath(const std::string& strPath) const
|
||||
{
|
||||
// On Android, there are two situations for full path.
|
||||
// 1) Files in APK, e.g. assets/path/path/file.png
|
||||
// 2) Files not in APK, e.g. /data/data/org.cocos2dx.hellocpp/cache/path/path/file.png, or /sdcard/path/path/file.png.
|
||||
// So these two situations need to be checked on Android.
|
||||
if (strPath[0] == '/' || strPath.find(ASSETS_FOLDER_NAME) == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
FileUtils::Status FileUtilsAndroid::getContents(const std::string& filename, ResizableBuffer* buffer)
|
||||
{
|
||||
if (filename.empty())
|
||||
return FileUtils::Status::NotExists;
|
||||
|
||||
std::string fullPath = fullPathForFilename(filename);
|
||||
if (fullPath.empty())
|
||||
return FileUtils::Status::NotExists;
|
||||
|
||||
if (fullPath[0] == '/')
|
||||
return FileUtils::getContents(fullPath, buffer);
|
||||
|
||||
std::string relativePath;
|
||||
size_t position = fullPath.find(ASSETS_FOLDER_NAME);
|
||||
if (0 == position) {
|
||||
// "@assets/" is at the beginning of the path and we don't want it
|
||||
relativePath += fullPath.substr(strlen(ASSETS_FOLDER_NAME));
|
||||
} else {
|
||||
relativePath = fullPath;
|
||||
}
|
||||
|
||||
if (obbfile)
|
||||
{
|
||||
if (obbfile->getFileData(relativePath, buffer))
|
||||
return FileUtils::Status::OK;
|
||||
}
|
||||
|
||||
if (nullptr == assetmanager) {
|
||||
LOGD("... FileUtilsAndroid::assetmanager is nullptr");
|
||||
return FileUtils::Status::NotInitialized;
|
||||
}
|
||||
|
||||
AAsset* asset = AAssetManager_open(assetmanager, relativePath.data(), AASSET_MODE_UNKNOWN);
|
||||
if (nullptr == asset) {
|
||||
LOGD("asset (%s) is nullptr", filename.c_str());
|
||||
return FileUtils::Status::OpenFailed;
|
||||
}
|
||||
|
||||
auto size = AAsset_getLength(asset);
|
||||
buffer->resize(size);
|
||||
|
||||
int readsize = AAsset_read(asset, buffer->buffer(), size);
|
||||
AAsset_close(asset);
|
||||
|
||||
if (readsize < size) {
|
||||
if (readsize >= 0)
|
||||
buffer->resize(readsize);
|
||||
return FileUtils::Status::ReadFailed;
|
||||
}
|
||||
|
||||
return FileUtils::Status::OK;
|
||||
}
|
||||
|
||||
std::string FileUtilsAndroid::getWritablePath() const
|
||||
{
|
||||
// Fix for Nexus 10 (Android 4.2 multi-user environment)
|
||||
// the path is retrieved through Java Context.getCacheDir() method
|
||||
std::string dir("");
|
||||
std::string tmp = JniHelper::callStaticStringMethod(JCLS_HELPER, "getWritablePath");
|
||||
|
||||
if (tmp.length() > 0)
|
||||
{
|
||||
dir.append(tmp).append("/");
|
||||
|
||||
return dir;
|
||||
}
|
||||
else
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
NS_CC_END
|
||||
|
||||
#endif // CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
|
90
cocos2d-x/cocos/platform/android/CCFileUtils-android.h
Normal file
90
cocos2d-x/cocos/platform/android/CCFileUtils-android.h
Normal file
@@ -0,0 +1,90 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2010-2012 cocos2d-x.org
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
#ifndef __CC_FILEUTILS_ANDROID_H__
|
||||
#define __CC_FILEUTILS_ANDROID_H__
|
||||
|
||||
#include "platform/CCPlatformConfig.h"
|
||||
#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
|
||||
|
||||
#include "platform/CCFileUtils.h"
|
||||
#include "base/ccMacros.h"
|
||||
#include "base/ccTypes.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "jni.h"
|
||||
#include "android/asset_manager.h"
|
||||
|
||||
NS_CC_BEGIN
|
||||
|
||||
class ZipFile;
|
||||
|
||||
/**
|
||||
* @addtogroup platform
|
||||
* @{
|
||||
*/
|
||||
|
||||
//! @brief Helper class to handle file operations
|
||||
class CC_DLL FileUtilsAndroid : public FileUtils
|
||||
{
|
||||
friend class FileUtils;
|
||||
public:
|
||||
FileUtilsAndroid();
|
||||
/**
|
||||
* @js NA
|
||||
* @lua NA
|
||||
*/
|
||||
virtual ~FileUtilsAndroid();
|
||||
|
||||
static void setassetmanager(AAssetManager* a);
|
||||
static AAssetManager* getAssetManager() { return assetmanager; }
|
||||
static ZipFile* getObbFile() { return obbfile; }
|
||||
|
||||
/* override functions */
|
||||
bool init() override;
|
||||
|
||||
virtual std::string getNewFilename(const std::string &filename) const override;
|
||||
|
||||
virtual FileUtils::Status getContents(const std::string& filename, ResizableBuffer* buffer) override;
|
||||
|
||||
virtual std::string getWritablePath() const override;
|
||||
virtual bool isAbsolutePath(const std::string& strPath) const override;
|
||||
|
||||
private:
|
||||
virtual bool isFileExistInternal(const std::string& strFilePath) const override;
|
||||
virtual bool isDirectoryExistInternal(const std::string& dirPath) const override;
|
||||
|
||||
static AAssetManager* assetmanager;
|
||||
static ZipFile* obbfile;
|
||||
};
|
||||
|
||||
// end of platform group
|
||||
/// @}
|
||||
|
||||
NS_CC_END
|
||||
|
||||
#endif // CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
|
||||
|
||||
#endif // __CC_FILEUTILS_ANDROID_H__
|
79
cocos2d-x/cocos/platform/android/CCGL-android.h
Normal file
79
cocos2d-x/cocos/platform/android/CCGL-android.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2010-2012 cocos2d-x.org
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __CCGL_H__
|
||||
#define __CCGL_H__
|
||||
|
||||
#include "platform/CCPlatformConfig.h"
|
||||
#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
|
||||
|
||||
#define glClearDepth glClearDepthf
|
||||
#define glDeleteVertexArrays glDeleteVertexArraysOES
|
||||
#define glGenVertexArrays glGenVertexArraysOES
|
||||
#define glBindVertexArray glBindVertexArrayOES
|
||||
#define glMapBuffer glMapBufferOES
|
||||
#define glUnmapBuffer glUnmapBufferOES
|
||||
#define glTexImage3D glTexImage3DOES
|
||||
#define glCompressedTexImage3D glCompressedTexImage3DOES
|
||||
#define glCompressedTexSubImage3D glCompressedTexSubImage3DOES
|
||||
#define glTexSubImage3D glTexSubImage3DOES
|
||||
#define glDepthRange glDepthRangef
|
||||
#define glSubImage3D glSubImage3DOES
|
||||
|
||||
#define GL_DEPTH24_STENCIL8 GL_DEPTH24_STENCIL8_OES
|
||||
#define GL_WRITE_ONLY GL_WRITE_ONLY_OES
|
||||
|
||||
// GL_GLEXT_PROTOTYPES isn't defined in glplatform.h on android ndk r7
|
||||
// we manually define it here
|
||||
#include <GLES2/gl2platform.h>
|
||||
#ifndef GL_GLEXT_PROTOTYPES
|
||||
#define GL_GLEXT_PROTOTYPES 1
|
||||
#endif
|
||||
|
||||
// normal process
|
||||
#include <GLES2/gl2.h>
|
||||
#include <GLES2/gl2ext.h>
|
||||
// gl2.h doesn't define GLchar on Android
|
||||
typedef char GLchar;
|
||||
// android defines GL_BGRA_EXT but not GL_BRGA
|
||||
#ifndef GL_BGRA
|
||||
#define GL_BGRA 0x80E1
|
||||
#endif
|
||||
|
||||
//declare here while define in EGLView_android.cpp
|
||||
extern PFNGLGENVERTEXARRAYSOESPROC glGenVertexArraysOESEXT;
|
||||
extern PFNGLBINDVERTEXARRAYOESPROC glBindVertexArrayOESEXT;
|
||||
extern PFNGLDELETEVERTEXARRAYSOESPROC glDeleteVertexArraysOESEXT;
|
||||
|
||||
#define glGenVertexArraysOES glGenVertexArraysOESEXT
|
||||
#define glBindVertexArrayOES glBindVertexArrayOESEXT
|
||||
#define glDeleteVertexArraysOES glDeleteVertexArraysOESEXT
|
||||
|
||||
|
||||
#endif // CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
|
||||
|
||||
#endif // __CCGL_H__
|
||||
|
68
cocos2d-x/cocos/platform/android/CCPlatformDefine-android.h
Normal file
68
cocos2d-x/cocos/platform/android/CCPlatformDefine-android.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2010-2012 cocos2d-x.org
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __CCPLATFORMDEFINE_H__
|
||||
#define __CCPLATFORMDEFINE_H__
|
||||
|
||||
#include "platform/CCPlatformConfig.h"
|
||||
#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
|
||||
|
||||
#include <android/log.h>
|
||||
|
||||
#define CC_DLL
|
||||
|
||||
#define CC_NO_MESSAGE_PSEUDOASSERT(cond) \
|
||||
if (!(cond)) { \
|
||||
__android_log_print(ANDROID_LOG_ERROR, \
|
||||
"assert", \
|
||||
"%s function:%s line:%d", \
|
||||
__FILE__, __FUNCTION__, __LINE__); \
|
||||
}
|
||||
|
||||
#define CC_MESSAGE_PSEUDOASSERT(cond, msg) \
|
||||
if (!(cond)) { \
|
||||
__android_log_print(ANDROID_LOG_ERROR, \
|
||||
"assert", \
|
||||
"file:%s function:%s line:%d, %s", \
|
||||
__FILE__, __FUNCTION__, __LINE__, msg); \
|
||||
}
|
||||
|
||||
#define CC_ASSERT(cond) CC_NO_MESSAGE_PSEUDOASSERT(cond)
|
||||
|
||||
#define CC_UNUSED_PARAM(unusedparam) (void)unusedparam
|
||||
|
||||
/* Define NULL pointer value */
|
||||
#ifndef NULL
|
||||
#ifdef __cplusplus
|
||||
#define NULL 0
|
||||
#else
|
||||
#define NULL ((void *)0)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
|
||||
|
||||
#endif /* __CCPLATFORMDEFINE_H__*/
|
9
cocos2d-x/cocos/platform/android/java/.classpath
Normal file
9
cocos2d-x/cocos/platform/android/java/.classpath
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
|
||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
|
||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="src" path="gen"/>
|
||||
<classpathentry kind="output" path="bin/classes"/>
|
||||
</classpath>
|
33
cocos2d-x/cocos/platform/android/java/.project
Normal file
33
cocos2d-x/cocos/platform/android/java/.project
Normal file
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>libcocos2dx</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.cocos2dx.lib"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0">
|
||||
|
||||
<uses-sdk android:minSdkVersion="9"/>
|
||||
|
||||
</manifest>
|
83
cocos2d-x/cocos/platform/android/java/build.xml
Normal file
83
cocos2d-x/cocos/platform/android/java/build.xml
Normal file
@@ -0,0 +1,83 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project name="cocos2dxandroid" default="help">
|
||||
|
||||
<!-- The local.properties file is created and updated by the 'android' tool.
|
||||
It contains the path to the SDK. It should *NOT* be checked into
|
||||
Version Control Systems. -->
|
||||
<property file="local.properties" />
|
||||
|
||||
<!-- The ant.properties file can be created by you. It is only edited by the
|
||||
'android' tool to add properties to it.
|
||||
This is the place to change some Ant specific build properties.
|
||||
Here are some properties you may want to change/update:
|
||||
|
||||
source.dir
|
||||
The name of the source directory. Default is 'src'.
|
||||
out.dir
|
||||
The name of the output directory. Default is 'bin'.
|
||||
|
||||
For other overridable properties, look at the beginning of the rules
|
||||
files in the SDK, at tools/ant/build.xml
|
||||
|
||||
Properties related to the SDK location or the project target should
|
||||
be updated using the 'android' tool with the 'update' action.
|
||||
|
||||
This file is an integral part of the build system for your
|
||||
application and should be checked into Version Control Systems.
|
||||
|
||||
-->
|
||||
<property file="ant.properties" />
|
||||
|
||||
<!-- The project.properties file is created and updated by the 'android'
|
||||
tool, as well as ADT.
|
||||
|
||||
This contains project specific properties such as project target, and library
|
||||
dependencies. Lower level build properties are stored in ant.properties
|
||||
(or in .classpath for Eclipse projects).
|
||||
|
||||
This file is an integral part of the build system for your
|
||||
application and should be checked into Version Control Systems. -->
|
||||
<loadproperties srcFile="project.properties" />
|
||||
|
||||
<!-- quick check on sdk.dir -->
|
||||
<fail
|
||||
message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through an env var"
|
||||
unless="sdk.dir"
|
||||
/>
|
||||
|
||||
<!--
|
||||
Import per project custom build rules if present at the root of the project.
|
||||
This is the place to put custom intermediary targets such as:
|
||||
-pre-build
|
||||
-pre-compile
|
||||
-post-compile (This is typically used for code obfuscation.
|
||||
Compiled code location: ${out.classes.absolute.dir}
|
||||
If this is not done in place, override ${out.dex.input.absolute.dir})
|
||||
-post-package
|
||||
-post-build
|
||||
-pre-clean
|
||||
-->
|
||||
<import file="custom_rules.xml" optional="true" />
|
||||
|
||||
<!-- Import the actual build file.
|
||||
|
||||
To customize existing targets, there are two options:
|
||||
- Customize only one target:
|
||||
- copy/paste the target into this file, *before* the
|
||||
<import> task.
|
||||
- customize it to your needs.
|
||||
- Customize the whole content of build.xml
|
||||
- copy/paste the content of the rules files (minus the top node)
|
||||
into this file, replacing the <import> task.
|
||||
- customize to your needs.
|
||||
|
||||
***********************
|
||||
****** IMPORTANT ******
|
||||
***********************
|
||||
In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
|
||||
in order to avoid having your file be overridden by tools such as "android update project"
|
||||
-->
|
||||
<!-- version-tag: 1 -->
|
||||
<import file="${sdk.dir}/tools/ant/build.xml" />
|
||||
|
||||
</project>
|
Binary file not shown.
BIN
cocos2d-x/cocos/platform/android/java/libs/okhttp-3.12.14.jar
Normal file
BIN
cocos2d-x/cocos/platform/android/java/libs/okhttp-3.12.14.jar
Normal file
Binary file not shown.
BIN
cocos2d-x/cocos/platform/android/java/libs/okio-1.15.0.jar
Normal file
BIN
cocos2d-x/cocos/platform/android/java/libs/okio-1.15.0.jar
Normal file
Binary file not shown.
20
cocos2d-x/cocos/platform/android/java/proguard-project.txt
Normal file
20
cocos2d-x/cocos/platform/android/java/proguard-project.txt
Normal file
@@ -0,0 +1,20 @@
|
||||
# To enable ProGuard in your project, edit project.properties
|
||||
# to define the proguard.config property as described in that file.
|
||||
#
|
||||
# Add project specific ProGuard rules here.
|
||||
# By default, the flags in this file are appended to flags specified
|
||||
# in ${sdk.dir}/tools/proguard/proguard-android.txt
|
||||
# You can edit the include path and order by changing the ProGuard
|
||||
# include property in project.properties.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# Add any project specific keep options here:
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
0
cocos2d-x/cocos/platform/android/java/res/.gitignore
vendored
Normal file
0
cocos2d-x/cocos/platform/android/java/res/.gitignore
vendored
Normal file
@@ -0,0 +1,510 @@
|
||||
/****************************************************************************
|
||||
* Copyright (c) 2018 Xiamen Yaji Software Co., Ltd.
|
||||
*
|
||||
* http://www.cocos.com
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
package org.cocos2dx.lib;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.Typeface;
|
||||
import android.os.Build;
|
||||
import android.text.TextPaint;
|
||||
import android.util.Log;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class CanvasRenderingContext2DImpl {
|
||||
|
||||
private static final String TAG = "CanvasContext2D";
|
||||
|
||||
private static final int TEXT_ALIGN_LEFT = 0;
|
||||
private static final int TEXT_ALIGN_CENTER = 1;
|
||||
private static final int TEXT_ALIGN_RIGHT = 2;
|
||||
|
||||
private static final int TEXT_BASELINE_TOP = 0;
|
||||
private static final int TEXT_BASELINE_MIDDLE = 1;
|
||||
private static final int TEXT_BASELINE_BOTTOM = 2;
|
||||
|
||||
private static WeakReference<Context> sContext;
|
||||
private TextPaint mTextPaint;
|
||||
private Paint mLinePaint;
|
||||
private Path mLinePath;
|
||||
private Canvas mCanvas = new Canvas();
|
||||
private Bitmap mBitmap;
|
||||
private int mTextAlign = TEXT_ALIGN_LEFT;
|
||||
private int mTextBaseline = TEXT_BASELINE_BOTTOM;
|
||||
private int mFillStyleR = 0;
|
||||
private int mFillStyleG = 0;
|
||||
private int mFillStyleB = 0;
|
||||
private int mFillStyleA = 255;
|
||||
|
||||
private int mStrokeStyleR = 0;
|
||||
private int mStrokeStyleG = 0;
|
||||
private int mStrokeStyleB = 0;
|
||||
private int mStrokeStyleA = 255;
|
||||
|
||||
private String mFontName = "Arial";
|
||||
private float mFontSize = 40.0f;
|
||||
private float mLineWidth = 0.0f;
|
||||
private static float _sApproximatingOblique = -0.25f;//please check paint api documentation
|
||||
private boolean mIsBoldFont = false;
|
||||
private boolean mIsItalicFont = false;
|
||||
private boolean mIsObliqueFont = false;
|
||||
private boolean mIsSmallCapsFontVariant = false;
|
||||
private String mLineCap = "butt";
|
||||
private String mLineJoin = "miter";
|
||||
|
||||
private class Size {
|
||||
Size(float w, float h) {
|
||||
this.width = w;
|
||||
this.height = h;
|
||||
}
|
||||
|
||||
Size() {
|
||||
this.width = 0;
|
||||
this.height = 0;
|
||||
}
|
||||
public float width;
|
||||
public float height;
|
||||
}
|
||||
|
||||
private class Point {
|
||||
Point(float x, float y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
Point() {
|
||||
this.x = this.y = 0.0f;
|
||||
}
|
||||
|
||||
Point(Point pt) {
|
||||
this.x = pt.x;
|
||||
this.y = pt.y;
|
||||
}
|
||||
|
||||
void set(float x, float y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public float x;
|
||||
public float y;
|
||||
}
|
||||
|
||||
static void init(Context context) {
|
||||
sContext = new WeakReference<>(context);
|
||||
}
|
||||
|
||||
static void destroy() {
|
||||
sContext = null;
|
||||
}
|
||||
|
||||
private static HashMap<String, Typeface> sTypefaceCache = new HashMap<>();
|
||||
|
||||
// url is a full path started with '@assets/'
|
||||
private static void loadTypeface(String familyName, String url) {
|
||||
if (!sTypefaceCache.containsKey(familyName)) {
|
||||
try {
|
||||
Typeface typeface = null;
|
||||
if (url.startsWith("/")) {
|
||||
typeface = Typeface.createFromFile(url);
|
||||
} else if (sContext.get() != null) {
|
||||
final String prefix = "@assets/";
|
||||
if (url.startsWith(prefix)) {
|
||||
url = url.substring(prefix.length());
|
||||
}
|
||||
typeface = Typeface.createFromAsset(sContext.get().getAssets(), url);
|
||||
}
|
||||
|
||||
if (typeface != null) {
|
||||
sTypefaceCache.put(familyName, typeface);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// REFINE:: native should clear font cache before exiting game.
|
||||
private static void clearTypefaceCache() {
|
||||
sTypefaceCache.clear();
|
||||
}
|
||||
|
||||
private static TextPaint newPaint(String fontName, int fontSize, boolean enableBold, boolean enableItalic, boolean obliqueFont, boolean smallCapsFontVariant) {
|
||||
TextPaint paint = new TextPaint();
|
||||
paint.setTextSize(fontSize);
|
||||
paint.setAntiAlias(true);
|
||||
paint.setSubpixelText(true);
|
||||
|
||||
String key = fontName;
|
||||
if (enableBold) {
|
||||
key += "-Bold";
|
||||
paint.setFakeBoldText(true);
|
||||
}
|
||||
if (enableItalic) {
|
||||
key += "-Italic";
|
||||
}
|
||||
|
||||
Typeface typeFace;
|
||||
if (sTypefaceCache.containsKey(key)) {
|
||||
typeFace = sTypefaceCache.get(key);
|
||||
} else {
|
||||
int style = Typeface.NORMAL;
|
||||
if (enableBold && enableItalic) {
|
||||
style = Typeface.BOLD_ITALIC;
|
||||
} else if (enableBold) {
|
||||
style = Typeface.BOLD;
|
||||
} else if (enableItalic) {
|
||||
style = Typeface.ITALIC;
|
||||
}
|
||||
typeFace = Typeface.create(fontName, style);
|
||||
}
|
||||
paint.setTypeface(typeFace);
|
||||
if(obliqueFont) {
|
||||
paint.setTextSkewX(_sApproximatingOblique);
|
||||
}
|
||||
if(smallCapsFontVariant && Build.VERSION.SDK_INT >= 21) {
|
||||
Cocos2dxReflectionHelper.<Void>invokeInstanceMethod(paint,
|
||||
"setFontFeatureSettings",
|
||||
new Class[]{String.class},
|
||||
new Object[]{"smcp"});
|
||||
}
|
||||
return paint;
|
||||
}
|
||||
|
||||
private CanvasRenderingContext2DImpl() {
|
||||
// Log.d(TAG, "constructor");
|
||||
}
|
||||
|
||||
private void recreateBuffer(float w, float h) {
|
||||
// Log.d(TAG, "recreateBuffer:" + w + ", " + h);
|
||||
if (mBitmap != null) {
|
||||
mBitmap.recycle();
|
||||
}
|
||||
mBitmap = Bitmap.createBitmap((int)Math.ceil(w), (int)Math.ceil(h), Bitmap.Config.ARGB_8888);
|
||||
// FIXME: in MIX 2S, its API level is 28, but can not find invokeInstanceMethod. It seems
|
||||
// devices may not obey the specification, so comment the codes.
|
||||
// if (Build.VERSION.SDK_INT >= 19) {
|
||||
// Cocos2dxReflectionHelper.<Void>invokeInstanceMethod(mBitmap,
|
||||
// "setPremultiplied",
|
||||
// new Class[]{Boolean.class},
|
||||
// new Object[]{Boolean.FALSE});
|
||||
// }
|
||||
mCanvas.setBitmap(mBitmap);
|
||||
}
|
||||
|
||||
private void beginPath() {
|
||||
if (mLinePath == null) {
|
||||
mLinePath = new Path();
|
||||
}
|
||||
mLinePath.reset();
|
||||
}
|
||||
|
||||
private void closePath() {
|
||||
mLinePath.close();
|
||||
}
|
||||
|
||||
private void moveTo(float x, float y) {
|
||||
mLinePath.moveTo(x, y);
|
||||
}
|
||||
|
||||
private void lineTo(float x, float y) {
|
||||
mLinePath.lineTo(x, y);
|
||||
}
|
||||
|
||||
private void stroke() {
|
||||
if (mLinePaint == null) {
|
||||
mLinePaint = new Paint();
|
||||
mLinePaint.setAntiAlias(true);
|
||||
}
|
||||
|
||||
if(mLinePath == null) {
|
||||
mLinePath = new Path();
|
||||
}
|
||||
|
||||
mLinePaint.setARGB(mStrokeStyleA, mStrokeStyleR, mStrokeStyleG, mStrokeStyleB);
|
||||
mLinePaint.setStyle(Paint.Style.STROKE);
|
||||
mLinePaint.setStrokeWidth(mLineWidth);
|
||||
this.setStrokeCap(mLinePaint);
|
||||
this.setStrokeJoin(mLinePaint);
|
||||
mCanvas.drawPath(mLinePath, mLinePaint);
|
||||
}
|
||||
|
||||
private void setStrokeCap(Paint paint) {
|
||||
switch (mLineCap) {
|
||||
case "butt":
|
||||
paint.setStrokeCap(Paint.Cap.BUTT);
|
||||
break;
|
||||
case "round":
|
||||
paint.setStrokeCap(Paint.Cap.ROUND);
|
||||
break;
|
||||
case "square":
|
||||
paint.setStrokeCap(Paint.Cap.SQUARE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void setStrokeJoin(Paint paint) {
|
||||
switch (mLineJoin) {
|
||||
case "bevel":
|
||||
paint.setStrokeJoin(Paint.Join.BEVEL);
|
||||
break;
|
||||
case "round":
|
||||
paint.setStrokeJoin(Paint.Join.ROUND);
|
||||
break;
|
||||
case "miter":
|
||||
paint.setStrokeJoin(Paint.Join.MITER);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void fill() {
|
||||
if (mLinePaint == null) {
|
||||
mLinePaint = new Paint();
|
||||
}
|
||||
|
||||
if(mLinePath == null) {
|
||||
mLinePath = new Path();
|
||||
}
|
||||
|
||||
mLinePaint.setARGB(mFillStyleA, mFillStyleR, mFillStyleG, mFillStyleB);
|
||||
mLinePaint.setStyle(Paint.Style.FILL);
|
||||
mCanvas.drawPath(mLinePath, mLinePaint);
|
||||
// workaround: draw a hairline to cover the border
|
||||
mLinePaint.setStrokeWidth(0);
|
||||
this.setStrokeCap(mLinePaint);
|
||||
this.setStrokeJoin(mLinePaint);
|
||||
mLinePaint.setStyle(Paint.Style.STROKE);
|
||||
mCanvas.drawPath(mLinePath, mLinePaint);
|
||||
mLinePaint.setStrokeWidth(mLineWidth);
|
||||
}
|
||||
|
||||
private void setLineCap(String lineCap) {
|
||||
mLineCap = lineCap;
|
||||
}
|
||||
|
||||
private void setLineJoin(String lineJoin) {
|
||||
mLineJoin = lineJoin;
|
||||
}
|
||||
|
||||
private void saveContext() {
|
||||
mCanvas.save();
|
||||
}
|
||||
|
||||
private void restoreContext() {
|
||||
// If there is no saved state, this method should do nothing.
|
||||
if (mCanvas.getSaveCount() > 1){
|
||||
mCanvas.restore();
|
||||
}
|
||||
}
|
||||
|
||||
private void rect(float x, float y, float w, float h) {
|
||||
// Log.d(TAG, "this: " + this + ", rect: " + x + ", " + y + ", " + w + ", " + h);
|
||||
beginPath();
|
||||
moveTo(x, y);
|
||||
lineTo(x, y + h);
|
||||
lineTo(x + w, y + h);
|
||||
lineTo(x + w, y);
|
||||
closePath();
|
||||
}
|
||||
|
||||
private void clearRect(float x, float y, float w, float h) {
|
||||
// Log.d(TAG, "this: " + this + ", clearRect: " + x + ", " + y + ", " + w + ", " + h);
|
||||
int clearSize = (int)(w * h);
|
||||
int[] clearColor = new int[clearSize];
|
||||
for (int i = 0; i < clearSize; ++i) {
|
||||
clearColor[i] = Color.TRANSPARENT;
|
||||
}
|
||||
mBitmap.setPixels(clearColor, 0, (int) w, (int) x, (int) y, (int) w, (int) h);
|
||||
}
|
||||
|
||||
private void createTextPaintIfNeeded() {
|
||||
if (mTextPaint == null) {
|
||||
mTextPaint = newPaint(mFontName, (int) mFontSize, mIsBoldFont, mIsItalicFont, mIsObliqueFont, mIsSmallCapsFontVariant);
|
||||
}
|
||||
}
|
||||
|
||||
private void fillRect(float x, float y, float w, float h) {
|
||||
// Log.d(TAG, "fillRect: " + x + ", " + y + ", " + ", " + w + ", " + h);
|
||||
int pixelValue = (mFillStyleA & 0xff) << 24 | (mFillStyleR & 0xff) << 16 | (mFillStyleG & 0xff) << 8 | (mFillStyleB & 0xff);
|
||||
int fillSize = (int)(w * h);
|
||||
int[] fillColors = new int[fillSize];
|
||||
for (int i = 0; i < fillSize; ++i) {
|
||||
fillColors[i] = pixelValue;
|
||||
}
|
||||
mBitmap.setPixels(fillColors, 0, (int) w, (int)x, (int)y, (int)w, (int)h);
|
||||
}
|
||||
|
||||
private void scaleX(TextPaint textPaint, String text, float maxWidth) {
|
||||
if(maxWidth < Float.MIN_VALUE) return;
|
||||
float measureWidth = this.measureText(text);
|
||||
if((measureWidth - maxWidth) < Float.MIN_VALUE) return;
|
||||
float scaleX = maxWidth/measureWidth;
|
||||
textPaint.setTextScaleX(scaleX);
|
||||
}
|
||||
|
||||
private void fillText(String text, float x, float y, float maxWidth) {
|
||||
// Log.d(TAG, "this: " + this + ", fillText: " + text + ", " + x + ", " + y + ", " + ", " + maxWidth);
|
||||
createTextPaintIfNeeded();
|
||||
mTextPaint.setARGB(mFillStyleA, mFillStyleR, mFillStyleG, mFillStyleB);
|
||||
mTextPaint.setStyle(Paint.Style.FILL);
|
||||
scaleX(mTextPaint, text, maxWidth);
|
||||
Point pt = convertDrawPoint(new Point(x, y), text);
|
||||
mCanvas.drawText(text, pt.x, pt.y, mTextPaint);
|
||||
}
|
||||
|
||||
private void strokeText(String text, float x, float y, float maxWidth) {
|
||||
// Log.d(TAG, "strokeText: " + text + ", " + x + ", " + y + ", " + ", " + maxWidth);
|
||||
createTextPaintIfNeeded();
|
||||
mTextPaint.setARGB(mStrokeStyleA, mStrokeStyleR, mStrokeStyleG, mStrokeStyleB);
|
||||
mTextPaint.setStyle(Paint.Style.STROKE);
|
||||
mTextPaint.setStrokeWidth(mLineWidth);
|
||||
scaleX(mTextPaint, text, maxWidth);
|
||||
Point pt = convertDrawPoint(new Point(x, y), text);
|
||||
mCanvas.drawText(text, pt.x, pt.y, mTextPaint);
|
||||
}
|
||||
|
||||
private float measureText(String text) {
|
||||
createTextPaintIfNeeded();
|
||||
float ret = mTextPaint.measureText(text);
|
||||
// Log.d(TAG, "measureText: " + text + ", return: " + ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
private Size measureTextReturnSize(String text) {
|
||||
createTextPaintIfNeeded();
|
||||
Paint.FontMetrics fm = mTextPaint.getFontMetrics();
|
||||
// Use descent & ascent for clipping the transparent region.
|
||||
// So don't use bottom & top which will make text be cut.
|
||||
return new Size(measureText(text), fm.descent - fm.ascent);
|
||||
}
|
||||
|
||||
private void updateFont(String fontName, float fontSize, boolean bold, boolean italic, boolean oblique, boolean smallCaps) {
|
||||
// Log.d(TAG, "updateFont: " + fontName + ", " + fontSize);
|
||||
mFontName = fontName;
|
||||
mFontSize = fontSize;
|
||||
mIsBoldFont = bold;
|
||||
mIsItalicFont = italic;
|
||||
mIsObliqueFont = oblique;
|
||||
mIsSmallCapsFontVariant = smallCaps;
|
||||
mTextPaint = null; // Reset paint to re-create paint object in createTextPaintIfNeeded
|
||||
}
|
||||
|
||||
private void setTextAlign(int align) {
|
||||
// Log.d(TAG, "setTextAlign: " + align);
|
||||
mTextAlign = align;
|
||||
}
|
||||
|
||||
private void setTextBaseline(int baseline) {
|
||||
// Log.d(TAG, "setTextBaseline: " + baseline);
|
||||
mTextBaseline = baseline;
|
||||
}
|
||||
|
||||
private void setFillStyle(float r, float g, float b, float a) {
|
||||
// Log.d(TAG, "setFillStyle: " + r + ", " + g + ", " + b + ", " + a);
|
||||
mFillStyleR = (int)(r * 255.0f);
|
||||
mFillStyleG = (int)(g * 255.0f);
|
||||
mFillStyleB = (int)(b * 255.0f);
|
||||
mFillStyleA = (int)(a * 255.0f);
|
||||
}
|
||||
|
||||
private void setStrokeStyle(float r, float g, float b, float a) {
|
||||
// Log.d(TAG, "setStrokeStyle: " + r + ", " + g + ", " + b + ", " + a);
|
||||
mStrokeStyleR = (int)(r * 255.0f);
|
||||
mStrokeStyleG = (int)(g * 255.0f);
|
||||
mStrokeStyleB = (int)(b * 255.0f);
|
||||
mStrokeStyleA = (int)(a * 255.0f);
|
||||
}
|
||||
|
||||
private void setLineWidth(float lineWidth) {
|
||||
mLineWidth = lineWidth;
|
||||
}
|
||||
|
||||
private void _fillImageData(byte[] imageData, float imageWidth, float imageHeight, float offsetX, float offsetY) {
|
||||
Log.d(TAG, "_fillImageData: ");
|
||||
int fillSize = (int) (imageWidth * imageHeight);
|
||||
int[] fillColors = new int[fillSize];
|
||||
int r, g, b, a;
|
||||
for (int i = 0; i < fillSize; ++i) {
|
||||
// imageData Pixel (RGBA) -> fillColors int (ARGB)
|
||||
r = ((int)imageData[4 * i + 0]) & 0xff;
|
||||
g = ((int)imageData[4 * i + 1]) & 0xff;
|
||||
b = ((int)imageData[4 * i + 2]) & 0xff;
|
||||
a = ((int)imageData[4 * i + 3]) & 0xff;
|
||||
fillColors[i] = (a & 0xff) << 24 | (r & 0xff) << 16 | (g & 0xff) << 8 | (b & 0xff);
|
||||
}
|
||||
mBitmap.setPixels(fillColors, 0, (int) imageWidth, (int) offsetX, (int) offsetY, (int) imageWidth, (int) imageHeight);
|
||||
}
|
||||
|
||||
private Point convertDrawPoint(final Point point, String text) {
|
||||
// The parameter 'point' is located at left-bottom position.
|
||||
// Need to adjust 'point' according 'text align' & 'text base line'.
|
||||
Point ret = new Point(point);
|
||||
Size textSize = measureTextReturnSize(text);
|
||||
// Log.d(TAG,"textSize: " + textSize.width + ", " + textSize.height);
|
||||
|
||||
if (mTextAlign == TEXT_ALIGN_CENTER)
|
||||
{
|
||||
ret.x -= textSize.width / 2;
|
||||
}
|
||||
else if (mTextAlign == TEXT_ALIGN_RIGHT)
|
||||
{
|
||||
ret.x -= textSize.width;
|
||||
}
|
||||
|
||||
if (mTextBaseline == TEXT_BASELINE_TOP)
|
||||
{
|
||||
ret.y += textSize.height;
|
||||
}
|
||||
else if (mTextBaseline == TEXT_BASELINE_MIDDLE)
|
||||
{
|
||||
ret.y += textSize.height / 2;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private byte[] getDataRef() {
|
||||
// Log.d(TAG, "this: " + this + ", getDataRef ...");
|
||||
if (mBitmap != null) {
|
||||
final int len = mBitmap.getWidth() * mBitmap.getHeight() * 4;
|
||||
final byte[] pixels = new byte[len];
|
||||
final ByteBuffer buf = ByteBuffer.wrap(pixels);
|
||||
buf.order(ByteOrder.nativeOrder());
|
||||
mBitmap.copyPixelsToBuffer(buf);
|
||||
|
||||
return pixels;
|
||||
}
|
||||
|
||||
Log.e(TAG, "getDataRef return null");
|
||||
return null;
|
||||
}
|
||||
}
|
@@ -0,0 +1,147 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2010-2013 cocos2d-x.org
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
package org.cocos2dx.lib;
|
||||
|
||||
import android.content.Context;
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorEvent;
|
||||
import android.hardware.SensorEventListener;
|
||||
import android.hardware.SensorManager;
|
||||
|
||||
public class Cocos2dxAccelerometer implements SensorEventListener {
|
||||
// ===========================================================
|
||||
// Constants
|
||||
// ===========================================================
|
||||
|
||||
private static final String TAG = Cocos2dxAccelerometer.class.getSimpleName();
|
||||
|
||||
// ===========================================================
|
||||
// Fields
|
||||
// ===========================================================
|
||||
private final Context mContext;
|
||||
private final SensorManager mSensorManager;
|
||||
private final Sensor mAcceleration;
|
||||
private final Sensor mAccelerationIncludingGravity;
|
||||
private final Sensor mGyroscope;
|
||||
private int mSamplingPeriodUs = SensorManager.SENSOR_DELAY_GAME;
|
||||
|
||||
class Acceleration {
|
||||
public float x = 0.0f;
|
||||
public float y = 0.0f;
|
||||
public float z = 0.0f;
|
||||
}
|
||||
|
||||
class RotationRate {
|
||||
public float alpha = 0.0f;
|
||||
public float beta = 0.0f;
|
||||
public float gamma = 0.0f;
|
||||
}
|
||||
|
||||
class DeviceMotionEvent {
|
||||
public Acceleration acceleration = new Acceleration();
|
||||
public Acceleration accelerationIncludingGravity = new Acceleration();
|
||||
public RotationRate rotationRate = new RotationRate();
|
||||
}
|
||||
|
||||
private DeviceMotionEvent mDeviceMotionEvent = new DeviceMotionEvent();
|
||||
|
||||
// ===========================================================
|
||||
// Constructors
|
||||
// ===========================================================
|
||||
|
||||
public Cocos2dxAccelerometer(final Context context) {
|
||||
mContext = context;
|
||||
|
||||
mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
|
||||
mAcceleration = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
|
||||
mAccelerationIncludingGravity = mSensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION);
|
||||
mGyroscope = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
|
||||
}
|
||||
|
||||
// ===========================================================
|
||||
// Getter & Setter
|
||||
// ===========================================================
|
||||
public void enable() {
|
||||
mSensorManager.registerListener(this, mAcceleration, mSamplingPeriodUs);
|
||||
mSensorManager.registerListener(this, mAccelerationIncludingGravity, mSamplingPeriodUs);
|
||||
mSensorManager.registerListener(this, mGyroscope, mSamplingPeriodUs);
|
||||
}
|
||||
|
||||
public void disable() {
|
||||
this.mSensorManager.unregisterListener(this);
|
||||
}
|
||||
|
||||
public void setInterval(float interval) {
|
||||
if (android.os.Build.VERSION.SDK_INT >= 11) {
|
||||
mSamplingPeriodUs = (int) (interval * 1000000);
|
||||
}
|
||||
disable();
|
||||
enable();
|
||||
}
|
||||
|
||||
public DeviceMotionEvent getDeviceMotionEvent() {
|
||||
return mDeviceMotionEvent;
|
||||
}
|
||||
|
||||
// ===========================================================
|
||||
// Methods for/from SuperClass/Interfaces
|
||||
// ===========================================================
|
||||
@Override
|
||||
public void onSensorChanged(final SensorEvent sensorEvent) {
|
||||
int type = sensorEvent.sensor.getType();
|
||||
if (type == Sensor.TYPE_ACCELEROMETER) {
|
||||
mDeviceMotionEvent.accelerationIncludingGravity.x = sensorEvent.values[0];
|
||||
mDeviceMotionEvent.accelerationIncludingGravity.y = sensorEvent.values[1];
|
||||
mDeviceMotionEvent.accelerationIncludingGravity.z = sensorEvent.values[2];
|
||||
}
|
||||
else if (type == Sensor.TYPE_LINEAR_ACCELERATION) {
|
||||
mDeviceMotionEvent.acceleration.x = sensorEvent.values[0];
|
||||
mDeviceMotionEvent.acceleration.y = sensorEvent.values[1];
|
||||
mDeviceMotionEvent.acceleration.z = sensorEvent.values[2];
|
||||
}
|
||||
else if (type == Sensor.TYPE_GYROSCOPE) {
|
||||
// The unit is rad/s, need to be converted to deg/s
|
||||
mDeviceMotionEvent.rotationRate.alpha = (float)Math.toDegrees(sensorEvent.values[0]);
|
||||
mDeviceMotionEvent.rotationRate.beta = (float)Math.toDegrees(sensorEvent.values[1]);
|
||||
mDeviceMotionEvent.rotationRate.gamma = (float)Math.toDegrees(sensorEvent.values[2]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAccuracyChanged(final Sensor sensor, final int accuracy) {
|
||||
}
|
||||
|
||||
// ===========================================================
|
||||
// Methods
|
||||
// Native method called from Cocos2dxGLSurfaceView (To be in the same thread)
|
||||
// ===========================================================
|
||||
|
||||
public static native void onSensorChanged(final float x, final float y, final float z, final long timestamp);
|
||||
|
||||
// ===========================================================
|
||||
// Inner and Anonymous Classes
|
||||
// ===========================================================
|
||||
}
|
@@ -0,0 +1,652 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2010-2013 cocos2d-x.org
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
package org.cocos2dx.lib;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.media.AudioManager;
|
||||
import android.opengl.GLSurfaceView;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Message;
|
||||
import android.preference.PreferenceManager.OnActivityResultListener;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.cocos2dx.lib.Cocos2dxHelper.Cocos2dxHelperListener;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import javax.microedition.khronos.egl.EGL10;
|
||||
import javax.microedition.khronos.egl.EGLConfig;
|
||||
import javax.microedition.khronos.egl.EGLDisplay;
|
||||
|
||||
public abstract class Cocos2dxActivity extends Activity implements Cocos2dxHelperListener {
|
||||
// ===========================================================
|
||||
// Constants
|
||||
// ===========================================================
|
||||
|
||||
private final static String TAG = Cocos2dxActivity.class.getSimpleName();
|
||||
|
||||
// ===========================================================
|
||||
// Fields
|
||||
// ===========================================================
|
||||
private static Cocos2dxActivity sContext = null;
|
||||
|
||||
protected FrameLayout mFrameLayout = null;
|
||||
|
||||
private Cocos2dxGLSurfaceView mGLSurfaceView = null;
|
||||
private int[] mGLContextAttrs = null;
|
||||
private Cocos2dxHandler mHandler = null;
|
||||
private Cocos2dxVideoHelper mVideoHelper = null;
|
||||
private Cocos2dxWebViewHelper mWebViewHelper = null;
|
||||
private boolean hasFocus = false;
|
||||
private Cocos2dxEditBox mEditBox = null;
|
||||
private boolean gainAudioFocus = false;
|
||||
private boolean paused = true;
|
||||
|
||||
// DEBUG VIEW BEGIN
|
||||
private LinearLayout mLinearLayoutForDebugView;
|
||||
private TextView mFPSTextView;
|
||||
private TextView mJSBInvocationTextView;
|
||||
private TextView mGLOptModeTextView;
|
||||
private TextView mGameInfoTextView_0;
|
||||
private TextView mGameInfoTextView_1;
|
||||
private TextView mGameInfoTextView_2;
|
||||
// DEBUG VIEW END
|
||||
|
||||
private Cocos2dxOrientationHelper mCocos2dxOrientationHelper = null;
|
||||
// ===========================================================
|
||||
// Inner class
|
||||
// ===========================================================
|
||||
|
||||
public class Cocos2dxEGLConfigChooser implements GLSurfaceView.EGLConfigChooser {
|
||||
protected int[] configAttribs;
|
||||
public Cocos2dxEGLConfigChooser(int redSize, int greenSize, int blueSize, int alphaSize, int depthSize, int stencilSize)
|
||||
{
|
||||
configAttribs = new int[] {redSize, greenSize, blueSize, alphaSize, depthSize, stencilSize};
|
||||
}
|
||||
public Cocos2dxEGLConfigChooser(int[] attribs)
|
||||
{
|
||||
configAttribs = attribs;
|
||||
}
|
||||
|
||||
private int findConfigAttrib(EGL10 egl, EGLDisplay display,
|
||||
EGLConfig config, int attribute, int defaultValue) {
|
||||
int[] value = new int[1];
|
||||
if (egl.eglGetConfigAttrib(display, config, attribute, value)) {
|
||||
return value[0];
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
class ConfigValue implements Comparable<ConfigValue> {
|
||||
public EGLConfig config = null;
|
||||
public int[] configAttribs = null;
|
||||
public int value = 0;
|
||||
private void calcValue() {
|
||||
// depth factor 29bit and [6,12)bit
|
||||
if (configAttribs[4] > 0) {
|
||||
value = value + (1 << 29) + ((configAttribs[4]%64) << 6);
|
||||
}
|
||||
// stencil factor 28bit and [0, 6)bit
|
||||
if (configAttribs[5] > 0) {
|
||||
value = value + (1 << 28) + ((configAttribs[5]%64));
|
||||
}
|
||||
// alpha factor 30bit and [24, 28)bit
|
||||
if (configAttribs[3] > 0) {
|
||||
value = value + (1 << 30) + ((configAttribs[3]%16) << 24);
|
||||
}
|
||||
// green factor [20, 24)bit
|
||||
if (configAttribs[1] > 0) {
|
||||
value = value + ((configAttribs[1]%16) << 20);
|
||||
}
|
||||
// blue factor [16, 20)bit
|
||||
if (configAttribs[2] > 0) {
|
||||
value = value + ((configAttribs[2]%16) << 16);
|
||||
}
|
||||
// red factor [12, 16)bit
|
||||
if (configAttribs[0] > 0) {
|
||||
value = value + ((configAttribs[0]%16) << 12);
|
||||
}
|
||||
}
|
||||
|
||||
public ConfigValue(int[] attribs) {
|
||||
configAttribs = attribs;
|
||||
calcValue();
|
||||
}
|
||||
|
||||
public ConfigValue(EGL10 egl, EGLDisplay display, EGLConfig config) {
|
||||
this.config = config;
|
||||
configAttribs = new int[6];
|
||||
configAttribs[0] = findConfigAttrib(egl, display, config, EGL10.EGL_RED_SIZE, 0);
|
||||
configAttribs[1] = findConfigAttrib(egl, display, config, EGL10.EGL_GREEN_SIZE, 0);
|
||||
configAttribs[2] = findConfigAttrib(egl, display, config, EGL10.EGL_BLUE_SIZE, 0);
|
||||
configAttribs[3] = findConfigAttrib(egl, display, config, EGL10.EGL_ALPHA_SIZE, 0);
|
||||
configAttribs[4] = findConfigAttrib(egl, display, config, EGL10.EGL_DEPTH_SIZE, 0);
|
||||
configAttribs[5] = findConfigAttrib(egl, display, config, EGL10.EGL_STENCIL_SIZE, 0);
|
||||
calcValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(ConfigValue another) {
|
||||
if (value < another.value) {
|
||||
return -1;
|
||||
} else if (value > another.value) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{ color: " + configAttribs[3] + configAttribs[2] + configAttribs[1] + configAttribs[0] +
|
||||
"; depth: " + configAttribs[4] + "; stencil: " + configAttribs[5] + ";}";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display)
|
||||
{
|
||||
int[] EGLattribs = {
|
||||
EGL10.EGL_RED_SIZE, configAttribs[0],
|
||||
EGL10.EGL_GREEN_SIZE, configAttribs[1],
|
||||
EGL10.EGL_BLUE_SIZE, configAttribs[2],
|
||||
EGL10.EGL_ALPHA_SIZE, configAttribs[3],
|
||||
EGL10.EGL_DEPTH_SIZE, configAttribs[4],
|
||||
EGL10.EGL_STENCIL_SIZE,configAttribs[5],
|
||||
EGL10.EGL_RENDERABLE_TYPE, 4, //EGL_OPENGL_ES2_BIT
|
||||
EGL10.EGL_NONE
|
||||
};
|
||||
EGLConfig[] configs = new EGLConfig[1];
|
||||
int[] numConfigs = new int[1];
|
||||
boolean eglChooseResult = egl.eglChooseConfig(display, EGLattribs, configs, 1, numConfigs);
|
||||
if (eglChooseResult && numConfigs[0] > 0)
|
||||
{
|
||||
return configs[0];
|
||||
}
|
||||
|
||||
// there's no config match the specific configAttribs, we should choose a closest one
|
||||
int[] EGLV2attribs = {
|
||||
EGL10.EGL_RENDERABLE_TYPE, 4, //EGL_OPENGL_ES2_BIT
|
||||
EGL10.EGL_NONE
|
||||
};
|
||||
eglChooseResult = egl.eglChooseConfig(display, EGLV2attribs, null, 0, numConfigs);
|
||||
if(eglChooseResult && numConfigs[0] > 0) {
|
||||
int num = numConfigs[0];
|
||||
ConfigValue[] cfgVals = new ConfigValue[num];
|
||||
|
||||
// convert all config to ConfigValue
|
||||
configs = new EGLConfig[num];
|
||||
egl.eglChooseConfig(display, EGLV2attribs, configs, num, numConfigs);
|
||||
for (int i = 0; i < num; ++i) {
|
||||
cfgVals[i] = new ConfigValue(egl, display, configs[i]);
|
||||
}
|
||||
|
||||
ConfigValue e = new ConfigValue(configAttribs);
|
||||
// bin search
|
||||
int lo = 0;
|
||||
int hi = num;
|
||||
int mi;
|
||||
while (lo < hi - 1) {
|
||||
mi = (lo + hi) / 2;
|
||||
if (e.compareTo(cfgVals[mi]) < 0) {
|
||||
hi = mi;
|
||||
} else {
|
||||
lo = mi;
|
||||
}
|
||||
}
|
||||
if (lo != num - 1) {
|
||||
lo = lo + 1;
|
||||
}
|
||||
Log.w("cocos2d", "Can't find EGLConfig match: " + e + ", instead of closest one:" + cfgVals[lo]);
|
||||
return cfgVals[lo].config;
|
||||
}
|
||||
|
||||
Log.e(DEVICE_POLICY_SERVICE, "Can not select an EGLConfig for rendering.");
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ===========================================================
|
||||
// Member methods
|
||||
// ===========================================================
|
||||
|
||||
public Cocos2dxGLSurfaceView getGLSurfaceView(){
|
||||
return mGLSurfaceView;
|
||||
}
|
||||
public static Context getContext() {
|
||||
return sContext;
|
||||
}
|
||||
|
||||
public void init() {
|
||||
ViewGroup.LayoutParams frameLayoutParams =
|
||||
new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT);
|
||||
mFrameLayout = new FrameLayout(this);
|
||||
mFrameLayout.setLayoutParams(frameLayoutParams);
|
||||
|
||||
Cocos2dxRenderer renderer = this.addSurfaceView();
|
||||
this.addDebugInfo(renderer);
|
||||
|
||||
|
||||
// Should create EditBox after adding SurfaceView, or EditBox will be hidden by SurfaceView.
|
||||
mEditBox = new Cocos2dxEditBox(this, mFrameLayout);
|
||||
|
||||
// Set frame layout as the content view
|
||||
setContentView(mFrameLayout);
|
||||
|
||||
WindowManager.LayoutParams lp = getWindow().getAttributes();
|
||||
try {
|
||||
Field field = lp.getClass().getField("layoutInDisplayCutoutMode");
|
||||
//Field constValue = lp.getClass().getDeclaredField("LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER");
|
||||
Field constValue = lp.getClass().getDeclaredField("LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES");
|
||||
field.setInt(lp, constValue.getInt(null));
|
||||
|
||||
// https://developer.android.com/training/system-ui/immersive
|
||||
int flag = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
||||
| View.SYSTEM_UI_FLAG_FULLSCREEN
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
|
||||
|
||||
flag |= View.class.getDeclaredField("SYSTEM_UI_FLAG_IMMERSIVE_STICKY").getInt(null);
|
||||
View view = getWindow().getDecorView();
|
||||
view.setSystemUiVisibility(flag);
|
||||
|
||||
} catch (NoSuchFieldException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
mCocos2dxOrientationHelper = new Cocos2dxOrientationHelper(this);
|
||||
}
|
||||
|
||||
public void setKeepScreenOn(boolean value) {
|
||||
final boolean newValue = value;
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mGLSurfaceView.setKeepScreenOn(newValue);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void setEnableAudioFocusGain(boolean value) {
|
||||
if(gainAudioFocus != value) {
|
||||
if(!paused) {
|
||||
if (value)
|
||||
Cocos2dxAudioFocusManager.registerAudioFocusListener(this);
|
||||
else
|
||||
Cocos2dxAudioFocusManager.unregisterAudioFocusListener(this);
|
||||
}
|
||||
gainAudioFocus = value;
|
||||
}
|
||||
}
|
||||
|
||||
public Cocos2dxGLSurfaceView onCreateView() {
|
||||
Cocos2dxGLSurfaceView glSurfaceView = new Cocos2dxGLSurfaceView(this);
|
||||
//this line is need on some device if we specify an alpha bits
|
||||
if(this.mGLContextAttrs[3] > 0) glSurfaceView.getHolder().setFormat(PixelFormat.TRANSLUCENT);
|
||||
|
||||
Cocos2dxEGLConfigChooser chooser = new Cocos2dxEGLConfigChooser(this.mGLContextAttrs);
|
||||
glSurfaceView.setEGLConfigChooser(chooser);
|
||||
|
||||
return glSurfaceView;
|
||||
}
|
||||
|
||||
// ===========================================================
|
||||
// Override functions
|
||||
// ===========================================================
|
||||
|
||||
@Override
|
||||
protected void onCreate(final Bundle savedInstanceState) {
|
||||
Log.d(TAG, "Cocos2dxActivity onCreate: " + this + ", savedInstanceState: " + savedInstanceState);
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// Workaround in https://stackoverflow.com/questions/16283079/re-launch-of-activity-on-home-button-but-only-the-first-time/16447508
|
||||
if (!isTaskRoot()) {
|
||||
// Android launched another instance of the root activity into an existing task
|
||||
// so just quietly finish and go away, dropping the user back into the activity
|
||||
// at the top of the stack (ie: the last state of this task)
|
||||
finish();
|
||||
Log.w(TAG, "[Workaround] Ignore the activity started from icon!");
|
||||
return;
|
||||
}
|
||||
|
||||
Utils.setActivity(this);
|
||||
|
||||
Utils.hideVirtualButton();
|
||||
|
||||
Cocos2dxHelper.registerBatteryLevelReceiver(this);
|
||||
|
||||
onLoadNativeLibraries();
|
||||
|
||||
sContext = this;
|
||||
this.mHandler = new Cocos2dxHandler(this);
|
||||
|
||||
Cocos2dxHelper.init(this);
|
||||
CanvasRenderingContext2DImpl.init(this);
|
||||
|
||||
this.mGLContextAttrs = getGLContextAttrs();
|
||||
this.init();
|
||||
|
||||
if (mVideoHelper == null) {
|
||||
mVideoHelper = new Cocos2dxVideoHelper(this, mFrameLayout);
|
||||
}
|
||||
|
||||
if(mWebViewHelper == null){
|
||||
mWebViewHelper = new Cocos2dxWebViewHelper(mFrameLayout);
|
||||
}
|
||||
|
||||
Window window = this.getWindow();
|
||||
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
|
||||
this.setVolumeControlStream(AudioManager.STREAM_MUSIC);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
Log.d(TAG, "onResume()");
|
||||
paused = false;
|
||||
super.onResume();
|
||||
if(gainAudioFocus)
|
||||
Cocos2dxAudioFocusManager.registerAudioFocusListener(this);
|
||||
Utils.hideVirtualButton();
|
||||
resumeIfHasFocus();
|
||||
mCocos2dxOrientationHelper.onResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWindowFocusChanged(boolean hasFocus) {
|
||||
Log.d(TAG, "onWindowFocusChanged() hasFocus=" + hasFocus);
|
||||
super.onWindowFocusChanged(hasFocus);
|
||||
|
||||
this.hasFocus = hasFocus;
|
||||
resumeIfHasFocus();
|
||||
}
|
||||
|
||||
private void resumeIfHasFocus() {
|
||||
if(hasFocus && !paused) {
|
||||
Utils.hideVirtualButton();
|
||||
Cocos2dxHelper.onResume();
|
||||
mGLSurfaceView.onResume();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
Log.d(TAG, "onPause()");
|
||||
paused = true;
|
||||
super.onPause();
|
||||
if(gainAudioFocus)
|
||||
Cocos2dxAudioFocusManager.unregisterAudioFocusListener(this);
|
||||
Cocos2dxHelper.onPause();
|
||||
mGLSurfaceView.onPause();
|
||||
mCocos2dxOrientationHelper.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
// Workaround in https://stackoverflow.com/questions/16283079/re-launch-of-activity-on-home-button-but-only-the-first-time/16447508
|
||||
if (!isTaskRoot()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(gainAudioFocus)
|
||||
Cocos2dxAudioFocusManager.unregisterAudioFocusListener(this);
|
||||
Cocos2dxHelper.unregisterBatteryLevelReceiver(this);;
|
||||
CanvasRenderingContext2DImpl.destroy();
|
||||
|
||||
Log.d(TAG, "Cocos2dxActivity onDestroy: " + this + ", mGLSurfaceView" + mGLSurfaceView);
|
||||
if (mGLSurfaceView != null) {
|
||||
Cocos2dxHelper.terminateProcess();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showDialog(final String pTitle, final String pMessage) {
|
||||
Message msg = new Message();
|
||||
msg.what = Cocos2dxHandler.HANDLER_SHOW_DIALOG;
|
||||
msg.obj = new Cocos2dxHandler.DialogMessage(pTitle, pMessage);
|
||||
this.mHandler.sendMessage(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runOnGLThread(final Runnable runnable) {
|
||||
this.mGLSurfaceView.queueEvent(runnable);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data)
|
||||
{
|
||||
for (OnActivityResultListener listener : Cocos2dxHelper.getOnActivityResultListeners()) {
|
||||
listener.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
|
||||
// ===========================================================
|
||||
// Protected and private methods
|
||||
// ===========================================================
|
||||
|
||||
protected void onLoadNativeLibraries() {
|
||||
try {
|
||||
ApplicationInfo ai = getPackageManager().getApplicationInfo(getPackageName(), PackageManager.GET_META_DATA);
|
||||
Bundle bundle = ai.metaData;
|
||||
String libName = bundle.getString("android.app.lib_name");
|
||||
System.loadLibrary(libName);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private Cocos2dxRenderer addSurfaceView() {
|
||||
this.mGLSurfaceView = this.onCreateView();
|
||||
this.mGLSurfaceView.setPreserveEGLContextOnPause(true);
|
||||
// Should set to transparent, or it will hide EditText
|
||||
// https://stackoverflow.com/questions/2978290/androids-edittext-is-hidden-when-the-virtual-keyboard-is-shown-and-a-surfacevie
|
||||
mGLSurfaceView.setBackgroundColor(Color.TRANSPARENT);
|
||||
// Switch to supported OpenGL (ARGB888) mode on emulator
|
||||
if (isAndroidEmulator())
|
||||
this.mGLSurfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 0);
|
||||
|
||||
Cocos2dxRenderer renderer = new Cocos2dxRenderer();
|
||||
this.mGLSurfaceView.setCocos2dxRenderer(renderer);
|
||||
|
||||
mFrameLayout.addView(this.mGLSurfaceView);
|
||||
|
||||
return renderer;
|
||||
}
|
||||
|
||||
private void addDebugInfo(Cocos2dxRenderer renderer) {
|
||||
LinearLayout.LayoutParams linearLayoutParam = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT);
|
||||
linearLayoutParam.setMargins(30, 0, 0, 0);
|
||||
Cocos2dxHelper.setOnGameInfoUpdatedListener(new Cocos2dxHelper.OnGameInfoUpdatedListener() {
|
||||
@Override
|
||||
public void onFPSUpdated(float fps) {
|
||||
Cocos2dxActivity.this.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (mFPSTextView != null) {
|
||||
mFPSTextView.setText("FPS: " + (int)Math.ceil(fps));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onJSBInvocationCountUpdated(int count) {
|
||||
Cocos2dxActivity.this.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (mJSBInvocationTextView != null) {
|
||||
mJSBInvocationTextView.setText("JSB: " + count);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpenDebugView() {
|
||||
Cocos2dxActivity.this.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (mLinearLayoutForDebugView != null || mFrameLayout == null) {
|
||||
Log.e(TAG, "onOpenDebugView: failed!");
|
||||
return;
|
||||
}
|
||||
|
||||
mLinearLayoutForDebugView = new LinearLayout(Cocos2dxActivity.this);
|
||||
mLinearLayoutForDebugView.setOrientation(LinearLayout.VERTICAL);
|
||||
mFrameLayout.addView(mLinearLayoutForDebugView);
|
||||
|
||||
mFPSTextView = new TextView(Cocos2dxActivity.this);
|
||||
mFPSTextView.setBackgroundColor(Color.RED);
|
||||
mFPSTextView.setTextColor(Color.WHITE);
|
||||
mLinearLayoutForDebugView.addView(mFPSTextView, linearLayoutParam);
|
||||
|
||||
mJSBInvocationTextView = new TextView(Cocos2dxActivity.this);
|
||||
mJSBInvocationTextView.setBackgroundColor(Color.GREEN);
|
||||
mJSBInvocationTextView.setTextColor(Color.WHITE);
|
||||
mLinearLayoutForDebugView.addView(mJSBInvocationTextView, linearLayoutParam);
|
||||
|
||||
mGLOptModeTextView = new TextView(Cocos2dxActivity.this);
|
||||
mGLOptModeTextView.setBackgroundColor(Color.BLUE);
|
||||
mGLOptModeTextView.setTextColor(Color.WHITE);
|
||||
mGLOptModeTextView.setText("GL Opt: Enabled");
|
||||
mLinearLayoutForDebugView.addView(mGLOptModeTextView, linearLayoutParam);
|
||||
|
||||
mGameInfoTextView_0 = new TextView(Cocos2dxActivity.this);
|
||||
mGameInfoTextView_0.setBackgroundColor(Color.RED);
|
||||
mGameInfoTextView_0.setTextColor(Color.WHITE);
|
||||
mLinearLayoutForDebugView.addView(mGameInfoTextView_0, linearLayoutParam);
|
||||
|
||||
mGameInfoTextView_1 = new TextView(Cocos2dxActivity.this);
|
||||
mGameInfoTextView_1.setBackgroundColor(Color.GREEN);
|
||||
mGameInfoTextView_1.setTextColor(Color.WHITE);
|
||||
mLinearLayoutForDebugView.addView(mGameInfoTextView_1, linearLayoutParam);
|
||||
|
||||
mGameInfoTextView_2 = new TextView(Cocos2dxActivity.this);
|
||||
mGameInfoTextView_2.setBackgroundColor(Color.BLUE);
|
||||
mGameInfoTextView_2.setTextColor(Color.WHITE);
|
||||
mLinearLayoutForDebugView.addView(mGameInfoTextView_2, linearLayoutParam);
|
||||
}
|
||||
});
|
||||
|
||||
renderer.showFPS();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisableBatchGLCommandsToNative() {
|
||||
Cocos2dxActivity.this.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (mGLOptModeTextView != null) {
|
||||
mGLOptModeTextView.setText("GL Opt: Disabled");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGameInfoUpdated_0(final String text) {
|
||||
|
||||
Cocos2dxActivity.this.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (mGameInfoTextView_0 != null) {
|
||||
mGameInfoTextView_0.setText(text);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGameInfoUpdated_1(String text) {
|
||||
|
||||
Cocos2dxActivity.this.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (mGameInfoTextView_1 != null) {
|
||||
mGameInfoTextView_1.setText(text);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGameInfoUpdated_2(String text) {
|
||||
|
||||
Cocos2dxActivity.this.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (mGameInfoTextView_2 != null) {
|
||||
mGameInfoTextView_2.setText(text);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private final static boolean isAndroidEmulator() {
|
||||
String model = Build.MODEL;
|
||||
Log.d(TAG, "model=" + model);
|
||||
String product = Build.PRODUCT;
|
||||
Log.d(TAG, "product=" + product);
|
||||
boolean isEmulator = false;
|
||||
if (product != null) {
|
||||
isEmulator = product.equals("sdk") || product.contains("_sdk") || product.contains("sdk_");
|
||||
}
|
||||
Log.d(TAG, "isEmulator=" + isEmulator);
|
||||
return isEmulator;
|
||||
}
|
||||
|
||||
// ===========================================================
|
||||
// Native methods
|
||||
// ===========================================================
|
||||
|
||||
//native method,call GLViewImpl::getGLContextAttrs() to get the OpenGL ES context attributions
|
||||
private static native int[] getGLContextAttrs();
|
||||
}
|
@@ -0,0 +1,127 @@
|
||||
/****************************************************************************
|
||||
* Copyright (c) 2016 Chukong Technologies Inc.
|
||||
* Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
*
|
||||
* http://www.cocos2d-x.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
package org.cocos2dx.lib;
|
||||
|
||||
import android.content.Context;
|
||||
import android.media.AudioManager;
|
||||
import android.util.Log;
|
||||
|
||||
class Cocos2dxAudioFocusManager {
|
||||
|
||||
private final static String TAG = "AudioFocusManager";
|
||||
// Audio focus values synchronized with which in cocos/platform/android/javaactivity-android.cpp
|
||||
private final static int AUDIOFOCUS_GAIN = 0;
|
||||
private final static int AUDIOFOCUS_LOST = 1;
|
||||
private final static int AUDIOFOCUS_LOST_TRANSIENT = 2;
|
||||
private final static int AUDIOFOCUS_LOST_TRANSIENT_CAN_DUCK = 3;
|
||||
|
||||
private static AudioManager.OnAudioFocusChangeListener sAfChangeListener =
|
||||
new AudioManager.OnAudioFocusChangeListener() {
|
||||
public void onAudioFocusChange(int focusChange) {
|
||||
|
||||
Log.d(TAG, "onAudioFocusChange: " + focusChange + ", thread: " + Thread.currentThread().getName());
|
||||
|
||||
if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
|
||||
// Permanent loss of audio focus
|
||||
// Pause playback immediately
|
||||
Log.d(TAG, "Pause music by AUDIOFOCUS_LOSS");
|
||||
Cocos2dxHelper.runOnGLThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
nativeOnAudioFocusChange(AUDIOFOCUS_LOST);
|
||||
}
|
||||
});
|
||||
|
||||
} else if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) {
|
||||
// Pause playback
|
||||
Log.d(TAG, "Pause music by AUDIOFOCUS_LOSS_TRANSILENT");
|
||||
Cocos2dxHelper.runOnGLThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
nativeOnAudioFocusChange(AUDIOFOCUS_LOST_TRANSIENT);
|
||||
}
|
||||
});
|
||||
} else if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) {
|
||||
// Lower the volume, keep playing
|
||||
Log.d(TAG, "Lower the volume, keep playing by AUDIOFOCUS_LOSS_TRANSILENT_CAN_DUCK");
|
||||
Cocos2dxHelper.runOnGLThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
nativeOnAudioFocusChange(AUDIOFOCUS_LOST_TRANSIENT_CAN_DUCK);
|
||||
}
|
||||
});
|
||||
} else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
|
||||
// Your app has been granted audio focus again
|
||||
// Raise volume to normal, restart playback if necessary
|
||||
Log.d(TAG, "Resume music by AUDIOFOCUS_GAIN");
|
||||
Cocos2dxHelper.runOnGLThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
nativeOnAudioFocusChange(AUDIOFOCUS_GAIN);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static boolean registerAudioFocusListener(Context context) {
|
||||
AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
|
||||
|
||||
// Request audio focus for playback
|
||||
int result = am.requestAudioFocus(sAfChangeListener,
|
||||
// Use the music stream.
|
||||
AudioManager.STREAM_MUSIC,
|
||||
// Request permanent focus.
|
||||
AudioManager.AUDIOFOCUS_GAIN);
|
||||
|
||||
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
|
||||
Log.d(TAG, "requestAudioFocus succeed");
|
||||
return true;
|
||||
}
|
||||
|
||||
Log.e(TAG, "requestAudioFocus failed!");
|
||||
return false;
|
||||
}
|
||||
|
||||
static void unregisterAudioFocusListener(Context context) {
|
||||
AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
|
||||
int result = am.abandonAudioFocus(sAfChangeListener);
|
||||
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
|
||||
Log.d(TAG, "abandonAudioFocus succeed!");
|
||||
} else {
|
||||
Log.e(TAG, "abandonAudioFocus failed!");
|
||||
}
|
||||
|
||||
Cocos2dxHelper.runOnGLThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
nativeOnAudioFocusChange(AUDIOFOCUS_GAIN);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static native void nativeOnAudioFocusChange(int focusChange);
|
||||
}
|
@@ -0,0 +1,369 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated engine source code (the "Software"), a limited,
|
||||
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
|
||||
to use Cocos Creator solely to develop games on your target platforms. You shall
|
||||
not use Cocos Creator software for developing other software or tools that's
|
||||
used for developing games. You are not granted to publish, distribute,
|
||||
sublicense, and/or sell copies of Cocos Creator.
|
||||
|
||||
The software or tools in this License Agreement are licensed, not sold.
|
||||
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
package org.cocos2dx.lib;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
// Rename package okhttp3 to org.cocos2dx.okhttp3
|
||||
// Github repo: https://github.com/PatriceJiang/okhttp/tree/cocos2dx-rename-3.12.x
|
||||
// and https://github.com/PatriceJiang/okio/tree/cocos2dx-rename-1.15.0
|
||||
import org.cocos2dx.okhttp3.Call;
|
||||
import org.cocos2dx.okhttp3.Callback;
|
||||
import org.cocos2dx.okhttp3.OkHttpClient;
|
||||
import org.cocos2dx.okhttp3.Request;
|
||||
import org.cocos2dx.okhttp3.Response;
|
||||
|
||||
public class Cocos2dxDownloader {
|
||||
|
||||
private int _id;
|
||||
private OkHttpClient _httpClient = null;
|
||||
|
||||
private String _tempFileNameSuffix;
|
||||
private int _countOfMaxProcessingTasks;
|
||||
private ConcurrentHashMap<Integer,Call> _taskMap = new ConcurrentHashMap<>();
|
||||
private Queue<Runnable> _taskQueue = new LinkedList<>();
|
||||
private int _runningTaskCount = 0;
|
||||
private static ConcurrentHashMap<String, Boolean> _resumingSupport = new ConcurrentHashMap<>();
|
||||
|
||||
private void onProgress(final int id, final long downloadBytes, final long downloadNow, final long downloadTotal) {
|
||||
Cocos2dxHelper.runOnGLThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
nativeOnProgress(_id, id, downloadBytes, downloadNow, downloadTotal);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void onFinish(final int id, final int errCode, final String errStr, final byte[] data) {
|
||||
Call task =_taskMap.get(id);
|
||||
if (null == task) return;
|
||||
_taskMap.remove(id);
|
||||
_runningTaskCount -= 1;
|
||||
Cocos2dxHelper.runOnGLThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
nativeOnFinish(_id, id, errCode, errStr, data);
|
||||
}
|
||||
});
|
||||
runNextTaskIfExists();
|
||||
}
|
||||
|
||||
public static Cocos2dxDownloader createDownloader(int id, int timeoutInSeconds, String tempFileSuffix, int maxProcessingTasks) {
|
||||
Cocos2dxDownloader downloader = new Cocos2dxDownloader();
|
||||
downloader._id = id;
|
||||
|
||||
if (timeoutInSeconds > 0) {
|
||||
downloader._httpClient = new OkHttpClient().newBuilder()
|
||||
.followRedirects(true)
|
||||
.followSslRedirects(true)
|
||||
.callTimeout(timeoutInSeconds, TimeUnit.SECONDS)
|
||||
.build();
|
||||
} else {
|
||||
downloader._httpClient = new OkHttpClient().newBuilder()
|
||||
.followRedirects(true)
|
||||
.followSslRedirects(true)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
downloader._tempFileNameSuffix = tempFileSuffix;
|
||||
downloader._countOfMaxProcessingTasks = maxProcessingTasks;
|
||||
return downloader;
|
||||
}
|
||||
|
||||
public static void createTask(final Cocos2dxDownloader downloader, int id_, String url_, String path_, String []header_) {
|
||||
final int id = id_;
|
||||
final String url = url_;
|
||||
final String path = path_;
|
||||
final String[] header = header_;
|
||||
|
||||
Runnable taskRunnable = new Runnable() {
|
||||
String domain = null;
|
||||
String host = null;
|
||||
File tempFile = null;
|
||||
File finalFile = null;
|
||||
long downloadStart = 0;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Call task = null;
|
||||
|
||||
do {
|
||||
if (path.length() > 0) {
|
||||
try {
|
||||
URI uri = new URI(url);
|
||||
domain = uri.getHost();
|
||||
} catch (URISyntaxException e) {
|
||||
e.printStackTrace();
|
||||
break;
|
||||
} catch (NullPointerException e) {
|
||||
e.printStackTrace();
|
||||
break;
|
||||
}
|
||||
|
||||
// file task
|
||||
tempFile = new File(path + downloader._tempFileNameSuffix);
|
||||
if (tempFile.isDirectory()) break;
|
||||
|
||||
File parent = tempFile.getParentFile();
|
||||
if (!parent.isDirectory() && !parent.mkdirs()) break;
|
||||
|
||||
finalFile = new File(path);
|
||||
if (finalFile.isDirectory()) break;
|
||||
long fileLen = tempFile.length();
|
||||
|
||||
host = domain.startsWith("www.") ? domain.substring(4) : domain;
|
||||
if (fileLen > 0) {
|
||||
if (_resumingSupport.containsKey(host) && _resumingSupport.get(host)) {
|
||||
downloadStart = fileLen;
|
||||
} else {
|
||||
// Remove previous downloaded context
|
||||
try {
|
||||
PrintWriter writer = new PrintWriter(tempFile);
|
||||
writer.print("");
|
||||
writer.close();
|
||||
}
|
||||
// Not found then nothing to do
|
||||
catch (FileNotFoundException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final Request.Builder builder = new Request.Builder().url(url);
|
||||
for (int i = 0; i < header.length / 2; i++) {
|
||||
builder.addHeader(header[i * 2], header[(i * 2) + 1]);
|
||||
}
|
||||
if (downloadStart > 0) {
|
||||
builder.addHeader("RANGE", "bytes=" + downloadStart + "-");
|
||||
}
|
||||
|
||||
final Request request = builder.build();
|
||||
task = downloader._httpClient.newCall(request);
|
||||
if (null == task) {
|
||||
final String errStr = "Can't create DownloadTask for " + url;
|
||||
Cocos2dxHelper.runOnGLThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
downloader.nativeOnFinish(downloader._id, id, 0, errStr, null);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
downloader._taskMap.put(id, task);
|
||||
}
|
||||
task.enqueue(new Callback() {
|
||||
@Override
|
||||
public void onFailure(Call call, IOException e) {
|
||||
downloader.onFinish(id, 0, e.toString(), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(Call call, Response response) throws IOException {
|
||||
InputStream is = null;
|
||||
byte[] buf = new byte[4096];
|
||||
FileOutputStream fos = null;
|
||||
|
||||
try {
|
||||
|
||||
if(!(response.code() >= 200 && response.code() <= 206)) {
|
||||
// it is encourage to delete the tmp file when requested range not satisfiable.
|
||||
if (response.code() == 416) {
|
||||
File file = new File(path + downloader._tempFileNameSuffix);
|
||||
if (file.exists() && file.isFile()) {
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
downloader.onFinish(id, -2, response.message(), null);
|
||||
return;
|
||||
}
|
||||
|
||||
long total = response.body().contentLength();
|
||||
if (path.length() > 0 && !_resumingSupport.containsKey(host)) {
|
||||
if (total > 0) {
|
||||
_resumingSupport.put(host, true);
|
||||
} else {
|
||||
_resumingSupport.put(host, false);
|
||||
}
|
||||
}
|
||||
|
||||
long current = downloadStart;
|
||||
is = response.body().byteStream();
|
||||
|
||||
if (path.length() > 0) {
|
||||
if (downloadStart > 0) {
|
||||
fos = new FileOutputStream(tempFile, true);
|
||||
} else {
|
||||
fos = new FileOutputStream(tempFile, false);
|
||||
}
|
||||
|
||||
int len;
|
||||
while ((len = is.read(buf)) != -1) {
|
||||
current += len;
|
||||
fos.write(buf, 0, len);
|
||||
downloader.onProgress(id, len, current, total);
|
||||
}
|
||||
fos.flush();
|
||||
|
||||
String errStr = null;
|
||||
do {
|
||||
// rename temp file to final file, if final file exist, remove it
|
||||
if (finalFile.exists()) {
|
||||
if (finalFile.isDirectory()) {
|
||||
break;
|
||||
}
|
||||
if (!finalFile.delete()) {
|
||||
errStr = "Can't remove old file:" + finalFile.getAbsolutePath();
|
||||
break;
|
||||
}
|
||||
}
|
||||
tempFile.renameTo(finalFile);
|
||||
} while (false);
|
||||
|
||||
if (errStr == null) {
|
||||
downloader.onFinish(id, 0, null, null);
|
||||
downloader.runNextTaskIfExists();
|
||||
}
|
||||
else
|
||||
downloader.onFinish(id, 0, errStr, null);
|
||||
} else {
|
||||
// 非文件
|
||||
ByteArrayOutputStream buffer;
|
||||
if(total > 0) {
|
||||
buffer = new ByteArrayOutputStream((int) total);
|
||||
} else {
|
||||
buffer = new ByteArrayOutputStream(4096);
|
||||
}
|
||||
|
||||
int len;
|
||||
while ((len = is.read(buf)) != -1) {
|
||||
current += len;
|
||||
buffer.write(buf, 0, len);
|
||||
downloader.onProgress(id, len, current, total);
|
||||
}
|
||||
downloader.onFinish(id, 0, null, buffer.toByteArray());
|
||||
downloader.runNextTaskIfExists();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
downloader.onFinish(id, 0, e.toString(), null);
|
||||
} finally {
|
||||
try {
|
||||
if (is != null) {
|
||||
is.close();
|
||||
}
|
||||
if (fos != null) {
|
||||
fos.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.e("Cocos2dxDownloader", e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
} while (false);
|
||||
}
|
||||
};
|
||||
downloader.enqueueTask(taskRunnable);
|
||||
}
|
||||
|
||||
public static void abort(final Cocos2dxDownloader downloader, final int id) {
|
||||
Cocos2dxHelper.getActivity().runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Iterator iter = downloader._taskMap.entrySet().iterator();
|
||||
while (iter.hasNext()) {
|
||||
Map.Entry entry = (Map.Entry) iter.next();
|
||||
Object key = entry.getKey();
|
||||
Call task = (Call) entry.getValue();
|
||||
if (null != task && Integer.parseInt(key.toString()) == id) {
|
||||
task.cancel();
|
||||
downloader._taskMap.remove(id);
|
||||
downloader.runNextTaskIfExists();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void cancelAllRequests(final Cocos2dxDownloader downloader) {
|
||||
Cocos2dxHelper.getActivity().runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (Object o : downloader._taskMap.entrySet()) {
|
||||
Map.Entry entry = (Map.Entry) o;
|
||||
Call task = (Call) entry.getValue();
|
||||
if (null != task) {
|
||||
task.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private void enqueueTask(Runnable taskRunnable) {
|
||||
synchronized (_taskQueue) {
|
||||
if (_runningTaskCount < _countOfMaxProcessingTasks) {
|
||||
Cocos2dxHelper.getActivity().runOnUiThread(taskRunnable);
|
||||
_runningTaskCount++;
|
||||
} else {
|
||||
_taskQueue.add(taskRunnable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void runNextTaskIfExists() {
|
||||
synchronized (_taskQueue) {
|
||||
while (_runningTaskCount < _countOfMaxProcessingTasks &&
|
||||
Cocos2dxDownloader.this._taskQueue.size() > 0) {
|
||||
|
||||
Runnable taskRunnable = Cocos2dxDownloader.this._taskQueue.poll();
|
||||
Cocos2dxHelper.getActivity().runOnUiThread(taskRunnable);
|
||||
_runningTaskCount += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
native void nativeOnProgress(int id, int taskId, long dl, long dlnow, long dltotal);
|
||||
native void nativeOnFinish(int id, int taskId, int errCode, String errStr, final byte[] data);
|
||||
}
|
@@ -0,0 +1,479 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2010-2012 cocos2d-x.org
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
package org.cocos2dx.lib;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.ShapeDrawable;
|
||||
import android.graphics.drawable.StateListDrawable;
|
||||
import android.graphics.drawable.shapes.RoundRectShape;
|
||||
import android.text.Editable;
|
||||
import android.text.InputFilter;
|
||||
import android.text.InputType;
|
||||
import android.text.TextUtils;
|
||||
import android.text.TextWatcher;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.view.WindowManager;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
public class Cocos2dxEditBox {
|
||||
|
||||
// a color of dark green, was used for confirm button background
|
||||
private static final int DARK_GREEN = Color.parseColor("#1fa014");
|
||||
private static final int DARK_GREEN_PRESS = Color.parseColor("#008e26");
|
||||
|
||||
private static Cocos2dxEditBox sThis = null;
|
||||
private Cocos2dxEditText mEditText = null;
|
||||
private Button mButton = null;
|
||||
private String mButtonTitle = null;
|
||||
private boolean mConfirmHold = true;
|
||||
private Cocos2dxActivity mActivity = null;
|
||||
private RelativeLayout mButtonLayout = null;
|
||||
private RelativeLayout.LayoutParams mButtonParams;
|
||||
private int mEditTextID = 1;
|
||||
private int mButtonLayoutID = 2;
|
||||
|
||||
/***************************************************************************************
|
||||
Inner class.
|
||||
**************************************************************************************/
|
||||
class Cocos2dxEditText extends EditText {
|
||||
private final String TAG = "Cocos2dxEditBox";
|
||||
private boolean mIsMultiLine = false;
|
||||
private TextWatcher mTextWatcher = null;
|
||||
private Paint mPaint;
|
||||
private int mLineColor = DARK_GREEN;
|
||||
private float mLineWidth = 2f;
|
||||
private boolean keyboardVisible = false;
|
||||
private int mScreenHeight;
|
||||
private int mTopMargin = 0;
|
||||
private int mOrientation;
|
||||
|
||||
public Cocos2dxEditText(Cocos2dxActivity context){
|
||||
super(context);
|
||||
//remove focus border
|
||||
this.setBackground(null);
|
||||
this.setTextColor(Color.BLACK);
|
||||
mScreenHeight = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).
|
||||
getDefaultDisplay().getHeight();
|
||||
mPaint = new Paint();
|
||||
mPaint.setStrokeWidth(mLineWidth);
|
||||
mPaint.setStyle(Paint.Style.FILL);
|
||||
mPaint.setColor(mLineColor);
|
||||
mOrientation = this.getResources().getConfiguration().orientation;
|
||||
|
||||
mTextWatcher = new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
// Pass text to c++.
|
||||
Cocos2dxEditBox.this.onKeyboardInput(s.toString());
|
||||
}
|
||||
};
|
||||
registKeyboardVisible();
|
||||
}
|
||||
|
||||
/***************************************************************************************
|
||||
Override functions.
|
||||
**************************************************************************************/
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
// draw the underline
|
||||
int padB = this.getPaddingBottom();
|
||||
canvas.drawLine(getScrollX(), this.getHeight() - padB / 2 - mLineWidth,
|
||||
getScrollX() + this.getWidth(),
|
||||
this.getHeight() - padB / 2 - mLineWidth, mPaint);
|
||||
super.onDraw(canvas);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
int newOrientation = newConfig.orientation;
|
||||
if (mOrientation != newOrientation) {
|
||||
mOrientation = newOrientation;
|
||||
mTopMargin = 0; // clear top margin cache
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************************
|
||||
Public functions.
|
||||
**************************************************************************************/
|
||||
|
||||
public void show(String defaultValue, int maxLength, boolean isMultiline, boolean confirmHold, String confirmType, String inputType) {
|
||||
mIsMultiLine = isMultiline;
|
||||
this.setFilters(new InputFilter[]{new InputFilter.LengthFilter(maxLength) });
|
||||
this.setText(defaultValue);
|
||||
if (this.getText().length() >= defaultValue.length()) {
|
||||
this.setSelection(defaultValue.length());
|
||||
} else {
|
||||
this.setSelection(this.getText().length());
|
||||
}
|
||||
this.setConfirmType(confirmType);
|
||||
this.setInputType(inputType, mIsMultiLine);
|
||||
this.setVisibility(View.VISIBLE);
|
||||
|
||||
// Open soft keyboard manually. Should request focus to open soft keyboard.
|
||||
this.requestFocus();
|
||||
|
||||
this.addListeners();
|
||||
}
|
||||
|
||||
public void hide() {
|
||||
mEditText.setVisibility(View.INVISIBLE);
|
||||
this.removeListeners();
|
||||
}
|
||||
|
||||
/***************************************************************************************
|
||||
Private functions.
|
||||
**************************************************************************************/
|
||||
|
||||
private void setConfirmType(final String confirmType) {
|
||||
if (confirmType.contentEquals("done")) {
|
||||
this.setImeOptions(EditorInfo.IME_ACTION_DONE | EditorInfo.IME_FLAG_NO_EXTRACT_UI);
|
||||
mButtonTitle = mActivity.getResources().getString(R.string.done);
|
||||
} else if (confirmType.contentEquals("next")) {
|
||||
this.setImeOptions(EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NO_EXTRACT_UI);
|
||||
mButtonTitle = mActivity.getResources().getString(R.string.next);
|
||||
} else if (confirmType.contentEquals("search")) {
|
||||
this.setImeOptions(EditorInfo.IME_ACTION_SEARCH | EditorInfo.IME_FLAG_NO_EXTRACT_UI);
|
||||
mButtonTitle = mActivity.getResources().getString(R.string.search);
|
||||
} else if (confirmType.contentEquals("go")) {
|
||||
this.setImeOptions(EditorInfo.IME_ACTION_GO | EditorInfo.IME_FLAG_NO_EXTRACT_UI);
|
||||
mButtonTitle = mActivity.getResources().getString(R.string.go);
|
||||
} else if (confirmType.contentEquals("send")) {
|
||||
this.setImeOptions(EditorInfo.IME_ACTION_SEND | EditorInfo.IME_FLAG_NO_EXTRACT_UI);
|
||||
mButtonTitle = mActivity.getResources().getString(R.string.send);
|
||||
} else{
|
||||
mButtonTitle = null;
|
||||
Log.e(TAG, "unknown confirm type " + confirmType);
|
||||
}
|
||||
}
|
||||
|
||||
private void setInputType(final String inputType, boolean isMultiLine){
|
||||
if (inputType.contentEquals("text")) {
|
||||
if (isMultiLine)
|
||||
this.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE);
|
||||
else
|
||||
this.setInputType(InputType.TYPE_CLASS_TEXT);
|
||||
}
|
||||
else if (inputType.contentEquals("email"))
|
||||
this.setInputType(InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS);
|
||||
else if (inputType.contentEquals("number"))
|
||||
this.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL | InputType.TYPE_NUMBER_FLAG_SIGNED);
|
||||
else if (inputType.contentEquals("phone"))
|
||||
this.setInputType(InputType.TYPE_CLASS_PHONE);
|
||||
else if (inputType.contentEquals("password"))
|
||||
this.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
|
||||
else
|
||||
Log.e(TAG, "unknown input type " + inputType);
|
||||
}
|
||||
|
||||
private void addListeners() {
|
||||
|
||||
this.setOnEditorActionListener(new TextView.OnEditorActionListener() {
|
||||
@Override
|
||||
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
|
||||
if (! mIsMultiLine) {
|
||||
Cocos2dxEditBox.this.hide();
|
||||
}
|
||||
|
||||
return false; // pass on to other listeners.
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
this.addTextChangedListener(mTextWatcher);
|
||||
}
|
||||
|
||||
private void removeListeners() {
|
||||
this.setOnEditorActionListener(null);
|
||||
this.removeTextChangedListener(mTextWatcher);
|
||||
}
|
||||
|
||||
private void registKeyboardVisible() {
|
||||
getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
|
||||
@Override
|
||||
public void onGlobalLayout() {
|
||||
Rect r = new Rect();
|
||||
getWindowVisibleDisplayFrame(r);
|
||||
int heightDiff = getRootView().getHeight() - (r.bottom - r.top);
|
||||
// if more than a quarter of the screen, its probably a keyboard
|
||||
if (heightDiff > mScreenHeight/4) {
|
||||
if (!keyboardVisible) {
|
||||
keyboardVisible = true;
|
||||
}
|
||||
} else {
|
||||
if (keyboardVisible) {
|
||||
keyboardVisible = false;
|
||||
Cocos2dxEditBox.this.hide();
|
||||
}
|
||||
}
|
||||
|
||||
if (Cocos2dxEditText.this.mTopMargin == 0 && r.bottom != getRootView().getHeight()) {
|
||||
Cocos2dxEditText.this.setTopMargin(r.bottom);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setTopMargin(int topMargin) {
|
||||
mTopMargin = topMargin;
|
||||
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) mEditText.getLayoutParams();
|
||||
layoutParams.topMargin = mTopMargin - getHeight();
|
||||
setLayoutParams(layoutParams);
|
||||
requestLayout();
|
||||
}
|
||||
}
|
||||
|
||||
public Cocos2dxEditBox(Cocos2dxActivity context, FrameLayout layout) {
|
||||
Cocos2dxEditBox.sThis = this;
|
||||
mActivity = context;
|
||||
this.addItems(context, layout);
|
||||
}
|
||||
|
||||
/***************************************************************************************
|
||||
Public functions.
|
||||
**************************************************************************************/
|
||||
|
||||
// Invoked by surface view to send a complete message to CPP.
|
||||
public static void complete() {
|
||||
Cocos2dxEditBox.sThis.hide();
|
||||
}
|
||||
|
||||
/***************************************************************************************
|
||||
Private functions.
|
||||
**************************************************************************************/
|
||||
private void addItems(Cocos2dxActivity context, FrameLayout layout) {
|
||||
RelativeLayout myLayout = new RelativeLayout(context);
|
||||
myLayout.setFitsSystemWindows(true);
|
||||
this.addEditText(context, myLayout);
|
||||
this.addButton(context, myLayout);
|
||||
|
||||
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
|
||||
layout.addView(myLayout, layoutParams);
|
||||
|
||||
//FXI ME: Is it needed?
|
||||
// When touch area outside EditText and soft keyboard, then hide.
|
||||
// layout.setOnTouchListener(new View.OnTouchListener() {
|
||||
// @Override
|
||||
// public boolean onTouch(View v, MotionEvent event) {
|
||||
// Cocos2dxEditBox.this.hide();
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
// });
|
||||
}
|
||||
|
||||
private void addEditText(Cocos2dxActivity context, RelativeLayout layout) {
|
||||
mEditText = new Cocos2dxEditText(context);
|
||||
mEditText.setVisibility(View.INVISIBLE);
|
||||
mEditText.setBackgroundColor(Color.WHITE);
|
||||
mEditText.setId(mEditTextID);
|
||||
RelativeLayout.LayoutParams editParams = new RelativeLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
editParams.addRule(RelativeLayout.LEFT_OF, mButtonLayoutID);
|
||||
layout.addView(mEditText, editParams);
|
||||
}
|
||||
|
||||
private void addButton(Cocos2dxActivity context, RelativeLayout layout) {
|
||||
mButton = new Button(context);
|
||||
mButtonParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
mButton.setTextColor(Color.WHITE);
|
||||
mButton.setBackground(getRoundRectShape());
|
||||
mButtonLayout = new RelativeLayout(Cocos2dxHelper.getActivity());
|
||||
mButtonLayout.setVisibility(View.INVISIBLE);
|
||||
mButtonLayout.setBackgroundColor(Color.WHITE);
|
||||
RelativeLayout.LayoutParams buttonLayoutParams = new RelativeLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
buttonLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
|
||||
buttonLayoutParams.addRule(RelativeLayout.ALIGN_BOTTOM, mEditTextID);
|
||||
buttonLayoutParams.addRule(RelativeLayout.ALIGN_TOP, mEditTextID);
|
||||
mButtonLayout.addView(mButton, mButtonParams);
|
||||
mButtonLayout.setId(mButtonLayoutID);
|
||||
layout.addView(mButtonLayout, buttonLayoutParams);
|
||||
|
||||
mButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Cocos2dxEditBox.this.onKeyboardConfirm(mEditText.getText().toString());
|
||||
|
||||
if (!Cocos2dxEditBox.this.mConfirmHold)
|
||||
Cocos2dxEditBox.this.hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private Drawable getRoundRectShape() {
|
||||
int radius = 7;
|
||||
float[] outerRadii = new float[]{radius, radius, radius, radius, radius, radius, radius, radius};
|
||||
RoundRectShape roundRectShape = new RoundRectShape(outerRadii, null, null);
|
||||
ShapeDrawable shapeDrawableNormal = new ShapeDrawable();
|
||||
shapeDrawableNormal.setShape(roundRectShape);
|
||||
shapeDrawableNormal.getPaint().setStyle(Paint.Style.FILL);
|
||||
shapeDrawableNormal.getPaint().setColor(DARK_GREEN);
|
||||
ShapeDrawable shapeDrawablePress = new ShapeDrawable();
|
||||
shapeDrawablePress.setShape(roundRectShape);
|
||||
shapeDrawablePress.getPaint().setStyle(Paint.Style.FILL);
|
||||
shapeDrawablePress.getPaint().setColor(DARK_GREEN_PRESS);
|
||||
StateListDrawable drawable = new StateListDrawable();
|
||||
drawable.addState(new int[]{android.R.attr.state_pressed}, shapeDrawablePress);
|
||||
drawable.addState(new int[]{}, shapeDrawableNormal);
|
||||
return drawable;
|
||||
}
|
||||
|
||||
|
||||
private void hide() {
|
||||
Utils.hideVirtualButton();
|
||||
mEditText.hide();
|
||||
mButtonLayout.setVisibility(View.INVISIBLE);
|
||||
this.closeKeyboard();
|
||||
|
||||
mActivity.getGLSurfaceView().requestFocus();
|
||||
mActivity.getGLSurfaceView().setStopHandleTouchAndKeyEvents(false);
|
||||
}
|
||||
|
||||
private void show(String defaultValue, int maxLength, boolean isMultiline, boolean confirmHold, String confirmType, String inputType) {
|
||||
mConfirmHold = confirmHold;
|
||||
mEditText.show(defaultValue, maxLength, isMultiline, confirmHold, confirmType, inputType);
|
||||
int editPaddingBottom = mEditText.getPaddingBottom();
|
||||
int editPadding = mEditText.getPaddingTop();
|
||||
mEditText.setPadding(editPadding, editPadding, editPadding, editPaddingBottom);
|
||||
mButton.setText(mButtonTitle);
|
||||
if (TextUtils.isEmpty(mButtonTitle)) {
|
||||
mButton.setPadding(0, 0, 0, 0);
|
||||
mButtonParams.setMargins(0, 0, 0, 0);
|
||||
mButtonLayout.setVisibility(View.INVISIBLE);
|
||||
} else {
|
||||
int buttonTextPadding = mEditText.getPaddingBottom() / 2;
|
||||
mButton.setPadding(editPadding, buttonTextPadding, editPadding, buttonTextPadding);
|
||||
mButtonParams.setMargins(0, buttonTextPadding, 2, 0);
|
||||
mButtonLayout.setVisibility(View.VISIBLE);
|
||||
}
|
||||
mActivity.getGLSurfaceView().setStopHandleTouchAndKeyEvents(true);
|
||||
this.openKeyboard();
|
||||
}
|
||||
|
||||
private void closeKeyboard() {
|
||||
InputMethodManager imm = (InputMethodManager) Cocos2dxEditBox.this.mActivity.getSystemService(Cocos2dxEditBox.this.mActivity.INPUT_METHOD_SERVICE);
|
||||
imm.hideSoftInputFromWindow(mEditText.getWindowToken(), 0);
|
||||
|
||||
this.onKeyboardComplete(mEditText.getText().toString());
|
||||
}
|
||||
|
||||
private void openKeyboard() {
|
||||
InputMethodManager imm = (InputMethodManager) Cocos2dxEditBox.this.mActivity.getSystemService(Cocos2dxEditBox.this.mActivity.INPUT_METHOD_SERVICE);
|
||||
imm.showSoftInput(mEditText, InputMethodManager.SHOW_IMPLICIT);
|
||||
}
|
||||
|
||||
/***************************************************************************************
|
||||
Functions invoked by CPP.
|
||||
**************************************************************************************/
|
||||
|
||||
private static void showNative(String defaultValue, int maxLength, boolean isMultiline, boolean confirmHold, String confirmType, String inputType) {
|
||||
if (null != Cocos2dxEditBox.sThis) {
|
||||
Cocos2dxEditBox.sThis.mActivity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Cocos2dxEditBox.sThis.show(defaultValue, maxLength, isMultiline, confirmHold, confirmType, inputType);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static void hideNative() {
|
||||
if (null != Cocos2dxEditBox.sThis) {
|
||||
Cocos2dxEditBox.sThis.mActivity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Cocos2dxEditBox.sThis.hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************************
|
||||
Native functions invoked by UI.
|
||||
**************************************************************************************/
|
||||
private void onKeyboardInput(String text) {
|
||||
mActivity.runOnGLThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Cocos2dxEditBox.onKeyboardInputNative(text);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void onKeyboardComplete(String text) {
|
||||
mActivity.getGLSurfaceView().requestFocus();
|
||||
mActivity.getGLSurfaceView().setStopHandleTouchAndKeyEvents(false);
|
||||
mActivity.runOnGLThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Cocos2dxEditBox.onKeyboardCompleteNative(text);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void onKeyboardConfirm(String text) {
|
||||
mActivity.runOnGLThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Cocos2dxEditBox.onKeyboardConfirmNative(text);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static native void onKeyboardInputNative(String text);
|
||||
private static native void onKeyboardCompleteNative(String text);
|
||||
private static native void onKeyboardConfirmNative(String text);
|
||||
}
|
@@ -0,0 +1,343 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2010-2013 cocos2d-x.org
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
package org.cocos2dx.lib;
|
||||
|
||||
import android.content.Context;
|
||||
import android.opengl.GLSurfaceView;
|
||||
import android.os.Handler;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
public class Cocos2dxGLSurfaceView extends GLSurfaceView {
|
||||
// ===========================================================
|
||||
// Constants
|
||||
// ===========================================================
|
||||
|
||||
private static final String TAG = Cocos2dxGLSurfaceView.class.getSimpleName();
|
||||
|
||||
private final static int HANDLER_OPEN_IME_KEYBOARD = 2;
|
||||
private final static int HANDLER_CLOSE_IME_KEYBOARD = 3;
|
||||
|
||||
// ===========================================================
|
||||
// Fields
|
||||
// ===========================================================
|
||||
|
||||
// REFINE: Static handler -> Potential leak!
|
||||
private static Handler sHandler;
|
||||
private static Cocos2dxGLSurfaceView mCocos2dxGLSurfaceView;
|
||||
|
||||
private Cocos2dxRenderer mCocos2dxRenderer;
|
||||
private boolean mStopHandleTouchAndKeyEvents = false;
|
||||
|
||||
public static native void nativeOnSizeChanged(int width, int height);
|
||||
|
||||
// ===========================================================
|
||||
// Constructors
|
||||
// ===========================================================
|
||||
|
||||
public Cocos2dxGLSurfaceView(final Context context) {
|
||||
super(context);
|
||||
|
||||
this.initView();
|
||||
}
|
||||
|
||||
public Cocos2dxGLSurfaceView(final Context context, final AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
|
||||
this.initView();
|
||||
}
|
||||
|
||||
protected void initView() {
|
||||
this.setEGLContextClientVersion(2);
|
||||
this.setFocusableInTouchMode(true);
|
||||
|
||||
Cocos2dxGLSurfaceView.mCocos2dxGLSurfaceView = this;
|
||||
}
|
||||
|
||||
// ===========================================================
|
||||
// Getter & Setter
|
||||
// ===========================================================
|
||||
|
||||
|
||||
public static Cocos2dxGLSurfaceView getInstance() {
|
||||
return mCocos2dxGLSurfaceView;
|
||||
}
|
||||
|
||||
public static void queueAccelerometer(final float x, final float y, final float z, final long timestamp) {
|
||||
mCocos2dxGLSurfaceView.queueEvent(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Cocos2dxAccelerometer.onSensorChanged(x, y, z, timestamp);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void setCocos2dxRenderer(final Cocos2dxRenderer renderer) {
|
||||
this.mCocos2dxRenderer = renderer;
|
||||
this.setRenderer(this.mCocos2dxRenderer);
|
||||
}
|
||||
|
||||
private String getContentText() {
|
||||
return this.mCocos2dxRenderer.getContentText();
|
||||
}
|
||||
|
||||
// ===========================================================
|
||||
// Methods for/from SuperClass/Interfaces
|
||||
// ===========================================================
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
this.setRenderMode(RENDERMODE_CONTINUOUSLY);
|
||||
this.queueEvent(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Cocos2dxGLSurfaceView.this.mCocos2dxRenderer.handleOnResume();
|
||||
}
|
||||
});
|
||||
mCocos2dxRenderer.setPauseInMainThread(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
this.queueEvent(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Cocos2dxGLSurfaceView.this.mCocos2dxRenderer.handleOnPause();
|
||||
}
|
||||
});
|
||||
this.setRenderMode(RENDERMODE_WHEN_DIRTY);
|
||||
mCocos2dxRenderer.setPauseInMainThread(true);
|
||||
//super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(final MotionEvent pMotionEvent) {
|
||||
// these data are used in ACTION_MOVE and ACTION_CANCEL
|
||||
final int pointerNumber = pMotionEvent.getPointerCount();
|
||||
final int[] ids = new int[pointerNumber];
|
||||
final float[] xs = new float[pointerNumber];
|
||||
final float[] ys = new float[pointerNumber];
|
||||
|
||||
for (int i = 0; i < pointerNumber; i++) {
|
||||
ids[i] = pMotionEvent.getPointerId(i);
|
||||
xs[i] = pMotionEvent.getX(i);
|
||||
ys[i] = pMotionEvent.getY(i);
|
||||
}
|
||||
|
||||
switch (pMotionEvent.getAction() & MotionEvent.ACTION_MASK) {
|
||||
case MotionEvent.ACTION_POINTER_DOWN:
|
||||
if (mStopHandleTouchAndKeyEvents) {
|
||||
Cocos2dxEditBox.complete();
|
||||
return true;
|
||||
}
|
||||
|
||||
final int indexPointerDown = pMotionEvent.getAction() >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
|
||||
final int idPointerDown = pMotionEvent.getPointerId(indexPointerDown);
|
||||
final float xPointerDown = pMotionEvent.getX(indexPointerDown);
|
||||
final float yPointerDown = pMotionEvent.getY(indexPointerDown);
|
||||
|
||||
this.queueEvent(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Cocos2dxGLSurfaceView.this.mCocos2dxRenderer.handleActionDown(idPointerDown, xPointerDown, yPointerDown);
|
||||
}
|
||||
});
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
if (mStopHandleTouchAndKeyEvents) {
|
||||
Cocos2dxEditBox.complete();
|
||||
return true;
|
||||
}
|
||||
|
||||
// there are only one finger on the screen
|
||||
final int idDown = pMotionEvent.getPointerId(0);
|
||||
final float xDown = xs[0];
|
||||
final float yDown = ys[0];
|
||||
|
||||
this.queueEvent(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Cocos2dxGLSurfaceView.this.mCocos2dxRenderer.handleActionDown(idDown, xDown, yDown);
|
||||
}
|
||||
});
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
this.queueEvent(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Cocos2dxGLSurfaceView.this.mCocos2dxRenderer.handleActionMove(ids, xs, ys);
|
||||
}
|
||||
});
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
final int indexPointUp = pMotionEvent.getAction() >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
|
||||
final int idPointerUp = pMotionEvent.getPointerId(indexPointUp);
|
||||
final float xPointerUp = pMotionEvent.getX(indexPointUp);
|
||||
final float yPointerUp = pMotionEvent.getY(indexPointUp);
|
||||
|
||||
this.queueEvent(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Cocos2dxGLSurfaceView.this.mCocos2dxRenderer.handleActionUp(idPointerUp, xPointerUp, yPointerUp);
|
||||
}
|
||||
});
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_UP:
|
||||
// there are only one finger on the screen
|
||||
final int idUp = pMotionEvent.getPointerId(0);
|
||||
final float xUp = xs[0];
|
||||
final float yUp = ys[0];
|
||||
|
||||
this.queueEvent(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Cocos2dxGLSurfaceView.this.mCocos2dxRenderer.handleActionUp(idUp, xUp, yUp);
|
||||
}
|
||||
});
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
this.queueEvent(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Cocos2dxGLSurfaceView.this.mCocos2dxRenderer.handleActionCancel(ids, xs, ys);
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
if (BuildConfig.DEBUG) {
|
||||
Cocos2dxGLSurfaceView.dumpMotionEvent(pMotionEvent);
|
||||
}
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called before Cocos2dxRenderer.nativeInit(), so the
|
||||
* width and height is correct.
|
||||
*/
|
||||
@Override
|
||||
protected void onSizeChanged(final int pNewSurfaceWidth, final int pNewSurfaceHeight, final int pOldSurfaceWidth, final int pOldSurfaceHeight) {
|
||||
if(!this.isInEditMode()) {
|
||||
this.mCocos2dxRenderer.setScreenWidthAndHeight(pNewSurfaceWidth, pNewSurfaceHeight);
|
||||
nativeOnSizeChanged(pNewSurfaceWidth, pNewSurfaceHeight);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyDown(final int pKeyCode, final KeyEvent pKeyEvent) {
|
||||
switch (pKeyCode) {
|
||||
case KeyEvent.KEYCODE_BACK:
|
||||
Cocos2dxVideoHelper.mVideoHandler.sendEmptyMessage(Cocos2dxVideoHelper.KeyEventBack);
|
||||
case KeyEvent.KEYCODE_MENU:
|
||||
case KeyEvent.KEYCODE_DPAD_LEFT:
|
||||
case KeyEvent.KEYCODE_DPAD_RIGHT:
|
||||
case KeyEvent.KEYCODE_DPAD_UP:
|
||||
case KeyEvent.KEYCODE_DPAD_DOWN:
|
||||
case KeyEvent.KEYCODE_ENTER:
|
||||
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
|
||||
case KeyEvent.KEYCODE_DPAD_CENTER:
|
||||
this.queueEvent(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Cocos2dxGLSurfaceView.this.mCocos2dxRenderer.handleKeyDown(pKeyCode);
|
||||
}
|
||||
});
|
||||
return true;
|
||||
default:
|
||||
return super.onKeyDown(pKeyCode, pKeyEvent);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyUp(final int keyCode, KeyEvent event) {
|
||||
switch (keyCode) {
|
||||
case KeyEvent.KEYCODE_BACK:
|
||||
case KeyEvent.KEYCODE_MENU:
|
||||
case KeyEvent.KEYCODE_DPAD_LEFT:
|
||||
case KeyEvent.KEYCODE_DPAD_RIGHT:
|
||||
case KeyEvent.KEYCODE_DPAD_UP:
|
||||
case KeyEvent.KEYCODE_DPAD_DOWN:
|
||||
case KeyEvent.KEYCODE_ENTER:
|
||||
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
|
||||
case KeyEvent.KEYCODE_DPAD_CENTER:
|
||||
this.queueEvent(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Cocos2dxGLSurfaceView.this.mCocos2dxRenderer.handleKeyUp(keyCode);
|
||||
}
|
||||
});
|
||||
return true;
|
||||
default:
|
||||
return super.onKeyUp(keyCode, event);
|
||||
}
|
||||
}
|
||||
|
||||
// ===========================================================
|
||||
// Methods
|
||||
// ===========================================================
|
||||
|
||||
public void setStopHandleTouchAndKeyEvents(boolean value) {
|
||||
mStopHandleTouchAndKeyEvents = value;
|
||||
}
|
||||
|
||||
// ===========================================================
|
||||
// Inner and Anonymous Classes
|
||||
// ===========================================================
|
||||
|
||||
private static void dumpMotionEvent(final MotionEvent event) {
|
||||
final String names[] = { "DOWN", "UP", "MOVE", "CANCEL", "OUTSIDE", "POINTER_DOWN", "POINTER_UP", "7?", "8?", "9?" };
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
final int action = event.getAction();
|
||||
final int actionCode = action & MotionEvent.ACTION_MASK;
|
||||
sb.append("event ACTION_").append(names[actionCode]);
|
||||
if (actionCode == MotionEvent.ACTION_POINTER_DOWN || actionCode == MotionEvent.ACTION_POINTER_UP) {
|
||||
sb.append("(pid ").append(action >> MotionEvent.ACTION_POINTER_INDEX_SHIFT);
|
||||
sb.append(")");
|
||||
}
|
||||
sb.append("[");
|
||||
for (int i = 0; i < event.getPointerCount(); i++) {
|
||||
sb.append("#").append(i);
|
||||
sb.append("(pid ").append(event.getPointerId(i));
|
||||
sb.append(")=").append((int) event.getX(i));
|
||||
sb.append(",").append((int) event.getY(i));
|
||||
if (i + 1 < event.getPointerCount()) {
|
||||
sb.append(";");
|
||||
}
|
||||
}
|
||||
sb.append("]");
|
||||
Log.d(Cocos2dxGLSurfaceView.TAG, sb.toString());
|
||||
}
|
||||
}
|
@@ -0,0 +1,104 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2010-2013 cocos2d-x.org
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
package org.cocos2dx.lib;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
public class Cocos2dxHandler extends Handler {
|
||||
// ===========================================================
|
||||
// Constants
|
||||
// ===========================================================
|
||||
public final static int HANDLER_SHOW_DIALOG = 1;
|
||||
|
||||
// ===========================================================
|
||||
// Fields
|
||||
// ===========================================================
|
||||
private WeakReference<Cocos2dxActivity> mActivity;
|
||||
|
||||
// ===========================================================
|
||||
// Constructors
|
||||
// ===========================================================
|
||||
public Cocos2dxHandler(Cocos2dxActivity activity) {
|
||||
this.mActivity = new WeakReference<Cocos2dxActivity>(activity);
|
||||
}
|
||||
|
||||
// ===========================================================
|
||||
// Getter & Setter
|
||||
// ===========================================================
|
||||
|
||||
// ===========================================================
|
||||
// Methods for/from SuperClass/Interfaces
|
||||
// ===========================================================
|
||||
|
||||
// ===========================================================
|
||||
// Methods
|
||||
// ===========================================================
|
||||
|
||||
public void handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case Cocos2dxHandler.HANDLER_SHOW_DIALOG:
|
||||
showDialog(msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void showDialog(Message msg) {
|
||||
Cocos2dxActivity theActivity = this.mActivity.get();
|
||||
DialogMessage dialogMessage = (DialogMessage)msg.obj;
|
||||
new AlertDialog.Builder(theActivity)
|
||||
.setTitle(dialogMessage.title)
|
||||
.setMessage(dialogMessage.message)
|
||||
.setPositiveButton("Ok",
|
||||
new DialogInterface.OnClickListener() {
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
// REFINE: Auto-generated method stub
|
||||
|
||||
}
|
||||
}).create().show();
|
||||
}
|
||||
|
||||
// ===========================================================
|
||||
// Inner and Anonymous Classes
|
||||
// ===========================================================
|
||||
|
||||
public static class DialogMessage {
|
||||
public String title;
|
||||
public String message;
|
||||
|
||||
public DialogMessage(String title, String message) {
|
||||
this.title = title;
|
||||
this.message = message;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,664 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2010-2012 cocos2d-x.org
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
package org.cocos2dx.lib;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.res.AssetFileDescriptor;
|
||||
import android.content.res.AssetManager;
|
||||
import android.media.AudioManager;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.net.Uri;
|
||||
import android.os.BatteryManager;
|
||||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.Vibrator;
|
||||
import android.preference.PreferenceManager.OnActivityResultListener;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.view.Display;
|
||||
import android.view.Surface;
|
||||
import android.view.WindowInsets;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import com.android.vending.expansion.zipfile.APKExpansionSupport;
|
||||
import com.android.vending.expansion.zipfile.ZipResourceFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
public class Cocos2dxHelper {
|
||||
// ===========================================================
|
||||
// Constants
|
||||
// ===========================================================
|
||||
private static final String PREFS_NAME = "Cocos2dxPrefsFile";
|
||||
private static final int RUNNABLES_PER_FRAME = 5;
|
||||
private static final String TAG = Cocos2dxHelper.class.getSimpleName();
|
||||
|
||||
// ===========================================================
|
||||
// Fields
|
||||
// ===========================================================
|
||||
|
||||
private static AssetManager sAssetManager;
|
||||
private static Cocos2dxAccelerometer sCocos2dxAccelerometer;
|
||||
private static boolean sAccelerometerEnabled;
|
||||
private static boolean sCompassEnabled;
|
||||
private static boolean sActivityVisible;
|
||||
private static String sPackageName;
|
||||
private static String sFileDirectory;
|
||||
private static Activity sActivity = null;
|
||||
private static Cocos2dxHelperListener sCocos2dxHelperListener;
|
||||
private static Set<OnActivityResultListener> onActivityResultListeners = new LinkedHashSet<OnActivityResultListener>();
|
||||
private static Vibrator sVibrateService = null;
|
||||
|
||||
// The absolute path to the OBB if it exists, else the absolute path to the APK.
|
||||
private static String sAssetsPath = "";
|
||||
|
||||
// The OBB file
|
||||
private static ZipResourceFile sOBBFile = null;
|
||||
|
||||
/**
|
||||
* Battery receiver to getting battery level.
|
||||
*/
|
||||
static class BatteryReceiver extends BroadcastReceiver {
|
||||
public float sBatteryLevel = 0.0f;
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
setBatteryLevelByIntent(intent);
|
||||
}
|
||||
|
||||
public void setBatteryLevelByIntent(Intent intent) {
|
||||
if (null != intent) {
|
||||
int current = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
|
||||
int total = intent.getIntExtra(BatteryManager.EXTRA_SCALE, 1);
|
||||
float level = current * 1.0f / total;
|
||||
// clamp to 0~1
|
||||
sBatteryLevel = Math.min(Math.max(level, 0.0f), 1.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static BatteryReceiver sBatteryReceiver = new BatteryReceiver();
|
||||
|
||||
static void registerBatteryLevelReceiver(Context context) {
|
||||
Intent intent = context.registerReceiver(sBatteryReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
|
||||
sBatteryReceiver.setBatteryLevelByIntent(intent);
|
||||
}
|
||||
|
||||
static void unregisterBatteryLevelReceiver(Context context) {
|
||||
context.unregisterReceiver(sBatteryReceiver);
|
||||
}
|
||||
|
||||
public static float getBatteryLevel() {
|
||||
return sBatteryReceiver.sBatteryLevel;
|
||||
}
|
||||
|
||||
public static final int NETWORK_TYPE_NONE = 0;
|
||||
public static final int NETWORK_TYPE_LAN = 1;
|
||||
public static final int NETWORK_TYPE_WWAN = 2;
|
||||
|
||||
public static int getNetworkType() {
|
||||
int status = NETWORK_TYPE_NONE;
|
||||
NetworkInfo networkInfo;
|
||||
try {
|
||||
ConnectivityManager connMgr = (ConnectivityManager) sActivity.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
networkInfo = connMgr.getActiveNetworkInfo();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return status;
|
||||
}
|
||||
if (networkInfo == null) {
|
||||
return status;
|
||||
}
|
||||
int nType = networkInfo.getType();
|
||||
if (nType == ConnectivityManager.TYPE_MOBILE) {
|
||||
status = NETWORK_TYPE_WWAN;
|
||||
} else if (nType == ConnectivityManager.TYPE_WIFI) {
|
||||
status = NETWORK_TYPE_LAN;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
// ===========================================================
|
||||
// Constructors
|
||||
// ===========================================================
|
||||
|
||||
public static void runOnGLThread(final Runnable r) {
|
||||
((Cocos2dxActivity)sActivity).runOnGLThread(r);
|
||||
}
|
||||
|
||||
private static boolean sInited = false;
|
||||
public static void init(final Activity activity) {
|
||||
sActivity = activity;
|
||||
Cocos2dxHelper.sCocos2dxHelperListener = (Cocos2dxHelperListener)activity;
|
||||
if (!sInited) {
|
||||
|
||||
PackageManager pm = activity.getPackageManager();
|
||||
boolean isSupportLowLatency = pm.hasSystemFeature(PackageManager.FEATURE_AUDIO_LOW_LATENCY);
|
||||
|
||||
Log.d(TAG, "isSupportLowLatency:" + isSupportLowLatency);
|
||||
|
||||
int sampleRate = 44100;
|
||||
int bufferSizeInFrames = 192;
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 17) {
|
||||
AudioManager am = (AudioManager) activity.getSystemService(Context.AUDIO_SERVICE);
|
||||
// use reflection to remove dependence of API 17 when compiling
|
||||
|
||||
// AudioManager.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE);
|
||||
final Class audioManagerClass = AudioManager.class;
|
||||
Object[] parameters = new Object[]{Cocos2dxReflectionHelper.<String>getConstantValue(audioManagerClass, "PROPERTY_OUTPUT_SAMPLE_RATE")};
|
||||
final String strSampleRate = Cocos2dxReflectionHelper.<String>invokeInstanceMethod(am, "getProperty", new Class[]{String.class}, parameters);
|
||||
|
||||
// AudioManager.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER);
|
||||
parameters = new Object[]{Cocos2dxReflectionHelper.<String>getConstantValue(audioManagerClass, "PROPERTY_OUTPUT_FRAMES_PER_BUFFER")};
|
||||
final String strBufferSizeInFrames = Cocos2dxReflectionHelper.<String>invokeInstanceMethod(am, "getProperty", new Class[]{String.class}, parameters);
|
||||
|
||||
sampleRate = Integer.parseInt(strSampleRate);
|
||||
bufferSizeInFrames = Integer.parseInt(strBufferSizeInFrames);
|
||||
|
||||
Log.d(TAG, "sampleRate: " + sampleRate + ", framesPerBuffer: " + bufferSizeInFrames);
|
||||
} else {
|
||||
Log.d(TAG, "android version is lower than 17");
|
||||
}
|
||||
|
||||
nativeSetAudioDeviceInfo(isSupportLowLatency, sampleRate, bufferSizeInFrames);
|
||||
|
||||
final ApplicationInfo applicationInfo = activity.getApplicationInfo();
|
||||
|
||||
Cocos2dxHelper.sPackageName = applicationInfo.packageName;
|
||||
Cocos2dxHelper.sFileDirectory = activity.getFilesDir().getAbsolutePath();
|
||||
|
||||
Cocos2dxHelper.nativeSetApkPath(Cocos2dxHelper.getAssetsPath());
|
||||
|
||||
Cocos2dxHelper.sCocos2dxAccelerometer = new Cocos2dxAccelerometer(activity);
|
||||
Cocos2dxHelper.sAssetManager = activity.getAssets();
|
||||
Cocos2dxHelper.nativeSetContext((Context)activity, Cocos2dxHelper.sAssetManager);
|
||||
Cocos2dxHelper.sVibrateService = (Vibrator)activity.getSystemService(Context.VIBRATOR_SERVICE);
|
||||
|
||||
sInited = true;
|
||||
|
||||
int versionCode = 1;
|
||||
try {
|
||||
versionCode = Cocos2dxActivity.getContext().getPackageManager().getPackageInfo(Cocos2dxHelper.getPackageName(), 0).versionCode;
|
||||
} catch (NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
try {
|
||||
Cocos2dxHelper.sOBBFile = APKExpansionSupport.getAPKExpansionZipFile(Cocos2dxActivity.getContext(), versionCode, 0);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This function returns the absolute path to the OBB if it exists,
|
||||
// else it returns the absolute path to the APK.
|
||||
public static String getAssetsPath()
|
||||
{
|
||||
if (Cocos2dxHelper.sAssetsPath == "") {
|
||||
int versionCode = 1;
|
||||
try {
|
||||
versionCode = Cocos2dxHelper.sActivity.getPackageManager().getPackageInfo(Cocos2dxHelper.sPackageName, 0).versionCode;
|
||||
} catch (NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
String pathToOBB = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Android/obb/" + Cocos2dxHelper.sPackageName + "/main." + versionCode + "." + Cocos2dxHelper.sPackageName + ".obb";
|
||||
File obbFile = new File(pathToOBB);
|
||||
if (obbFile.exists())
|
||||
Cocos2dxHelper.sAssetsPath = pathToOBB;
|
||||
else
|
||||
Cocos2dxHelper.sAssetsPath = Cocos2dxHelper.sActivity.getApplicationInfo().sourceDir;
|
||||
}
|
||||
|
||||
return Cocos2dxHelper.sAssetsPath;
|
||||
}
|
||||
|
||||
public static ZipResourceFile getObbFile()
|
||||
{
|
||||
return Cocos2dxHelper.sOBBFile;
|
||||
}
|
||||
|
||||
public static Activity getActivity() {
|
||||
return sActivity;
|
||||
}
|
||||
|
||||
public static void addOnActivityResultListener(OnActivityResultListener listener) {
|
||||
onActivityResultListeners.add(listener);
|
||||
}
|
||||
|
||||
public static Set<OnActivityResultListener> getOnActivityResultListeners() {
|
||||
return onActivityResultListeners;
|
||||
}
|
||||
|
||||
public static boolean isActivityVisible(){
|
||||
return sActivityVisible;
|
||||
}
|
||||
|
||||
// ===========================================================
|
||||
// Getter & Setter
|
||||
// ===========================================================
|
||||
|
||||
// ===========================================================
|
||||
// Methods for/from SuperClass/Interfaces
|
||||
// ===========================================================
|
||||
|
||||
// ===========================================================
|
||||
// Methods
|
||||
// ===========================================================
|
||||
|
||||
private static native void nativeSetApkPath(final String pApkPath);
|
||||
|
||||
private static native void nativeSetEditTextDialogResult(final byte[] pBytes);
|
||||
|
||||
private static native void nativeSetContext(final Context pContext, final AssetManager pAssetManager);
|
||||
|
||||
private static native void nativeSetAudioDeviceInfo(boolean isSupportLowLatency, int deviceSampleRate, int audioBufferSizeInFames);
|
||||
|
||||
public static String getPackageName() {
|
||||
return Cocos2dxHelper.sPackageName;
|
||||
}
|
||||
public static String getWritablePath() {
|
||||
return Cocos2dxHelper.sFileDirectory;
|
||||
}
|
||||
|
||||
public static String getCurrentLanguage() {
|
||||
return Locale.getDefault().getLanguage();
|
||||
}
|
||||
|
||||
public static String getCurrentLanguageCode() {
|
||||
return Locale.getDefault().toString();
|
||||
}
|
||||
|
||||
public static String getDeviceModel(){
|
||||
return Build.MODEL;
|
||||
}
|
||||
|
||||
public static AssetManager getAssetManager() {
|
||||
return Cocos2dxHelper.sAssetManager;
|
||||
}
|
||||
|
||||
public static void enableAccelerometer() {
|
||||
Cocos2dxHelper.sAccelerometerEnabled = true;
|
||||
Cocos2dxHelper.sCocos2dxAccelerometer.enable();
|
||||
}
|
||||
|
||||
public static void setAccelerometerInterval(float interval) {
|
||||
Cocos2dxHelper.sCocos2dxAccelerometer.setInterval(interval);
|
||||
}
|
||||
|
||||
public static void disableAccelerometer() {
|
||||
Cocos2dxHelper.sAccelerometerEnabled = false;
|
||||
Cocos2dxHelper.sCocos2dxAccelerometer.disable();
|
||||
}
|
||||
|
||||
public static void setKeepScreenOn(boolean value) {
|
||||
((Cocos2dxActivity)sActivity).setKeepScreenOn(value);
|
||||
}
|
||||
|
||||
public static void vibrate(float duration) {
|
||||
try {
|
||||
if (sVibrateService != null && sVibrateService.hasVibrator()) {
|
||||
if (android.os.Build.VERSION.SDK_INT >= 26) {
|
||||
Class<?> vibrationEffectClass = Class.forName("android.os.VibrationEffect");
|
||||
if(vibrationEffectClass != null) {
|
||||
final int DEFAULT_AMPLITUDE = Cocos2dxReflectionHelper.<Integer>getConstantValue(vibrationEffectClass,
|
||||
"DEFAULT_AMPLITUDE");
|
||||
//VibrationEffect.createOneShot(long milliseconds, int amplitude)
|
||||
final Method method = vibrationEffectClass.getMethod("createOneShot",
|
||||
new Class[]{Long.TYPE, Integer.TYPE});
|
||||
Class<?> type = method.getReturnType();
|
||||
|
||||
Object effect = method.invoke(vibrationEffectClass,
|
||||
new Object[]{(long) (duration * 1000), DEFAULT_AMPLITUDE});
|
||||
//sVibrateService.vibrate(VibrationEffect effect);
|
||||
Cocos2dxReflectionHelper.invokeInstanceMethod(sVibrateService,"vibrate",
|
||||
new Class[]{type}, new Object[]{(effect)});
|
||||
}
|
||||
} else {
|
||||
sVibrateService.vibrate((long) (duration * 1000));
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static String getVersion() {
|
||||
try {
|
||||
String version = Cocos2dxActivity.getContext().getPackageManager().getPackageInfo(Cocos2dxActivity.getContext().getPackageName(), 0).versionName;
|
||||
return version;
|
||||
} catch(Exception e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean openURL(String url) {
|
||||
boolean ret = false;
|
||||
try {
|
||||
Intent i = new Intent(Intent.ACTION_VIEW);
|
||||
i.setData(Uri.parse(url));
|
||||
sActivity.startActivity(i);
|
||||
ret = true;
|
||||
} catch (Exception e) {
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 复制文本到剪切板
|
||||
public static void copyTextToClipboard(final String text){
|
||||
sActivity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
ClipboardManager myClipboard = (ClipboardManager)sActivity.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
ClipData myClip = ClipData.newPlainText("text", text);
|
||||
myClipboard.setPrimaryClip(myClip);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static long[] getObbAssetFileDescriptor(final String path) {
|
||||
long[] array = new long[3];
|
||||
if (Cocos2dxHelper.sOBBFile != null) {
|
||||
AssetFileDescriptor descriptor = Cocos2dxHelper.sOBBFile.getAssetFileDescriptor(path);
|
||||
if (descriptor != null) {
|
||||
try {
|
||||
ParcelFileDescriptor parcel = descriptor.getParcelFileDescriptor();
|
||||
Method method = parcel.getClass().getMethod("getFd", new Class[] {});
|
||||
array[0] = (Integer)method.invoke(parcel);
|
||||
array[1] = descriptor.getStartOffset();
|
||||
array[2] = descriptor.getLength();
|
||||
} catch (NoSuchMethodException e) {
|
||||
Log.e(Cocos2dxHelper.TAG, "Accessing file descriptor directly from the OBB is only supported from Android 3.1 (API level 12) and above.");
|
||||
} catch (IllegalAccessException e) {
|
||||
Log.e(Cocos2dxHelper.TAG, e.toString());
|
||||
} catch (InvocationTargetException e) {
|
||||
Log.e(Cocos2dxHelper.TAG, e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
public static void endApplication() {
|
||||
if (sActivity != null)
|
||||
sActivity.finish();
|
||||
}
|
||||
|
||||
public static void onResume() {
|
||||
sActivityVisible = true;
|
||||
if (Cocos2dxHelper.sAccelerometerEnabled) {
|
||||
Cocos2dxHelper.sCocos2dxAccelerometer.enable();
|
||||
}
|
||||
}
|
||||
|
||||
public static void onPause() {
|
||||
sActivityVisible = false;
|
||||
if (Cocos2dxHelper.sAccelerometerEnabled) {
|
||||
Cocos2dxHelper.sCocos2dxAccelerometer.disable();
|
||||
}
|
||||
}
|
||||
|
||||
public static void onEnterBackground() {
|
||||
|
||||
}
|
||||
|
||||
public static void onEnterForeground() {
|
||||
|
||||
}
|
||||
|
||||
public static void terminateProcess() {
|
||||
android.os.Process.killProcess(android.os.Process.myPid());
|
||||
}
|
||||
|
||||
private static void showDialog(final String pTitle, final String pMessage) {
|
||||
Cocos2dxHelper.sCocos2dxHelperListener.showDialog(pTitle, pMessage);
|
||||
}
|
||||
|
||||
public static void setEditTextDialogResult(final String pResult) {
|
||||
try {
|
||||
final byte[] bytesUTF8 = pResult.getBytes("UTF8");
|
||||
|
||||
Cocos2dxHelper.sCocos2dxHelperListener.runOnGLThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Cocos2dxHelper.nativeSetEditTextDialogResult(bytesUTF8);
|
||||
}
|
||||
});
|
||||
} catch (UnsupportedEncodingException pUnsupportedEncodingException) {
|
||||
/* Nothing. */
|
||||
}
|
||||
}
|
||||
|
||||
private static int displayMetricsToDPI(DisplayMetrics metrics)
|
||||
{
|
||||
if(metrics.xdpi != metrics.ydpi) {
|
||||
Log.w(Cocos2dxHelper.TAG, "xdpi != ydpi, use (xdpi + ydpi)/2 instead.");
|
||||
return (int) ((metrics.xdpi + metrics.ydpi) / 2.0);
|
||||
} else {
|
||||
return (int)metrics.xdpi;
|
||||
}
|
||||
}
|
||||
|
||||
public static int getDPI()
|
||||
{
|
||||
if (sActivity != null)
|
||||
{
|
||||
DisplayMetrics metrics = new DisplayMetrics();
|
||||
WindowManager wm = sActivity.getWindowManager();
|
||||
if (wm != null)
|
||||
{
|
||||
Display d = wm.getDefaultDisplay();
|
||||
if (d != null)
|
||||
{
|
||||
try {
|
||||
Method getRealMetrics = d.getClass().getMethod("getRealMetrics", metrics.getClass());
|
||||
getRealMetrics.invoke(d, metrics);
|
||||
return displayMetricsToDPI(metrics);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
d.getMetrics(metrics);
|
||||
return displayMetricsToDPI(metrics);
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static byte[] conversionEncoding(byte[] text, String fromCharset,String newCharset)
|
||||
{
|
||||
try {
|
||||
String str = new String(text,fromCharset);
|
||||
return str.getBytes(newCharset);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void setGameInfoDebugViewText(int index, String text) {
|
||||
if (sOnGameInfoUpdatedListener != null) {
|
||||
if (index == 0) {
|
||||
sOnGameInfoUpdatedListener.onGameInfoUpdated_0(text);
|
||||
}
|
||||
else if (index == 1) {
|
||||
sOnGameInfoUpdatedListener.onGameInfoUpdated_1(text);
|
||||
}
|
||||
else if (index == 2) {
|
||||
sOnGameInfoUpdatedListener.onGameInfoUpdated_2(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void setJSBInvocationCount(int count) {
|
||||
if (sOnGameInfoUpdatedListener != null) {
|
||||
sOnGameInfoUpdatedListener.onJSBInvocationCountUpdated(count);
|
||||
}
|
||||
}
|
||||
|
||||
private static void openDebugView() {
|
||||
if (sOnGameInfoUpdatedListener != null) {
|
||||
sOnGameInfoUpdatedListener.onOpenDebugView();
|
||||
}
|
||||
}
|
||||
|
||||
private static void disableBatchGLCommandsToNative() {
|
||||
if (sOnGameInfoUpdatedListener != null) {
|
||||
sOnGameInfoUpdatedListener.onDisableBatchGLCommandsToNative();
|
||||
}
|
||||
}
|
||||
|
||||
public interface OnGameInfoUpdatedListener {
|
||||
void onFPSUpdated(float fps);
|
||||
void onJSBInvocationCountUpdated(int count);
|
||||
void onOpenDebugView();
|
||||
void onDisableBatchGLCommandsToNative();
|
||||
void onGameInfoUpdated_0(String text);
|
||||
void onGameInfoUpdated_1(String text);
|
||||
void onGameInfoUpdated_2(String text);
|
||||
}
|
||||
|
||||
private static OnGameInfoUpdatedListener sOnGameInfoUpdatedListener;
|
||||
|
||||
public static void setOnGameInfoUpdatedListener(OnGameInfoUpdatedListener listener) {
|
||||
sOnGameInfoUpdatedListener = listener;
|
||||
}
|
||||
|
||||
public static OnGameInfoUpdatedListener getOnGameInfoUpdatedListener() {
|
||||
return sOnGameInfoUpdatedListener;
|
||||
}
|
||||
|
||||
// ===========================================================
|
||||
// Inner and Anonymous Classes
|
||||
// ===========================================================
|
||||
|
||||
public static interface Cocos2dxHelperListener {
|
||||
public void showDialog(final String pTitle, final String pMessage);
|
||||
|
||||
public void runOnGLThread(final Runnable pRunnable);
|
||||
}
|
||||
|
||||
private static float[] sDeviceMotionValues = new float[9];
|
||||
|
||||
private static float[] getDeviceMotionValue() {
|
||||
Cocos2dxAccelerometer.DeviceMotionEvent event = Cocos2dxHelper.sCocos2dxAccelerometer.getDeviceMotionEvent();
|
||||
sDeviceMotionValues[0] = event.acceleration.x;
|
||||
sDeviceMotionValues[1] = event.acceleration.y;
|
||||
// Issue https://github.com/cocos-creator/2d-tasks/issues/2532
|
||||
// use negative event.acceleration.z to match iOS value
|
||||
sDeviceMotionValues[2] = - event.acceleration.z;
|
||||
|
||||
sDeviceMotionValues[3] = event.accelerationIncludingGravity.x;
|
||||
sDeviceMotionValues[4] = event.accelerationIncludingGravity.y;
|
||||
sDeviceMotionValues[5] = event.accelerationIncludingGravity.z;
|
||||
|
||||
sDeviceMotionValues[6] = event.rotationRate.alpha;
|
||||
sDeviceMotionValues[7] = event.rotationRate.beta;
|
||||
sDeviceMotionValues[8] = event.rotationRate.gamma;
|
||||
|
||||
return sDeviceMotionValues;
|
||||
}
|
||||
|
||||
public static int getSDKVersion() {
|
||||
return Build.VERSION.SDK_INT;
|
||||
}
|
||||
|
||||
public static String getSystemVersion() {
|
||||
return Build.VERSION.RELEASE;
|
||||
}
|
||||
|
||||
|
||||
public static int getDeviceRotation() {
|
||||
try {
|
||||
Display display = ((WindowManager) sActivity.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
|
||||
return display.getRotation();
|
||||
} catch (NullPointerException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return Surface.ROTATION_0;
|
||||
}
|
||||
|
||||
public static float[] getSafeArea() {
|
||||
|
||||
if (android.os.Build.VERSION.SDK_INT >= 28) {
|
||||
|
||||
do {
|
||||
Object windowInsectObj = getActivity().getWindow().getDecorView().getRootWindowInsets();
|
||||
|
||||
if(windowInsectObj == null) break;
|
||||
|
||||
Class<?> windowInsets = WindowInsets.class;
|
||||
try {
|
||||
Method wiGetDisplayCutout = windowInsets.getMethod("getDisplayCutout");
|
||||
Object cutout = wiGetDisplayCutout.invoke(windowInsectObj);
|
||||
|
||||
if(cutout == null) break;
|
||||
|
||||
Class<?> displayCutout = cutout.getClass();
|
||||
Method dcGetLeft = displayCutout.getMethod("getSafeInsetLeft");
|
||||
Method dcGetRight = displayCutout.getMethod("getSafeInsetRight");
|
||||
Method dcGetBottom = displayCutout.getMethod("getSafeInsetBottom");
|
||||
Method dcGetTop = displayCutout.getMethod("getSafeInsetTop");
|
||||
|
||||
if (dcGetLeft != null && dcGetRight != null && dcGetBottom != null && dcGetTop != null) {
|
||||
int left = (Integer) dcGetLeft.invoke(cutout);
|
||||
int right = (Integer) dcGetRight.invoke(cutout);
|
||||
int top = (Integer) dcGetTop.invoke(cutout);
|
||||
int bottom = (Integer) dcGetBottom.invoke(cutout);
|
||||
return new float[]{top, left, bottom, right};
|
||||
}
|
||||
} catch (NoSuchMethodException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}while(false);
|
||||
}
|
||||
return new float[]{0,0,0,0};
|
||||
}
|
||||
}
|
@@ -0,0 +1,413 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2010-2014 cocos2d-x.org
|
||||
Copyright (c) 2014-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
package org.cocos2dx.lib;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.ProtocolException;
|
||||
import java.net.URL;
|
||||
import java.security.KeyStore;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.InflaterInputStream;
|
||||
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
|
||||
public class Cocos2dxHttpURLConnection
|
||||
{
|
||||
private static String TAG = "Cocos2dxHttpURLConnection";
|
||||
private static final String POST_METHOD = "POST" ;
|
||||
private static final String PUT_METHOD = "PUT" ;
|
||||
|
||||
static HttpURLConnection createHttpURLConnection(String linkURL) {
|
||||
URL url;
|
||||
HttpURLConnection urlConnection;
|
||||
try {
|
||||
url = new URL(linkURL);
|
||||
urlConnection = (HttpURLConnection) url.openConnection();
|
||||
//Accept-Encoding
|
||||
urlConnection.setRequestProperty("Accept-Encoding", "identity");
|
||||
urlConnection.setDoInput(true);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Log.e(TAG, "createHttpURLConnection:" + e.toString());
|
||||
return null;
|
||||
}
|
||||
|
||||
return urlConnection;
|
||||
}
|
||||
|
||||
static void setReadAndConnectTimeout(HttpURLConnection urlConnection, int readMiliseconds, int connectMiliseconds) {
|
||||
urlConnection.setReadTimeout(readMiliseconds);
|
||||
urlConnection.setConnectTimeout(connectMiliseconds);
|
||||
}
|
||||
|
||||
static void setRequestMethod(HttpURLConnection urlConnection, String method){
|
||||
try {
|
||||
urlConnection.setRequestMethod(method);
|
||||
if(method.equalsIgnoreCase(POST_METHOD) || method.equalsIgnoreCase(PUT_METHOD)) {
|
||||
urlConnection.setDoOutput(true);
|
||||
}
|
||||
} catch (ProtocolException e) {
|
||||
Log.e(TAG, "setRequestMethod:" + e.toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void setVerifySSL(HttpURLConnection urlConnection, String sslFilename) {
|
||||
if(!(urlConnection instanceof HttpsURLConnection))
|
||||
return;
|
||||
|
||||
|
||||
HttpsURLConnection httpsURLConnection = (HttpsURLConnection)urlConnection;
|
||||
|
||||
try {
|
||||
InputStream caInput = null;
|
||||
if (sslFilename.startsWith("/")) {
|
||||
caInput = new BufferedInputStream(new FileInputStream(sslFilename));
|
||||
}else {
|
||||
String assetString = "assets/";
|
||||
String assetsfilenameString = sslFilename.substring(assetString.length());
|
||||
caInput = new BufferedInputStream(Cocos2dxHelper.getActivity().getAssets().open(assetsfilenameString));
|
||||
}
|
||||
|
||||
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
||||
Certificate ca;
|
||||
ca = cf.generateCertificate(caInput);
|
||||
System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
|
||||
caInput.close();
|
||||
|
||||
// Create a KeyStore containing our trusted CAs
|
||||
String keyStoreType = KeyStore.getDefaultType();
|
||||
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
|
||||
keyStore.load(null, null);
|
||||
keyStore.setCertificateEntry("ca", ca);
|
||||
|
||||
// Create a TrustManager that trusts the CAs in our KeyStore
|
||||
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
|
||||
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
|
||||
tmf.init(keyStore);
|
||||
|
||||
// Create an SSLContext that uses our TrustManager
|
||||
SSLContext context = SSLContext.getInstance("TLS");
|
||||
context.init(null, tmf.getTrustManagers(), null);
|
||||
|
||||
httpsURLConnection.setSSLSocketFactory(context.getSocketFactory());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Log.e(TAG, "setVerifySSL:" + e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
//Add header
|
||||
static void addRequestHeader(HttpURLConnection urlConnection, String key, String value) {
|
||||
urlConnection.setRequestProperty(key, value);
|
||||
}
|
||||
|
||||
static int connect(HttpURLConnection http) {
|
||||
int suc = 0;
|
||||
|
||||
try {
|
||||
http.connect();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Log.e(TAG, "connect" + e.toString());
|
||||
suc = 1;
|
||||
}
|
||||
|
||||
return suc;
|
||||
}
|
||||
|
||||
static void disconnect(HttpURLConnection http) {
|
||||
http.disconnect();
|
||||
}
|
||||
|
||||
static void sendRequest(HttpURLConnection http, byte[] byteArray) {
|
||||
try {
|
||||
OutputStream out = http.getOutputStream();
|
||||
if(null != byteArray) {
|
||||
out.write(byteArray);
|
||||
out.flush();
|
||||
}
|
||||
out.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Log.e(TAG, "sendRequest:" + e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
static String getResponseHeaders(HttpURLConnection http) {
|
||||
Map<String, List<String>> headers = http.getHeaderFields();
|
||||
if (null == headers) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String header = "";
|
||||
|
||||
for (Entry<String, List<String>> entry: headers.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
if (null == key) {
|
||||
header += listToString(entry.getValue(), ",") + "\n";
|
||||
} else {
|
||||
header += key + ":" + listToString(entry.getValue(), ",") + "\n";
|
||||
}
|
||||
}
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
static String getResponseHeaderByIdx(HttpURLConnection http, int idx) {
|
||||
Map<String, List<String>> headers = http.getHeaderFields();
|
||||
if (null == headers) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String header = null;
|
||||
|
||||
int counter = 0;
|
||||
for (Entry<String, List<String>> entry: headers.entrySet()) {
|
||||
if (counter == idx) {
|
||||
String key = entry.getKey();
|
||||
if (null == key) {
|
||||
header = listToString(entry.getValue(), ",") + "\n";
|
||||
} else {
|
||||
header = key + ":" + listToString(entry.getValue(), ",") + "\n";
|
||||
}
|
||||
break;
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
static String getResponseHeaderByKey(HttpURLConnection http, String key) {
|
||||
if (null == key) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Map<String, List<String>> headers = http.getHeaderFields();
|
||||
if (null == headers) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String header = null;
|
||||
|
||||
for (Entry<String, List<String>> entry: headers.entrySet()) {
|
||||
if (key.equalsIgnoreCase(entry.getKey())) {
|
||||
if ("set-cookie".equalsIgnoreCase(key)) {
|
||||
header = combinCookies(entry.getValue(), http.getURL().getHost());
|
||||
} else {
|
||||
header = listToString(entry.getValue(), ",");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
static int getResponseHeaderByKeyInt(HttpURLConnection http, String key) {
|
||||
String value = http.getHeaderField(key);
|
||||
|
||||
if (null == value) {
|
||||
return 0;
|
||||
} else {
|
||||
return Integer.parseInt(value);
|
||||
}
|
||||
}
|
||||
|
||||
static byte[] getResponseContent(HttpURLConnection http) {
|
||||
InputStream in;
|
||||
try {
|
||||
in = http.getInputStream();
|
||||
String contentEncoding = http.getContentEncoding();
|
||||
if (contentEncoding != null) {
|
||||
if(contentEncoding.equalsIgnoreCase("gzip")){
|
||||
in = new GZIPInputStream(http.getInputStream()); //reads 2 bytes to determine GZIP stream!
|
||||
}
|
||||
else if(contentEncoding.equalsIgnoreCase("deflate")){
|
||||
in = new InflaterInputStream(http.getInputStream());
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
in = http.getErrorStream();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Log.e(TAG, "1 getResponseContent: " + e.toString());
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
byte[] buffer = new byte[1024];
|
||||
int size = 0;
|
||||
ByteArrayOutputStream bytestream = new ByteArrayOutputStream();
|
||||
while((size = in.read(buffer, 0 , 1024)) != -1)
|
||||
{
|
||||
bytestream.write(buffer, 0, size);
|
||||
}
|
||||
byte retbuffer[] = bytestream.toByteArray();
|
||||
bytestream.close();
|
||||
return retbuffer;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Log.e(TAG, "2 getResponseContent:" + e.toString());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static int getResponseCode(HttpURLConnection http) {
|
||||
int code = 0;
|
||||
try {
|
||||
code = http.getResponseCode();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Log.e(TAG, "getResponseCode:" + e.toString());
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
static String getResponseMessage(HttpURLConnection http) {
|
||||
String msg;
|
||||
try {
|
||||
msg = http.getResponseMessage();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
msg = e.toString();
|
||||
Log.e(TAG, "getResponseMessage: " + msg);
|
||||
}
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
public static String listToString(List<String> list, String strInterVal) {
|
||||
if (list == null) {
|
||||
return null;
|
||||
}
|
||||
StringBuilder result = new StringBuilder();
|
||||
boolean flag = false;
|
||||
for (String str : list) {
|
||||
if (flag) {
|
||||
result.append(strInterVal);
|
||||
}
|
||||
if (null == str) {
|
||||
str = "";
|
||||
}
|
||||
result.append(str);
|
||||
flag = true;
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
public static String combinCookies(List<String> list, String hostDomain) {
|
||||
StringBuilder sbCookies = new StringBuilder();
|
||||
String domain = hostDomain;
|
||||
String tailmatch = "FALSE";
|
||||
String path = "/";
|
||||
String secure = "FALSE";
|
||||
String key = null;
|
||||
String value = null;
|
||||
String expires = null;
|
||||
for (String str : list) {
|
||||
String[] parts = str.split(";");
|
||||
for (String part : parts) {
|
||||
int firstIndex = part.indexOf("=");
|
||||
if (-1 == firstIndex)
|
||||
continue;
|
||||
|
||||
String[] item = {part.substring(0, firstIndex), part.substring(firstIndex + 1)};
|
||||
if ("expires".equalsIgnoreCase(item[0].trim())) {
|
||||
expires = str2Seconds(item[1].trim());
|
||||
} else if("path".equalsIgnoreCase(item[0].trim())) {
|
||||
path = item[1];
|
||||
} else if("secure".equalsIgnoreCase(item[0].trim())) {
|
||||
secure = item[1];
|
||||
} else if("domain".equalsIgnoreCase(item[0].trim())) {
|
||||
domain = item[1];
|
||||
} else if("version".equalsIgnoreCase(item[0].trim()) || "max-age".equalsIgnoreCase(item[0].trim())) {
|
||||
//do nothing
|
||||
} else {
|
||||
key = item[0];
|
||||
value = item[1];
|
||||
}
|
||||
}
|
||||
|
||||
if (null == domain) {
|
||||
domain = "none";
|
||||
}
|
||||
|
||||
sbCookies.append(domain);
|
||||
sbCookies.append('\t');
|
||||
sbCookies.append(tailmatch); //access
|
||||
sbCookies.append('\t');
|
||||
sbCookies.append(path); //path
|
||||
sbCookies.append('\t');
|
||||
sbCookies.append(secure); //secure
|
||||
sbCookies.append('\t');
|
||||
sbCookies.append(expires); //expires
|
||||
sbCookies.append("\t");
|
||||
sbCookies.append(key); //key
|
||||
sbCookies.append("\t");
|
||||
sbCookies.append(value); //value
|
||||
sbCookies.append('\n');
|
||||
}
|
||||
|
||||
return sbCookies.toString();
|
||||
}
|
||||
|
||||
private static String str2Seconds(String strTime) {
|
||||
Calendar c = Calendar.getInstance();
|
||||
long milliseconds = 0;
|
||||
|
||||
try {
|
||||
c.setTime(new SimpleDateFormat("EEE, dd-MMM-yy hh:mm:ss zzz", Locale.US).parse(strTime));
|
||||
milliseconds = c.getTimeInMillis() / 1000;
|
||||
} catch (ParseException e) {
|
||||
Log.e(TAG, "str2Seconds: " + e.toString());
|
||||
}
|
||||
|
||||
return Long.toString(milliseconds);
|
||||
}
|
||||
}
|
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
* Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package org.cocos2dx.lib;
|
||||
|
||||
public class Cocos2dxJavascriptJavaBridge {
|
||||
public static native int evalString(String value);
|
||||
}
|
@@ -0,0 +1,174 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
package org.cocos2dx.lib;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.util.Log;
|
||||
|
||||
public class Cocos2dxLocalStorage {
|
||||
|
||||
private static final String TAG = "Cocos2dxLocalStorage";
|
||||
|
||||
private static String DATABASE_NAME = "jsb.sqlite";
|
||||
private static String TABLE_NAME = "data";
|
||||
private static final int DATABASE_VERSION = 1;
|
||||
|
||||
private static DBOpenHelper mDatabaseOpenHelper = null;
|
||||
private static SQLiteDatabase mDatabase = null;
|
||||
/**
|
||||
* Constructor
|
||||
* @param context The Context within which to work, used to create the DB
|
||||
* @return
|
||||
*/
|
||||
public static boolean init(String dbName, String tableName) {
|
||||
if (Cocos2dxActivity.getContext() != null) {
|
||||
DATABASE_NAME = dbName;
|
||||
TABLE_NAME = tableName;
|
||||
mDatabaseOpenHelper = new DBOpenHelper(Cocos2dxActivity.getContext());
|
||||
mDatabase = mDatabaseOpenHelper.getWritableDatabase();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void destroy() {
|
||||
if (mDatabase != null) {
|
||||
mDatabase.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static void setItem(String key, String value) {
|
||||
try {
|
||||
String sql = "replace into "+TABLE_NAME+"(key,value)values(?,?)";
|
||||
mDatabase.execSQL(sql, new Object[] { key, value });
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static String getItem(String key) {
|
||||
String ret = null;
|
||||
try {
|
||||
String sql = "select value from "+TABLE_NAME+" where key=?";
|
||||
Cursor c = mDatabase.rawQuery(sql, new String[]{key});
|
||||
while (c.moveToNext()) {
|
||||
// only return the first value
|
||||
if (ret != null)
|
||||
{
|
||||
Log.e(TAG, "The key contains more than one value.");
|
||||
break;
|
||||
}
|
||||
ret = c.getString(c.getColumnIndex("value"));
|
||||
}
|
||||
c.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static void removeItem(String key) {
|
||||
try {
|
||||
String sql = "delete from "+TABLE_NAME+" where key=?";
|
||||
mDatabase.execSQL(sql, new Object[] {key});
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static void clear() {
|
||||
try {
|
||||
String sql = "delete from "+TABLE_NAME;
|
||||
mDatabase.execSQL(sql);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static String getKey(int nIndex) {
|
||||
String ret = null;
|
||||
try {
|
||||
int nCount = 0;
|
||||
String sql = "select key from "+TABLE_NAME + " order by rowid asc";
|
||||
Cursor c = mDatabase.rawQuery(sql, null);
|
||||
if(nIndex < 0 || nIndex >= c.getCount()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
while (c.moveToNext()) {
|
||||
if(nCount == nIndex) {
|
||||
ret = c.getString(c.getColumnIndex("key"));
|
||||
break;
|
||||
}
|
||||
nCount++;
|
||||
}
|
||||
c.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static int getLength() {
|
||||
int res = 0;
|
||||
try {
|
||||
String sql = "select count(*) as nums from "+TABLE_NAME;
|
||||
Cursor c = mDatabase.rawQuery(sql, null);
|
||||
if (c.moveToNext()){
|
||||
res = c.getInt(c.getColumnIndex("nums"));
|
||||
}
|
||||
c.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* This creates/opens the database.
|
||||
*/
|
||||
private static class DBOpenHelper extends SQLiteOpenHelper {
|
||||
|
||||
DBOpenHelper(Context context) {
|
||||
super(context, DATABASE_NAME, null, DATABASE_VERSION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(SQLiteDatabase db) {
|
||||
db.execSQL("CREATE TABLE IF NOT EXISTS "+TABLE_NAME+"(key TEXT PRIMARY KEY,value TEXT);");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
|
||||
+ newVersion + ", which will destroy all old data");
|
||||
//db.execSQL("DROP TABLE IF EXISTS " + VIRTUAL_TABLE);
|
||||
//onCreate(db);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,33 @@
|
||||
package org.cocos2dx.lib;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.OrientationEventListener;
|
||||
|
||||
public class Cocos2dxOrientationHelper extends OrientationEventListener {
|
||||
|
||||
private int currentOrientation;
|
||||
|
||||
public Cocos2dxOrientationHelper(Context context) {
|
||||
super(context);
|
||||
currentOrientation = Cocos2dxHelper.getDeviceRotation();
|
||||
}
|
||||
|
||||
public void onPause() {
|
||||
this.disable();
|
||||
}
|
||||
|
||||
public void onResume() {
|
||||
this.enable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOrientationChanged(int orientation) {
|
||||
int curOrientation = Cocos2dxHelper.getDeviceRotation();
|
||||
if (curOrientation != currentOrientation) {
|
||||
currentOrientation = Cocos2dxHelper.getDeviceRotation();
|
||||
nativeOnOrientationChanged(currentOrientation);
|
||||
}
|
||||
}
|
||||
|
||||
public static native void nativeOnOrientationChanged(int rotation);
|
||||
}
|
@@ -0,0 +1,134 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2016 cocos2d-x.org
|
||||
Copyright (c) 2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
package org.cocos2dx.lib;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
|
||||
public class Cocos2dxReflectionHelper {
|
||||
public static <T> T getConstantValue(final Class aClass, final String constantName) {
|
||||
try {
|
||||
return (T)aClass.getDeclaredField(constantName).get(null);
|
||||
} catch (NoSuchFieldException e) {
|
||||
Log.e("error", "can not find " + constantName + " in " + aClass.getName());
|
||||
}
|
||||
catch (IllegalAccessException e) {
|
||||
Log.e("error", constantName + " is not accessable");
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
Log.e("error", "arguments error when get " + constantName);
|
||||
}
|
||||
catch (Exception e) {
|
||||
Log.e("error", "can not get constant" + constantName);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static <T> T invokeInstanceMethod(final Object instance, final String methodName,
|
||||
final Class[] parameterTypes, final Object[] parameters) {
|
||||
|
||||
final Class aClass = instance.getClass();
|
||||
try {
|
||||
final Method method = aClass.getMethod(methodName, parameterTypes);
|
||||
return (T)method.invoke(instance, parameters);
|
||||
} catch (NoSuchMethodException e) {
|
||||
Log.e("error", "can not find " + methodName + " in " + aClass.getName());
|
||||
}
|
||||
catch (IllegalAccessException e) {
|
||||
Log.e("error", methodName + " is not accessible");
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
Log.e("error", "arguments are error when invoking " + methodName);
|
||||
}
|
||||
catch (InvocationTargetException e) {
|
||||
Log.e("error", "an exception was thrown by the invoked method when invoking " + methodName);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static <T> T invokeInterfaceMethod(final Class clazz, final String methodName,
|
||||
final Class[] parameterTypes, final Object[] parameters) {
|
||||
|
||||
try {
|
||||
final Method method = clazz.getMethod(methodName, parameterTypes);
|
||||
return (T)method.invoke(null, parameters);
|
||||
} catch (NoSuchMethodException e) {
|
||||
Log.e("error", "can not find " + methodName + " in " + clazz.getName());
|
||||
}
|
||||
catch (IllegalAccessException e) {
|
||||
Log.e("error", methodName + " is not accessible");
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
Log.e("error", "arguments are error when invoking " + methodName);
|
||||
}
|
||||
catch (InvocationTargetException e) {
|
||||
Log.e("error", "an exception was thrown by the invoked method when invoking " + methodName);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Object createInstanceInterface(final String className, final String interfaceName) {
|
||||
try {
|
||||
final Class clazz = Class.forName(className + "$" + interfaceName);
|
||||
return Proxy.newProxyInstance(clazz.getClassLoader(),
|
||||
new Class<?>[]{clazz}, new InvocationHandler() {
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
} catch (ClassNotFoundException ex) {
|
||||
Log.e("error", "can not find " + className + "." + interfaceName);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Class getClassByName(final String className) {
|
||||
try {
|
||||
return Class.forName(className);
|
||||
} catch (ClassNotFoundException ex) {
|
||||
Log.e("error", "can not find " + className);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Class getInterfaceByName(final String className, final String interfaceName) {
|
||||
try {
|
||||
return Class.forName(className + "$" + interfaceName);
|
||||
} catch (ClassNotFoundException ex) {
|
||||
Log.e("error", "can not find " + className + "." + interfaceName);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@@ -0,0 +1,270 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2010-2011 cocos2d-x.org
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
package org.cocos2dx.lib;
|
||||
|
||||
import android.opengl.GLSurfaceView;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import javax.microedition.khronos.egl.EGLConfig;
|
||||
import javax.microedition.khronos.opengles.GL10;
|
||||
public class Cocos2dxRenderer implements GLSurfaceView.Renderer {
|
||||
// ===========================================================
|
||||
// Constants
|
||||
// ===========================================================
|
||||
private final static String TAG = "Cocos2dxRenderer";
|
||||
|
||||
private final static long NANOSECONDSPERSECOND = 1000000000L;
|
||||
private final static long NANOSECONDSPERMICROSECOND = 1000000;
|
||||
|
||||
private static final long INTERVAL_60_FPS = (long) (1.0 / 60 * Cocos2dxRenderer.NANOSECONDSPERSECOND);
|
||||
private static long sAnimationInterval = INTERVAL_60_FPS;
|
||||
private static WeakReference<Cocos2dxRenderer> sRenderer;
|
||||
|
||||
// ===========================================================
|
||||
// Fields
|
||||
// ===========================================================
|
||||
|
||||
private long mLastTickInNanoSeconds;
|
||||
private int mScreenWidth;
|
||||
private int mScreenHeight;
|
||||
private boolean mNativeInitCompleted = false;
|
||||
private boolean mNeedShowFPS = false;
|
||||
private String mDefaultResourcePath = "";
|
||||
private long mOldNanoTime = 0;
|
||||
private long mFrameCount = 0;
|
||||
private boolean mNeedToPause = false;
|
||||
|
||||
// ===========================================================
|
||||
// Constructors
|
||||
// ===========================================================
|
||||
|
||||
// ===========================================================
|
||||
// Getter & Setter
|
||||
// ===========================================================
|
||||
|
||||
public static void setPreferredFramesPerSecond(int fps) {
|
||||
Cocos2dxRenderer.sAnimationInterval = (long) (1.0 / fps * Cocos2dxRenderer.NANOSECONDSPERSECOND);
|
||||
}
|
||||
|
||||
public void setScreenWidthAndHeight(final int surfaceWidth, final int surfaceHeight) {
|
||||
this.mScreenWidth = surfaceWidth;
|
||||
this.mScreenHeight = surfaceHeight;
|
||||
}
|
||||
|
||||
public void setDefaultResourcePath(String path) {
|
||||
if (path == null)
|
||||
return;
|
||||
mDefaultResourcePath = path;
|
||||
}
|
||||
|
||||
public void showFPS() {
|
||||
mNeedShowFPS = true;
|
||||
}
|
||||
|
||||
public interface OnGameEngineInitializedListener {
|
||||
void onGameEngineInitialized();
|
||||
}
|
||||
|
||||
private OnGameEngineInitializedListener mGameEngineInitializedListener;
|
||||
|
||||
public void setOnGameEngineInitializedListener(OnGameEngineInitializedListener listener) {
|
||||
mGameEngineInitializedListener = listener;
|
||||
}
|
||||
|
||||
// ===========================================================
|
||||
// Methods for/from SuperClass/Interfaces
|
||||
// ===========================================================
|
||||
|
||||
@Override
|
||||
public void onSurfaceCreated(final GL10 GL10, final EGLConfig EGLConfig) {
|
||||
mNativeInitCompleted = false;
|
||||
Cocos2dxRenderer.nativeInit(this.mScreenWidth, this.mScreenHeight, mDefaultResourcePath);
|
||||
mOldNanoTime = System.nanoTime();
|
||||
this.mLastTickInNanoSeconds = System.nanoTime();
|
||||
mNativeInitCompleted = true;
|
||||
if (mGameEngineInitializedListener != null) {
|
||||
Cocos2dxHelper.getActivity().runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mGameEngineInitializedListener.onGameEngineInitialized();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceChanged(final GL10 GL10, final int width, final int height) {
|
||||
Cocos2dxRenderer.nativeOnSurfaceChanged(width, height);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDrawFrame(final GL10 gl) {
|
||||
if (mNeedToPause)
|
||||
return;
|
||||
|
||||
if (mNeedShowFPS) {
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
//IDEA: show FPS in Android Text control rather than outputing log.
|
||||
++mFrameCount;
|
||||
long nowFpsTime = System.nanoTime();
|
||||
long fpsTimeInterval = nowFpsTime - mOldNanoTime;
|
||||
if (fpsTimeInterval > 1000000000L) {
|
||||
double frameRate = 1000000000.0 * mFrameCount / fpsTimeInterval;
|
||||
Cocos2dxHelper.OnGameInfoUpdatedListener listener = Cocos2dxHelper.getOnGameInfoUpdatedListener();
|
||||
if (listener != null) {
|
||||
listener.onFPSUpdated((float) frameRate);
|
||||
}
|
||||
mFrameCount = 0;
|
||||
mOldNanoTime = System.nanoTime();
|
||||
}
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
}
|
||||
/*
|
||||
* No need to use algorithm in default(60 FPS) situation,
|
||||
* since onDrawFrame() was called by system 60 times per second by default.
|
||||
*/
|
||||
if (sAnimationInterval <= INTERVAL_60_FPS) {
|
||||
Cocos2dxRenderer.nativeRender();
|
||||
} else {
|
||||
final long now = System.nanoTime();
|
||||
final long interval = now - this.mLastTickInNanoSeconds;
|
||||
|
||||
if (interval < Cocos2dxRenderer.sAnimationInterval) {
|
||||
try {
|
||||
Thread.sleep((Cocos2dxRenderer.sAnimationInterval - interval) / Cocos2dxRenderer.NANOSECONDSPERMICROSECOND);
|
||||
} catch (final Exception e) {
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Render time MUST be counted in, or the FPS will slower than appointed.
|
||||
*/
|
||||
this.mLastTickInNanoSeconds = System.nanoTime();
|
||||
Cocos2dxRenderer.nativeRender();
|
||||
}
|
||||
}
|
||||
|
||||
// ===========================================================
|
||||
// Methods
|
||||
// ===========================================================
|
||||
|
||||
private static native void nativeTouchesBegin(final int id, final float x, final float y);
|
||||
private static native void nativeTouchesEnd(final int id, final float x, final float y);
|
||||
private static native void nativeTouchesMove(final int[] ids, final float[] xs, final float[] ys);
|
||||
private static native void nativeTouchesCancel(final int[] ids, final float[] xs, final float[] ys);
|
||||
private static native boolean nativeKeyEvent(final int keyCode,boolean isPressed);
|
||||
private static native void nativeRender();
|
||||
private static native void nativeInit(final int width, final int height, final String resourcePath);
|
||||
private static native void nativeOnSurfaceChanged(final int width, final int height);
|
||||
private static native void nativeOnPause();
|
||||
private static native void nativeOnResume();
|
||||
|
||||
// This function will be invoked in main thread.
|
||||
public void setPauseInMainThread(boolean value) {
|
||||
mNeedToPause = value;
|
||||
}
|
||||
|
||||
public void handleActionDown(final int id, final float x, final float y) {
|
||||
if (! mNativeInitCompleted)
|
||||
return;
|
||||
|
||||
Cocos2dxRenderer.nativeTouchesBegin(id, x, y);
|
||||
}
|
||||
|
||||
public void handleActionUp(final int id, final float x, final float y) {
|
||||
if (! mNativeInitCompleted)
|
||||
return;
|
||||
|
||||
Cocos2dxRenderer.nativeTouchesEnd(id, x, y);
|
||||
}
|
||||
|
||||
public void handleActionCancel(final int[] ids, final float[] xs, final float[] ys) {
|
||||
if (! mNativeInitCompleted)
|
||||
return;
|
||||
|
||||
Cocos2dxRenderer.nativeTouchesCancel(ids, xs, ys);
|
||||
}
|
||||
|
||||
public void handleActionMove(final int[] ids, final float[] xs, final float[] ys) {
|
||||
if (! mNativeInitCompleted)
|
||||
return;
|
||||
|
||||
Cocos2dxRenderer.nativeTouchesMove(ids, xs, ys);
|
||||
}
|
||||
|
||||
public void handleKeyDown(final int keyCode) {
|
||||
if (! mNativeInitCompleted)
|
||||
return;
|
||||
|
||||
Cocos2dxRenderer.nativeKeyEvent(keyCode, true);
|
||||
}
|
||||
|
||||
public void handleKeyUp(final int keyCode) {
|
||||
if (! mNativeInitCompleted)
|
||||
return;
|
||||
|
||||
Cocos2dxRenderer.nativeKeyEvent(keyCode, false);
|
||||
}
|
||||
|
||||
public void handleOnPause() {
|
||||
/**
|
||||
* onPause may be invoked before onSurfaceCreated,
|
||||
* and engine will be initialized correctly after
|
||||
* onSurfaceCreated is invoked. Can not invoke any
|
||||
* native method before onSurfaceCreated is invoked
|
||||
*/
|
||||
if (! mNativeInitCompleted)
|
||||
return;
|
||||
|
||||
Cocos2dxHelper.onEnterBackground();
|
||||
Cocos2dxRenderer.nativeOnPause();
|
||||
}
|
||||
|
||||
public void handleOnResume() {
|
||||
Cocos2dxHelper.onEnterForeground();
|
||||
Cocos2dxRenderer.nativeOnResume();
|
||||
}
|
||||
|
||||
private static native void nativeInsertText(final String text);
|
||||
private static native void nativeDeleteBackward();
|
||||
private static native String nativeGetContentText();
|
||||
|
||||
public void handleInsertText(final String text) {
|
||||
Cocos2dxRenderer.nativeInsertText(text);
|
||||
}
|
||||
|
||||
public void handleDeleteBackward() {
|
||||
Cocos2dxRenderer.nativeDeleteBackward();
|
||||
}
|
||||
|
||||
public String getContentText() {
|
||||
return Cocos2dxRenderer.nativeGetContentText();
|
||||
}
|
||||
|
||||
// ===========================================================
|
||||
// Inner and Anonymous Classes
|
||||
// ===========================================================
|
||||
}
|
@@ -0,0 +1,81 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2010-2012 cocos2d-x.org
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
package org.cocos2dx.lib;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Typeface;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public class Cocos2dxTypefaces {
|
||||
// ===========================================================
|
||||
// Constants
|
||||
// ===========================================================
|
||||
|
||||
// ===========================================================
|
||||
// Fields
|
||||
// ===========================================================
|
||||
|
||||
private static final HashMap<String, Typeface> sTypefaceCache = new HashMap<String, Typeface>();
|
||||
|
||||
// ===========================================================
|
||||
// Constructors
|
||||
// ===========================================================
|
||||
|
||||
// ===========================================================
|
||||
// Getter & Setter
|
||||
// ===========================================================
|
||||
|
||||
// ===========================================================
|
||||
// Methods for/from SuperClass/Interfaces
|
||||
// ===========================================================
|
||||
|
||||
// ===========================================================
|
||||
// Methods
|
||||
// ===========================================================
|
||||
|
||||
public static synchronized Typeface get(final Context context, final String assetName) {
|
||||
if (!Cocos2dxTypefaces.sTypefaceCache.containsKey(assetName)) {
|
||||
Typeface typeface = null;
|
||||
if (assetName.startsWith("/"))
|
||||
{
|
||||
typeface = Typeface.createFromFile(assetName);
|
||||
}
|
||||
else
|
||||
{
|
||||
typeface = Typeface.createFromAsset(context.getAssets(), assetName);
|
||||
}
|
||||
Cocos2dxTypefaces.sTypefaceCache.put(assetName, typeface);
|
||||
}
|
||||
|
||||
return Cocos2dxTypefaces.sTypefaceCache.get(assetName);
|
||||
}
|
||||
|
||||
// ===========================================================
|
||||
// Inner and Anonymous Classes
|
||||
// ===========================================================
|
||||
|
||||
}
|
@@ -0,0 +1,575 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2014-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
package org.cocos2dx.lib;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import org.cocos2dx.lib.Cocos2dxVideoView.OnVideoEventListener;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.FutureTask;
|
||||
|
||||
public class Cocos2dxVideoHelper {
|
||||
|
||||
private FrameLayout mLayout = null;
|
||||
private Cocos2dxActivity mActivity = null;
|
||||
private static SparseArray<Cocos2dxVideoView> sVideoViews = null;
|
||||
static VideoHandler mVideoHandler = null;
|
||||
private static Handler sHandler = null;
|
||||
|
||||
Cocos2dxVideoHelper(Cocos2dxActivity activity, FrameLayout layout)
|
||||
{
|
||||
mActivity = activity;
|
||||
mLayout = layout;
|
||||
|
||||
mVideoHandler = new VideoHandler(this);
|
||||
sVideoViews = new SparseArray<Cocos2dxVideoView>();
|
||||
sHandler = new Handler(Looper.myLooper());
|
||||
}
|
||||
|
||||
private static int videoTag = 0;
|
||||
private final static int VideoTaskCreate = 0;
|
||||
private final static int VideoTaskRemove = 1;
|
||||
private final static int VideoTaskSetSource = 2;
|
||||
private final static int VideoTaskSetRect = 3;
|
||||
private final static int VideoTaskStart = 4;
|
||||
private final static int VideoTaskPause = 5;
|
||||
private final static int VideoTaskResume = 6;
|
||||
private final static int VideoTaskStop = 7;
|
||||
private final static int VideoTaskSeek = 8;
|
||||
private final static int VideoTaskSetVisible = 9;
|
||||
private final static int VideoTaskRestart = 10;
|
||||
private final static int VideoTaskKeepRatio = 11;
|
||||
private final static int VideoTaskFullScreen = 12;
|
||||
private final static int VideoTaskSetVolume = 13;
|
||||
|
||||
final static int KeyEventBack = 1000;
|
||||
|
||||
static class VideoHandler extends Handler{
|
||||
WeakReference<Cocos2dxVideoHelper> mReference;
|
||||
|
||||
VideoHandler(Cocos2dxVideoHelper helper){
|
||||
mReference = new WeakReference<Cocos2dxVideoHelper>(helper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
Cocos2dxVideoHelper helper = mReference.get();
|
||||
switch (msg.what) {
|
||||
case VideoTaskCreate: {
|
||||
helper._createVideoView(msg.arg1);
|
||||
break;
|
||||
}
|
||||
case VideoTaskRemove: {
|
||||
helper._removeVideoView(msg.arg1);
|
||||
break;
|
||||
}
|
||||
case VideoTaskSetSource: {
|
||||
helper._setVideoURL(msg.arg1, msg.arg2, (String)msg.obj);
|
||||
break;
|
||||
}
|
||||
case VideoTaskStart: {
|
||||
helper._startVideo(msg.arg1);
|
||||
break;
|
||||
}
|
||||
case VideoTaskSetRect: {
|
||||
Rect rect = (Rect)msg.obj;
|
||||
helper._setVideoRect(msg.arg1, rect.left, rect.top, rect.right, rect.bottom);
|
||||
break;
|
||||
}
|
||||
case VideoTaskFullScreen:{
|
||||
if (msg.arg2 == 1) {
|
||||
helper._setFullScreenEnabled(msg.arg1, true);
|
||||
} else {
|
||||
helper._setFullScreenEnabled(msg.arg1, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VideoTaskPause: {
|
||||
helper._pauseVideo(msg.arg1);
|
||||
break;
|
||||
}
|
||||
|
||||
case VideoTaskStop: {
|
||||
helper._stopVideo(msg.arg1);
|
||||
break;
|
||||
}
|
||||
case VideoTaskSeek: {
|
||||
helper._seekVideoTo(msg.arg1, msg.arg2);
|
||||
break;
|
||||
}
|
||||
case VideoTaskSetVisible: {
|
||||
if (msg.arg2 == 1) {
|
||||
helper._setVideoVisible(msg.arg1, true);
|
||||
} else {
|
||||
helper._setVideoVisible(msg.arg1, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VideoTaskKeepRatio: {
|
||||
if (msg.arg2 == 1) {
|
||||
helper._setVideoKeepRatio(msg.arg1, true);
|
||||
} else {
|
||||
helper._setVideoKeepRatio(msg.arg1, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case KeyEventBack: {
|
||||
helper.onBackKeyEvent();
|
||||
break;
|
||||
}
|
||||
case VideoTaskSetVolume: {
|
||||
float volume = (float) msg.arg2 / 10;
|
||||
helper._setVolume(msg.arg1, volume);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
super.handleMessage(msg);
|
||||
}
|
||||
}
|
||||
|
||||
private class VideoEventRunnable implements Runnable
|
||||
{
|
||||
private int mVideoTag;
|
||||
private int mVideoEvent;
|
||||
|
||||
public VideoEventRunnable(int tag,int event) {
|
||||
mVideoTag = tag;
|
||||
mVideoEvent = event;
|
||||
}
|
||||
@Override
|
||||
public void run() {
|
||||
nativeExecuteVideoCallback(mVideoTag, mVideoEvent);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static native void nativeExecuteVideoCallback(int index,int event);
|
||||
|
||||
OnVideoEventListener videoEventListener = new OnVideoEventListener() {
|
||||
|
||||
@Override
|
||||
public void onVideoEvent(int tag,int event) {
|
||||
mActivity.runOnGLThread(new VideoEventRunnable(tag, event));
|
||||
}
|
||||
};
|
||||
|
||||
public static int createVideoWidget() {
|
||||
Message msg = new Message();
|
||||
msg.what = VideoTaskCreate;
|
||||
msg.arg1 = videoTag;
|
||||
mVideoHandler.sendMessage(msg);
|
||||
|
||||
return videoTag++;
|
||||
}
|
||||
|
||||
private void _createVideoView(int index) {
|
||||
Cocos2dxVideoView videoView = new Cocos2dxVideoView(mActivity,index);
|
||||
sVideoViews.put(index, videoView);
|
||||
FrameLayout.LayoutParams lParams = new FrameLayout.LayoutParams(
|
||||
FrameLayout.LayoutParams.WRAP_CONTENT,
|
||||
FrameLayout.LayoutParams.WRAP_CONTENT);
|
||||
mLayout.addView(videoView, lParams);
|
||||
videoView.setZOrderOnTop(true);
|
||||
videoView.setVideoViewEventListener(videoEventListener);
|
||||
}
|
||||
|
||||
public static void removeVideoWidget(int index){
|
||||
Message msg = new Message();
|
||||
msg.what = VideoTaskRemove;
|
||||
msg.arg1 = index;
|
||||
mVideoHandler.sendMessage(msg);
|
||||
}
|
||||
|
||||
private void _removeVideoView(int index) {
|
||||
Cocos2dxVideoView view = sVideoViews.get(index);
|
||||
if (view != null) {
|
||||
view.stopPlayback();
|
||||
sVideoViews.remove(index);
|
||||
mLayout.removeView(view);
|
||||
}
|
||||
}
|
||||
|
||||
public static void setVideoUrl(int index, int videoSource, String videoUrl) {
|
||||
Message msg = new Message();
|
||||
msg.what = VideoTaskSetSource;
|
||||
msg.arg1 = index;
|
||||
msg.arg2 = videoSource;
|
||||
msg.obj = videoUrl;
|
||||
mVideoHandler.sendMessage(msg);
|
||||
}
|
||||
|
||||
private void _setVideoURL(int index, int videoSource, String videoUrl) {
|
||||
Cocos2dxVideoView videoView = sVideoViews.get(index);
|
||||
if (videoView != null) {
|
||||
switch (videoSource) {
|
||||
case 0:
|
||||
videoView.setVideoFileName(videoUrl);
|
||||
break;
|
||||
case 1:
|
||||
videoView.setVideoURL(videoUrl);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void setVideoRect(int index, int left, int top, int maxWidth, int maxHeight) {
|
||||
Message msg = new Message();
|
||||
msg.what = VideoTaskSetRect;
|
||||
msg.arg1 = index;
|
||||
msg.obj = new Rect(left, top, maxWidth, maxHeight);
|
||||
mVideoHandler.sendMessage(msg);
|
||||
}
|
||||
|
||||
private void _setVideoRect(int index, int left, int top, int maxWidth, int maxHeight) {
|
||||
Cocos2dxVideoView videoView = sVideoViews.get(index);
|
||||
if (videoView != null) {
|
||||
videoView.setVideoRect(left,top,maxWidth,maxHeight);
|
||||
}
|
||||
}
|
||||
|
||||
public static void setFullScreenEnabled(int index, boolean enabled) {
|
||||
Message msg = new Message();
|
||||
msg.what = VideoTaskFullScreen;
|
||||
msg.arg1 = index;
|
||||
if (enabled) {
|
||||
msg.arg2 = 1;
|
||||
} else {
|
||||
msg.arg2 = 0;
|
||||
}
|
||||
mVideoHandler.sendMessage(msg);
|
||||
}
|
||||
|
||||
private void _setFullScreenEnabled(int index, boolean enabled) {
|
||||
Cocos2dxVideoView videoView = sVideoViews.get(index);
|
||||
if (videoView != null) {
|
||||
videoView.setFullScreenEnabled(enabled);
|
||||
}
|
||||
}
|
||||
|
||||
private void onBackKeyEvent() {
|
||||
int viewCount = sVideoViews.size();
|
||||
for (int i = 0; i < viewCount; i++) {
|
||||
int key = sVideoViews.keyAt(i);
|
||||
Cocos2dxVideoView videoView = sVideoViews.get(key);
|
||||
if (videoView != null) {
|
||||
videoView.setFullScreenEnabled(false);
|
||||
mActivity.runOnGLThread(new VideoEventRunnable(key, KeyEventBack));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void startVideo(int index) {
|
||||
Message msg = new Message();
|
||||
msg.what = VideoTaskStart;
|
||||
msg.arg1 = index;
|
||||
mVideoHandler.sendMessage(msg);
|
||||
}
|
||||
|
||||
private void _startVideo(int index) {
|
||||
Cocos2dxVideoView videoView = sVideoViews.get(index);
|
||||
if (videoView != null) {
|
||||
videoView.start();
|
||||
}
|
||||
}
|
||||
|
||||
public static void pauseVideo(int index) {
|
||||
Message msg = new Message();
|
||||
msg.what = VideoTaskPause;
|
||||
msg.arg1 = index;
|
||||
mVideoHandler.sendMessage(msg);
|
||||
}
|
||||
|
||||
private void _pauseVideo(int index) {
|
||||
Cocos2dxVideoView videoView = sVideoViews.get(index);
|
||||
if (videoView != null) {
|
||||
videoView.pause();
|
||||
}
|
||||
}
|
||||
|
||||
public static void stopVideo(int index) {
|
||||
Message msg = new Message();
|
||||
msg.what = VideoTaskStop;
|
||||
msg.arg1 = index;
|
||||
mVideoHandler.sendMessage(msg);
|
||||
}
|
||||
|
||||
private void _stopVideo(int index) {
|
||||
Cocos2dxVideoView videoView = sVideoViews.get(index);
|
||||
if (videoView != null) {
|
||||
videoView.stop();
|
||||
}
|
||||
}
|
||||
|
||||
public static void seekVideoTo(int index,int msec) {
|
||||
Message msg = new Message();
|
||||
msg.what = VideoTaskSeek;
|
||||
msg.arg1 = index;
|
||||
msg.arg2 = msec;
|
||||
mVideoHandler.sendMessage(msg);
|
||||
}
|
||||
|
||||
private void _seekVideoTo(int index,int msec) {
|
||||
Cocos2dxVideoView videoView = sVideoViews.get(index);
|
||||
if (videoView != null) {
|
||||
videoView.seekTo(msec);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static <T> T callInMainThread(Callable<T> call) throws ExecutionException, InterruptedException {
|
||||
FutureTask<T> task = new FutureTask<T>(call);
|
||||
sHandler.post(task);
|
||||
return task.get();
|
||||
}
|
||||
|
||||
public static float getCurrentTime(final int index) {
|
||||
Callable<Float> callable = new Callable<Float>() {
|
||||
@Override
|
||||
public Float call() throws Exception {
|
||||
Cocos2dxVideoView video = sVideoViews.get(index);
|
||||
float currentPosition = -1;
|
||||
if (video != null) {
|
||||
currentPosition = video.getCurrentPosition() / 1000.0f;
|
||||
}
|
||||
return new Float(currentPosition);
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
return callInMainThread(callable);
|
||||
} catch (ExecutionException e) {
|
||||
return -1;
|
||||
} catch (InterruptedException e) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public static float getDuration(final int index) {
|
||||
Callable<Float> callable = new Callable<Float>() {
|
||||
@Override
|
||||
public Float call() throws Exception {
|
||||
Cocos2dxVideoView video = sVideoViews.get(index);
|
||||
float duration = -1;
|
||||
if (video != null) {
|
||||
duration = video.getDuration() / 1000.0f;
|
||||
}
|
||||
if (duration <= 0) {
|
||||
Log.w("Cocos2dxVideoHelper", "Video player's duration is not ready to get now!");
|
||||
}
|
||||
return new Float(duration);
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
return callInMainThread(callable);
|
||||
} catch (ExecutionException e) {
|
||||
return -1;
|
||||
} catch (InterruptedException e) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public static void setVideoVisible(int index, boolean visible) {
|
||||
Message msg = new Message();
|
||||
msg.what = VideoTaskSetVisible;
|
||||
msg.arg1 = index;
|
||||
if (visible) {
|
||||
msg.arg2 = 1;
|
||||
} else {
|
||||
msg.arg2 = 0;
|
||||
}
|
||||
|
||||
mVideoHandler.sendMessage(msg);
|
||||
}
|
||||
|
||||
private void _setVideoVisible(int index, boolean visible) {
|
||||
Cocos2dxVideoView videoView = sVideoViews.get(index);
|
||||
if (videoView != null) {
|
||||
if (visible) {
|
||||
videoView.fixSize();
|
||||
videoView.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
videoView.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void setVideoKeepRatioEnabled(int index, boolean enable) {
|
||||
Message msg = new Message();
|
||||
msg.what = VideoTaskKeepRatio;
|
||||
msg.arg1 = index;
|
||||
if (enable) {
|
||||
msg.arg2 = 1;
|
||||
} else {
|
||||
msg.arg2 = 0;
|
||||
}
|
||||
mVideoHandler.sendMessage(msg);
|
||||
}
|
||||
|
||||
private void _setVideoKeepRatio(int index, boolean enable) {
|
||||
Cocos2dxVideoView videoView = sVideoViews.get(index);
|
||||
if (videoView != null) {
|
||||
videoView.setKeepRatio(enable);
|
||||
}
|
||||
}
|
||||
|
||||
private void _setVolume(final int index, final float volume) {
|
||||
Cocos2dxVideoView videoView = sVideoViews.get(index);
|
||||
if (videoView != null) {
|
||||
videoView.setVolume(volume);
|
||||
}
|
||||
}
|
||||
|
||||
public static void setVolume(final int index, final float volume) {
|
||||
Message msg = new Message();
|
||||
msg.what = VideoTaskSetVolume;
|
||||
msg.arg1 = index;
|
||||
msg.arg2 = (int) (volume * 10);
|
||||
mVideoHandler.sendMessage(msg);
|
||||
}
|
||||
|
||||
private byte[] getFrame(final int index) {
|
||||
Callable<byte[]> callable = new Callable<byte[]>() {
|
||||
@Override
|
||||
public byte[] call() throws Exception {
|
||||
Cocos2dxVideoView video = sVideoViews.get(index);
|
||||
byte datas[] = null;
|
||||
if (video != null) datas = video.getFrame();
|
||||
if (datas == null) {
|
||||
Log.w("Cocos2dxVideoHelper", "Video player's frame is not ready to get now!");
|
||||
}
|
||||
return datas;
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
return callInMainThread(callable);
|
||||
} catch (ExecutionException e) {
|
||||
Log.w("ExecutionException", e.getMessage());
|
||||
return null;
|
||||
} catch (InterruptedException e) {
|
||||
Log.w("InterruptedException", e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private float getFrameChannel(final int index) {
|
||||
Callable<Float> callable = new Callable<Float>() {
|
||||
@Override
|
||||
public Float call() throws Exception {
|
||||
Cocos2dxVideoView video = sVideoViews.get(index);
|
||||
int channel = 0;
|
||||
if (video != null) {
|
||||
channel = video.getFrameChannel();
|
||||
}
|
||||
if (channel == 0) {
|
||||
Log.w("Cocos2dxVideoHelper", "Video player's frame channel is unknown!");
|
||||
}
|
||||
return new Float((float)channel);
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
return callInMainThread(callable);
|
||||
} catch (ExecutionException e) {
|
||||
return -1.0f;
|
||||
} catch (InterruptedException e) {
|
||||
return -1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
private float getFrameWidth(final int index) {
|
||||
Callable<Float> callable = new Callable<Float>() {
|
||||
@Override
|
||||
public Float call() {
|
||||
Cocos2dxVideoView video = sVideoViews.get(index);
|
||||
int width = 0;
|
||||
if (video != null) {
|
||||
width = video.getFrameWidth();
|
||||
}
|
||||
if (width == 0) {
|
||||
Log.w("Cocos2dxVideoHelper", "Video player's frame width is not ready to get now!");
|
||||
}
|
||||
return new Float((float)width);
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
return callInMainThread(callable);
|
||||
} catch (ExecutionException e) {
|
||||
return -1.0f;
|
||||
} catch (InterruptedException e) {
|
||||
return -1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
private float getFrameHeight(final int index) {
|
||||
Callable<Float> callable = new Callable<Float>() {
|
||||
@Override
|
||||
public Float call() {
|
||||
Cocos2dxVideoView video = sVideoViews.get(index);
|
||||
int height = 0;
|
||||
if (video != null) {
|
||||
height = video.getFrameHeight();
|
||||
}
|
||||
if (height == 0) {
|
||||
Log.w("Cocos2dxVideoHelper", "Video player's frame height is not ready to get now!");
|
||||
}
|
||||
return new Float((float)height);
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
return callInMainThread(callable);
|
||||
} catch (ExecutionException e) {
|
||||
return -1.0f;
|
||||
} catch (InterruptedException e) {
|
||||
return -1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
private void setShowRawFrame(final int index, final boolean show) {
|
||||
Cocos2dxVideoView video = sVideoViews.get(index);
|
||||
if (video != null) {
|
||||
video.setShowRawFrame(show);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,717 @@
|
||||
/*
|
||||
* Copyright (C) 2006 The Android Open Source Project
|
||||
* Copyright (c) 2014-2016 Chukong Technologies Inc.
|
||||
* Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.cocos2dx.lib;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.res.AssetFileDescriptor;
|
||||
import android.content.res.Resources;
|
||||
import android.media.AudioManager;
|
||||
import android.media.MediaPlayer;
|
||||
import android.media.MediaMetadataRetriever;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.Surface;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.SurfaceView;
|
||||
import android.widget.FrameLayout;
|
||||
import android.graphics.Bitmap;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class Cocos2dxVideoView extends SurfaceView {
|
||||
|
||||
// ===========================================================
|
||||
// Internal classes and interfaces.
|
||||
// ===========================================================
|
||||
|
||||
public interface OnVideoEventListener
|
||||
{
|
||||
void onVideoEvent(int tag,int event);
|
||||
}
|
||||
|
||||
private enum State{
|
||||
IDLE,
|
||||
ERROR,
|
||||
INITIALIZED,
|
||||
PREPARING,
|
||||
PREPARED,
|
||||
STARTED,
|
||||
PAUSED,
|
||||
STOPPED,
|
||||
PLAYBACK_COMPLETED,
|
||||
}
|
||||
|
||||
// ===========================================================
|
||||
// Constants
|
||||
// ===========================================================
|
||||
private static final String AssetResourceRoot = "@assets/";
|
||||
|
||||
// ===========================================================
|
||||
// Fields
|
||||
// ===========================================================
|
||||
|
||||
private String TAG = "Cocos2dxVideoView";
|
||||
|
||||
private Uri mVideoUri;
|
||||
private int mDuration;
|
||||
|
||||
private State mCurrentState = State.IDLE;
|
||||
|
||||
// All the stuff we need for playing and showing a video
|
||||
private SurfaceHolder mSurfaceHolder = null;
|
||||
private MediaPlayer mMediaPlayer = null;
|
||||
private int mVideoWidth = 0;
|
||||
private int mVideoHeight = 0;
|
||||
|
||||
private OnVideoEventListener mOnVideoEventListener;
|
||||
|
||||
// recording the seek position while preparing
|
||||
private int mSeekWhenPrepared = 0;
|
||||
|
||||
protected Cocos2dxActivity mCocos2dxActivity = null;
|
||||
|
||||
protected int mViewLeft = 0;
|
||||
protected int mViewTop = 0;
|
||||
protected int mViewWidth = 0;
|
||||
protected int mViewHeight = 0;
|
||||
|
||||
protected int mVisibleLeft = 0;
|
||||
protected int mVisibleTop = 0;
|
||||
protected int mVisibleWidth = 0;
|
||||
protected int mVisibleHeight = 0;
|
||||
|
||||
protected boolean mFullScreenEnabled = false;
|
||||
protected int mFullScreenWidth = 0;
|
||||
protected int mFullScreenHeight = 0;
|
||||
|
||||
private boolean mIsAssetRouse = false;
|
||||
private String mVideoFilePath = null;
|
||||
|
||||
private int mViewTag = 0;
|
||||
private boolean mKeepRatio = false;
|
||||
private boolean mMetaUpdated = false;
|
||||
|
||||
private MediaMetadataRetriever mRetriever = null;
|
||||
private ByteBuffer mFrameBuf = null;
|
||||
private byte mPixels[] = null;
|
||||
private Bitmap mFrame = null;
|
||||
private Bitmap mCurFrame = null;
|
||||
private boolean mShowRaw = true;
|
||||
private Object mCopyListener = null;
|
||||
|
||||
private Surface mSurface = null;
|
||||
|
||||
private static final int PX_INVALID = 0;
|
||||
private static final int PX_ALPHA = 1;
|
||||
private static final int PX_ARGB_4444 = 2;
|
||||
private static final int PX_ARGB_8888 = 3;
|
||||
private static final int PX_HARDWARE = 4;
|
||||
private static final int PX_RGBA_F16 = 5;
|
||||
private static final int PX_RGB_565 = 6;
|
||||
|
||||
// MediaPlayer will be released when surface view is destroyed, so should record the position,
|
||||
// and use it to play after MedialPlayer is created again.
|
||||
private int mPositionBeforeRelease = 0;
|
||||
|
||||
// ===========================================================
|
||||
// Constructors
|
||||
// ===========================================================
|
||||
|
||||
public Cocos2dxVideoView(Cocos2dxActivity activity,int tag) {
|
||||
super(activity);
|
||||
|
||||
mViewTag = tag;
|
||||
mCocos2dxActivity = activity;
|
||||
initVideoView();
|
||||
setShowRawFrame(true); // Show mediaplayer window.
|
||||
}
|
||||
|
||||
// ===========================================================
|
||||
// Getter & Setter
|
||||
// ===========================================================
|
||||
|
||||
public void setVideoRect(int left, int top, int maxWidth, int maxHeight) {
|
||||
if (mViewLeft == left && mViewTop == top && mViewWidth == maxWidth && mViewHeight == maxHeight)
|
||||
return;
|
||||
|
||||
mViewLeft = left;
|
||||
mViewTop = top;
|
||||
mViewWidth = maxWidth;
|
||||
mViewHeight = maxHeight;
|
||||
|
||||
fixSize(mViewLeft, mViewTop, mViewWidth, mViewHeight);
|
||||
}
|
||||
|
||||
public void setFullScreenEnabled(boolean enabled) {
|
||||
if (mFullScreenEnabled != enabled) {
|
||||
mFullScreenEnabled = enabled;
|
||||
fixSize();
|
||||
}
|
||||
}
|
||||
|
||||
public void setVolume (float volume) {
|
||||
if (mMediaPlayer != null) {
|
||||
mMediaPlayer.setVolume(volume, volume);
|
||||
}
|
||||
}
|
||||
|
||||
public void setKeepRatio(boolean enabled) {
|
||||
mKeepRatio = enabled;
|
||||
fixSize();
|
||||
}
|
||||
|
||||
public void setVideoURL(String url) {
|
||||
mIsAssetRouse = false;
|
||||
setVideoURI(Uri.parse(url), null);
|
||||
}
|
||||
|
||||
public void setVideoFileName(String path) {
|
||||
if (path.startsWith(AssetResourceRoot)) {
|
||||
path = path.substring(AssetResourceRoot.length());
|
||||
}
|
||||
|
||||
if (path.startsWith("/")) {
|
||||
mIsAssetRouse = false;
|
||||
setVideoURI(Uri.parse(path),null);
|
||||
}
|
||||
else {
|
||||
|
||||
mVideoFilePath = path;
|
||||
mIsAssetRouse = true;
|
||||
setVideoURI(Uri.parse(path), null);
|
||||
}
|
||||
}
|
||||
|
||||
public int getCurrentPosition() {
|
||||
if (! (mCurrentState == State.ERROR |
|
||||
mMediaPlayer == null) ) {
|
||||
return mMediaPlayer.getCurrentPosition();
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int getDuration() {
|
||||
if (! (mCurrentState == State.IDLE ||
|
||||
mCurrentState == State.ERROR ||
|
||||
mCurrentState == State.INITIALIZED ||
|
||||
mMediaPlayer == null) ) {
|
||||
mDuration = mMediaPlayer.getDuration();
|
||||
}
|
||||
|
||||
return mDuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a callback to be invoked when some video event triggered.
|
||||
*
|
||||
* @param l The callback that will be run
|
||||
*/
|
||||
public void setVideoViewEventListener(OnVideoEventListener l)
|
||||
{
|
||||
mOnVideoEventListener = l;
|
||||
}
|
||||
|
||||
// ===========================================================
|
||||
// Overrides
|
||||
// ===========================================================
|
||||
|
||||
@Override
|
||||
public void setVisibility(int visibility) {
|
||||
super.setVisibility(visibility);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
setMeasuredDimension(mVisibleWidth, mVisibleHeight);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
if ((event.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_UP) {
|
||||
this.sendEvent(EVENT_CLICKED);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// ===========================================================
|
||||
// Public functions
|
||||
// ===========================================================
|
||||
|
||||
public void stop() {
|
||||
if (!(mCurrentState == State.IDLE || mCurrentState == State.INITIALIZED || mCurrentState == State.ERROR || mCurrentState == State.STOPPED)
|
||||
&& mMediaPlayer != null) {
|
||||
mCurrentState = State.STOPPED;
|
||||
mMediaPlayer.stop();
|
||||
this.sendEvent(EVENT_STOPPED);
|
||||
|
||||
// after the video is stop, it shall prepare to be playable again
|
||||
try {
|
||||
mMediaPlayer.prepare();
|
||||
this.showFirstFrame();
|
||||
} catch (Exception ex) {}
|
||||
}
|
||||
}
|
||||
|
||||
public void stopPlayback() {
|
||||
this.release();
|
||||
}
|
||||
|
||||
public void start() {
|
||||
if ((mCurrentState == State.PREPARED ||
|
||||
mCurrentState == State.PAUSED ||
|
||||
mCurrentState == State.PLAYBACK_COMPLETED) &&
|
||||
mMediaPlayer != null) {
|
||||
|
||||
mCurrentState = State.STARTED;
|
||||
mMediaPlayer.start();
|
||||
this.sendEvent(EVENT_PLAYING);
|
||||
}
|
||||
}
|
||||
|
||||
public void pause() {
|
||||
if ((mCurrentState == State.STARTED || mCurrentState == State.PLAYBACK_COMPLETED) &&
|
||||
mMediaPlayer != null) {
|
||||
mCurrentState = State.PAUSED;
|
||||
mMediaPlayer.pause();
|
||||
this.sendEvent(EVENT_PAUSED);
|
||||
}
|
||||
}
|
||||
|
||||
public void seekTo(int ms) {
|
||||
if (mCurrentState == State.IDLE || mCurrentState == State.INITIALIZED ||
|
||||
mCurrentState == State.STOPPED || mCurrentState == State.ERROR ||
|
||||
mMediaPlayer == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
mMediaPlayer.seekTo(ms);
|
||||
}
|
||||
|
||||
public void fixSize() {
|
||||
if (mFullScreenEnabled) {
|
||||
mFullScreenWidth = mCocos2dxActivity.getGLSurfaceView().getWidth();
|
||||
mFullScreenHeight = mCocos2dxActivity.getGLSurfaceView().getHeight();
|
||||
|
||||
fixSize(0, 0, mFullScreenWidth, mFullScreenHeight);
|
||||
} else {
|
||||
fixSize(mViewLeft, mViewTop, mViewWidth, mViewHeight);
|
||||
}
|
||||
}
|
||||
|
||||
public void fixSize(int left, int top, int width, int height) {
|
||||
if (mVideoWidth == 0 || mVideoHeight == 0) {
|
||||
mVisibleLeft = left;
|
||||
mVisibleTop = top;
|
||||
mVisibleWidth = width;
|
||||
mVisibleHeight = height;
|
||||
}
|
||||
else if (width != 0 && height != 0) {
|
||||
if (mKeepRatio && !mFullScreenEnabled) {
|
||||
if ( mVideoWidth * height > width * mVideoHeight ) {
|
||||
mVisibleWidth = width;
|
||||
mVisibleHeight = width * mVideoHeight / mVideoWidth;
|
||||
} else if ( mVideoWidth * height < width * mVideoHeight ) {
|
||||
mVisibleWidth = height * mVideoWidth / mVideoHeight;
|
||||
mVisibleHeight = height;
|
||||
}
|
||||
mVisibleLeft = left + (width - mVisibleWidth) / 2;
|
||||
mVisibleTop = top + (height - mVisibleHeight) / 2;
|
||||
} else {
|
||||
mVisibleLeft = left;
|
||||
mVisibleTop = top;
|
||||
mVisibleWidth = width;
|
||||
mVisibleHeight = height;
|
||||
}
|
||||
}
|
||||
else {
|
||||
mVisibleLeft = left;
|
||||
mVisibleTop = top;
|
||||
mVisibleWidth = mVideoWidth;
|
||||
mVisibleHeight = mVideoHeight;
|
||||
}
|
||||
|
||||
getHolder().setFixedSize(mVisibleWidth, mVisibleHeight);
|
||||
|
||||
FrameLayout.LayoutParams lParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
|
||||
FrameLayout.LayoutParams.MATCH_PARENT);
|
||||
lParams.leftMargin = mVisibleLeft;
|
||||
lParams.topMargin = mVisibleTop;
|
||||
setLayoutParams(lParams);
|
||||
}
|
||||
|
||||
public int resolveAdjustedSize(int desiredSize, int measureSpec) {
|
||||
int result = desiredSize;
|
||||
int specMode = MeasureSpec.getMode(measureSpec);
|
||||
int specSize = MeasureSpec.getSize(measureSpec);
|
||||
|
||||
switch (specMode) {
|
||||
case MeasureSpec.UNSPECIFIED:
|
||||
/* Parent says we can be as big as we want. Just don't be larger
|
||||
* than max size imposed on ourselves.
|
||||
*/
|
||||
result = desiredSize;
|
||||
break;
|
||||
|
||||
case MeasureSpec.AT_MOST:
|
||||
/* Parent says we can be as big as we want, up to specSize.
|
||||
* Don't be larger than specSize, and don't be larger than
|
||||
* the max size imposed on ourselves.
|
||||
*/
|
||||
result = Math.min(desiredSize, specSize);
|
||||
break;
|
||||
|
||||
case MeasureSpec.EXACTLY:
|
||||
// No choice. Do what we are told.
|
||||
result = specSize;
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public byte[] getFrame() {
|
||||
if(mRetriever == null) {
|
||||
return null;
|
||||
} else {
|
||||
try {
|
||||
if (Build.VERSION.SDK_INT < 24) {
|
||||
mFrame = mRetriever.getFrameAtTime(mMediaPlayer.getCurrentPosition() * 1000, MediaMetadataRetriever.OPTION_CLOSEST);
|
||||
} else {
|
||||
if(mFrame == null) {
|
||||
Bitmap firstFrame = mRetriever.getFrameAtTime(0, MediaMetadataRetriever.OPTION_CLOSEST);
|
||||
mFrame = Bitmap.createBitmap(getWidth(), getHeight(), firstFrame.getConfig());
|
||||
}
|
||||
|
||||
if (mCopyListener == null) {
|
||||
mCopyListener = Cocos2dxReflectionHelper.createInstanceInterface("android.view.PixelCopy", "OnPixelCopyFinishedListener");
|
||||
}
|
||||
|
||||
final Class clazz = Cocos2dxReflectionHelper.getClassByName("android.view.PixelCopy");
|
||||
final Class intef = Cocos2dxReflectionHelper.getInterfaceByName("android.view.PixelCopy", "OnPixelCopyFinishedListener");
|
||||
final Class types[] = {SurfaceView.class, Bitmap.class, intef, Handler.class};
|
||||
final Object params[] = {this, mFrame, mCopyListener, this.getHandler()};
|
||||
|
||||
Cocos2dxReflectionHelper.invokeInterfaceMethod(clazz, "request", types, params);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e("Grab error", e.getStackTrace().toString());
|
||||
return mPixels;
|
||||
}
|
||||
|
||||
if(mFrame == null) {
|
||||
return mPixels;
|
||||
}
|
||||
|
||||
mCurFrame = mFrame;
|
||||
|
||||
if(mFrameBuf == null) {
|
||||
mFrameBuf = ByteBuffer.allocate(mCurFrame.getByteCount());
|
||||
}
|
||||
mFrameBuf.position(0);
|
||||
mCurFrame.copyPixelsToBuffer(mFrameBuf);
|
||||
mPixels = mFrameBuf.array();
|
||||
|
||||
return mPixels;
|
||||
}
|
||||
}
|
||||
|
||||
public int getFrameChannel() throws NoSuchFieldException, IllegalAccessException {
|
||||
if (mCurFrame == null) {
|
||||
return 0;
|
||||
} else {
|
||||
Bitmap.Config cfg = mCurFrame.getConfig();
|
||||
if(Build.VERSION.SDK_INT > 26) {
|
||||
Field hardware = Bitmap.Config.class.getDeclaredField("HARDWARE");
|
||||
Field rgba_f16 = Bitmap.Config.class.getDeclaredField("RGBA_F16");
|
||||
if(hardware != null && cfg == hardware.get(null)) return PX_HARDWARE;
|
||||
if(rgba_f16 != null && cfg == rgba_f16.get(null)) return PX_RGBA_F16;
|
||||
}
|
||||
|
||||
switch (cfg) {
|
||||
case ALPHA_8:
|
||||
return PX_ALPHA;
|
||||
case ARGB_4444:
|
||||
return PX_ARGB_4444;
|
||||
case ARGB_8888:
|
||||
return PX_ARGB_8888;
|
||||
case RGB_565:
|
||||
return PX_RGB_565;
|
||||
default:
|
||||
return PX_INVALID;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int getFrameWidth() {
|
||||
if (mCurFrame != null) {
|
||||
return mCurFrame.getWidth();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public int getFrameHeight() {
|
||||
if(mCurFrame != null) {
|
||||
return mCurFrame.getHeight();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void setShowRawFrame(boolean show) {
|
||||
if(mShowRaw == show) { // Now show state == Before show state
|
||||
return; // Do nothing
|
||||
}
|
||||
setTranslationY(0); // Show view
|
||||
if(!show) {
|
||||
setTranslationY(-1000); // Hide view
|
||||
}
|
||||
mShowRaw = show;
|
||||
}
|
||||
|
||||
// ===========================================================
|
||||
// Private functions
|
||||
// ===========================================================
|
||||
|
||||
private void initVideoView() {
|
||||
mVideoWidth = 0;
|
||||
mVideoHeight = 0;
|
||||
getHolder().addCallback(mSHCallback);
|
||||
//Fix issue#11516:Can't play video on Android 2.3.x
|
||||
getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
|
||||
setFocusable(true);
|
||||
setFocusableInTouchMode(true);
|
||||
mCurrentState = State.IDLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
private void setVideoURI(Uri uri, Map<String, String> headers) {
|
||||
mVideoUri = uri;
|
||||
mVideoWidth = 0;
|
||||
mVideoHeight = 0;
|
||||
}
|
||||
|
||||
private void openVideo() {
|
||||
if (mSurfaceHolder == null) {
|
||||
// not ready for playback just yet, will try again later
|
||||
return;
|
||||
}
|
||||
if (mIsAssetRouse) {
|
||||
if(mVideoFilePath == null)
|
||||
return;
|
||||
} else if(mVideoUri == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.pausePlaybackService();
|
||||
|
||||
try {
|
||||
mMediaPlayer = new MediaPlayer();
|
||||
mMediaPlayer.setOnPreparedListener(mPreparedListener);
|
||||
mMediaPlayer.setOnCompletionListener(mCompletionListener);
|
||||
mMediaPlayer.setOnErrorListener(mErrorListener);
|
||||
mMediaPlayer.setDisplay(mSurfaceHolder);
|
||||
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
|
||||
mMediaPlayer.setScreenOnWhilePlaying(true);
|
||||
|
||||
mRetriever = new MediaMetadataRetriever();
|
||||
mFrameBuf = null;
|
||||
mPixels = null;
|
||||
mCurFrame = null;
|
||||
mFrame = null;
|
||||
|
||||
if (mIsAssetRouse) {
|
||||
AssetFileDescriptor afd = mCocos2dxActivity.getAssets().openFd(mVideoFilePath);
|
||||
mMediaPlayer.setDataSource(afd.getFileDescriptor(),afd.getStartOffset(),afd.getLength());
|
||||
mRetriever.setDataSource(afd.getFileDescriptor(),afd.getStartOffset(),afd.getLength());
|
||||
} else {
|
||||
mMediaPlayer.setDataSource(mVideoUri.toString());
|
||||
if (mVideoUri.getHost().length() > 0) {
|
||||
mRetriever.setDataSource(mVideoUri.toString(), new HashMap<String, String>());
|
||||
} else {
|
||||
mRetriever.setDataSource(mCocos2dxActivity.getContext(), mVideoUri);
|
||||
}
|
||||
}
|
||||
mCurrentState = State.INITIALIZED;
|
||||
|
||||
|
||||
// Use Prepare() instead of PrepareAsync to make things easy.
|
||||
mMediaPlayer.prepare();
|
||||
this.showFirstFrame();
|
||||
|
||||
// mMediaPlayer.prepareAsync();
|
||||
} catch (IOException ex) {
|
||||
Log.w(TAG, "Unable to open content: " + mVideoUri, ex);
|
||||
mCurrentState = State.ERROR;
|
||||
mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
|
||||
return;
|
||||
} catch (IllegalArgumentException ex) {
|
||||
Log.w(TAG, "Unable to open content: " + mVideoUri, ex);
|
||||
mCurrentState = State.ERROR;
|
||||
mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
MediaPlayer.OnPreparedListener mPreparedListener = new MediaPlayer.OnPreparedListener() {
|
||||
public void onPrepared(MediaPlayer mp) {
|
||||
mVideoWidth = mp.getVideoWidth();
|
||||
mVideoHeight = mp.getVideoHeight();
|
||||
|
||||
if (mVideoWidth != 0 && mVideoHeight != 0) {
|
||||
fixSize();
|
||||
}
|
||||
|
||||
if(!mMetaUpdated) {
|
||||
Cocos2dxVideoView.this.sendEvent(EVENT_META_LOADED);
|
||||
Cocos2dxVideoView.this.sendEvent(EVENT_READY_TO_PLAY);
|
||||
mMetaUpdated = true;
|
||||
}
|
||||
|
||||
mCurrentState = State.PREPARED;
|
||||
}
|
||||
};
|
||||
|
||||
private MediaPlayer.OnCompletionListener mCompletionListener =
|
||||
new MediaPlayer.OnCompletionListener() {
|
||||
public void onCompletion(MediaPlayer mp) {
|
||||
mCurrentState = State.PLAYBACK_COMPLETED;
|
||||
Cocos2dxVideoView.this.sendEvent(EVENT_COMPLETED);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
private static final int EVENT_PLAYING = 0;
|
||||
private static final int EVENT_PAUSED = 1;
|
||||
private static final int EVENT_STOPPED = 2;
|
||||
private static final int EVENT_COMPLETED = 3;
|
||||
private static final int EVENT_META_LOADED = 4;
|
||||
private static final int EVENT_CLICKED = 5;
|
||||
private static final int EVENT_READY_TO_PLAY = 6;
|
||||
|
||||
private MediaPlayer.OnErrorListener mErrorListener =
|
||||
new MediaPlayer.OnErrorListener() {
|
||||
public boolean onError(MediaPlayer mp, int framework_err, int impl_err) {
|
||||
Log.d(TAG, "Error: " + framework_err + "," + impl_err);
|
||||
mCurrentState = State.ERROR;
|
||||
|
||||
/* Otherwise, pop up an error dialog so the user knows that
|
||||
* something bad has happened. Only try and pop up the dialog
|
||||
* if we're attached to a window. When we're going away and no
|
||||
* longer have a window, don't bother showing the user an error.
|
||||
*/
|
||||
if (getWindowToken() != null) {
|
||||
Resources r = mCocos2dxActivity.getResources();
|
||||
int messageId;
|
||||
|
||||
if (framework_err == MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK) {
|
||||
// messageId = com.android.internal.R.string.VideoView_error_text_invalid_progressive_playback;
|
||||
messageId = r.getIdentifier("VideoView_error_text_invalid_progressive_playback", "string", "android");
|
||||
} else {
|
||||
// messageId = com.android.internal.R.string.VideoView_error_text_unknown;
|
||||
messageId = r.getIdentifier("VideoView_error_text_unknown", "string", "android");
|
||||
}
|
||||
|
||||
int titleId = r.getIdentifier("VideoView_error_title", "string", "android");
|
||||
int buttonStringId = r.getIdentifier("VideoView_error_button", "string", "android");
|
||||
|
||||
new AlertDialog.Builder(mCocos2dxActivity)
|
||||
.setTitle(r.getString(titleId))
|
||||
.setMessage(messageId)
|
||||
.setPositiveButton(r.getString(buttonStringId),
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int whichButton) {
|
||||
/* If we get here, there is no onError listener, so
|
||||
* at least inform them that the video is over.
|
||||
*/
|
||||
Cocos2dxVideoView.this.sendEvent(EVENT_COMPLETED);
|
||||
}
|
||||
})
|
||||
.setCancelable(false)
|
||||
.show();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
SurfaceHolder.Callback mSHCallback = new SurfaceHolder.Callback()
|
||||
{
|
||||
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
|
||||
}
|
||||
|
||||
public void surfaceCreated(SurfaceHolder holder) {
|
||||
mSurfaceHolder = holder;
|
||||
Cocos2dxVideoView.this.openVideo();
|
||||
|
||||
if (mPositionBeforeRelease > 0)
|
||||
mMediaPlayer.seekTo(mPositionBeforeRelease);
|
||||
}
|
||||
|
||||
public void surfaceDestroyed(SurfaceHolder holder) {
|
||||
// after we return from this we can't use the surface any more
|
||||
mSurfaceHolder = null;
|
||||
mPositionBeforeRelease = getCurrentPosition();
|
||||
Cocos2dxVideoView.this.release();
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* release the media player in any state
|
||||
*/
|
||||
private void release() {
|
||||
if (mMediaPlayer != null) {
|
||||
mMediaPlayer.release();
|
||||
mMediaPlayer = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void showFirstFrame() {
|
||||
mMediaPlayer.seekTo(1);
|
||||
}
|
||||
|
||||
private void sendEvent(int event) {
|
||||
if (this.mOnVideoEventListener != null) {
|
||||
this.mOnVideoEventListener.onVideoEvent(this.mViewTag, event);
|
||||
}
|
||||
}
|
||||
|
||||
// Tell the music playback service to pause
|
||||
// REFINE: these constants need to be published somewhere in the framework.
|
||||
private void pausePlaybackService() {
|
||||
Intent i = new Intent("com.android.music.musicservicecommand");
|
||||
i.putExtra("command", "pause");
|
||||
mCocos2dxActivity.sendBroadcast(i);
|
||||
}
|
||||
}
|
174
cocos2d-x/cocos/platform/android/java/src/org/cocos2dx/lib/Cocos2dxWebView.java
Executable file
174
cocos2d-x/cocos/platform/android/java/src/org/cocos2dx/lib/Cocos2dxWebView.java
Executable file
@@ -0,0 +1,174 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated engine source code (the "Software"), a limited,
|
||||
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
|
||||
to use Cocos Creator solely to develop games on your target platforms. You shall
|
||||
not use Cocos Creator software for developing other software or tools that's
|
||||
used for developing games. You are not granted to publish, distribute,
|
||||
sublicense, and/or sell copies of Cocos Creator.
|
||||
|
||||
The software or tools in this License Agreement are licensed, not sold.
|
||||
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
package org.cocos2dx.lib;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
import android.webkit.WebChromeClient;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebViewClient;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URI;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
class ShouldStartLoadingWorker implements Runnable {
|
||||
private CountDownLatch mLatch;
|
||||
private boolean[] mResult;
|
||||
private final int mViewTag;
|
||||
private final String mUrlString;
|
||||
|
||||
ShouldStartLoadingWorker(CountDownLatch latch, boolean[] result, int viewTag, String urlString) {
|
||||
this.mLatch = latch;
|
||||
this.mResult = result;
|
||||
this.mViewTag = viewTag;
|
||||
this.mUrlString = urlString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
this.mResult[0] = Cocos2dxWebViewHelper._shouldStartLoading(mViewTag, mUrlString);
|
||||
this.mLatch.countDown(); // notify that result is ready
|
||||
}
|
||||
}
|
||||
|
||||
public class Cocos2dxWebView extends WebView {
|
||||
private static final String TAG = Cocos2dxWebViewHelper.class.getSimpleName();
|
||||
|
||||
private int mViewTag;
|
||||
private String mJSScheme;
|
||||
|
||||
public Cocos2dxWebView(Context context) {
|
||||
this(context, -1);
|
||||
}
|
||||
|
||||
@SuppressLint("SetJavaScriptEnabled")
|
||||
public Cocos2dxWebView(Context context, int viewTag) {
|
||||
super(context);
|
||||
this.mViewTag = viewTag;
|
||||
this.mJSScheme = "";
|
||||
|
||||
this.setFocusable(true);
|
||||
this.setFocusableInTouchMode(true);
|
||||
|
||||
this.getSettings().setSupportZoom(false);
|
||||
|
||||
this.getSettings().setDomStorageEnabled(true);
|
||||
this.getSettings().setJavaScriptEnabled(true);
|
||||
|
||||
// `searchBoxJavaBridge_` has big security risk. http://jvn.jp/en/jp/JVN53768697
|
||||
try {
|
||||
Method method = this.getClass().getMethod("removeJavascriptInterface", new Class[]{String.class});
|
||||
method.invoke(this, "searchBoxJavaBridge_");
|
||||
} catch (Exception e) {
|
||||
Log.d(TAG, "This API level do not support `removeJavascriptInterface`");
|
||||
}
|
||||
|
||||
this.setWebViewClient(new Cocos2dxWebViewClient());
|
||||
this.setWebChromeClient(new WebChromeClient());
|
||||
}
|
||||
|
||||
public void setJavascriptInterfaceScheme(String scheme) {
|
||||
this.mJSScheme = scheme != null ? scheme : "";
|
||||
}
|
||||
|
||||
public void setScalesPageToFit(boolean scalesPageToFit) {
|
||||
this.getSettings().setSupportZoom(scalesPageToFit);
|
||||
}
|
||||
|
||||
class Cocos2dxWebViewClient extends WebViewClient {
|
||||
@Override
|
||||
public boolean shouldOverrideUrlLoading(WebView view, final String urlString) {
|
||||
Cocos2dxActivity activity = (Cocos2dxActivity)getContext();
|
||||
|
||||
try {
|
||||
URI uri = URI.create(urlString);
|
||||
if (uri != null && uri.getScheme().equals(mJSScheme)) {
|
||||
activity.runOnGLThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Cocos2dxWebViewHelper._onJsCallback(mViewTag, urlString);
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.d(TAG, "Failed to create URI from url");
|
||||
}
|
||||
|
||||
boolean[] result = new boolean[] { true };
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
|
||||
// run worker on cocos thread
|
||||
activity.runOnGLThread(new ShouldStartLoadingWorker(latch, result, mViewTag, urlString));
|
||||
|
||||
// wait for result from cocos thread
|
||||
try {
|
||||
latch.await();
|
||||
} catch (InterruptedException ex) {
|
||||
Log.d(TAG, "'shouldOverrideUrlLoading' failed");
|
||||
}
|
||||
|
||||
return result[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageFinished(WebView view, final String url) {
|
||||
super.onPageFinished(view, url);
|
||||
Cocos2dxActivity activity = (Cocos2dxActivity)getContext();
|
||||
activity.runOnGLThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Cocos2dxWebViewHelper._didFinishLoading(mViewTag, url);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceivedError(WebView view, int errorCode, String description, final String failingUrl) {
|
||||
super.onReceivedError(view, errorCode, description, failingUrl);
|
||||
Cocos2dxActivity activity = (Cocos2dxActivity)getContext();
|
||||
activity.runOnGLThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Cocos2dxWebViewHelper._didFailLoading(mViewTag, failingUrl);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void setWebViewRect(int left, int top, int maxWidth, int maxHeight) {
|
||||
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
|
||||
FrameLayout.LayoutParams.MATCH_PARENT);
|
||||
layoutParams.leftMargin = left;
|
||||
layoutParams.topMargin = top;
|
||||
layoutParams.width = maxWidth;
|
||||
layoutParams.height = maxHeight;
|
||||
this.setLayoutParams(layoutParams);
|
||||
}
|
||||
}
|
@@ -0,0 +1,323 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2010-2011 cocos2d-x.org
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
package org.cocos2dx.lib;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.SparseArray;
|
||||
import android.view.View;
|
||||
import android.webkit.WebView;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.FutureTask;
|
||||
|
||||
|
||||
public class Cocos2dxWebViewHelper {
|
||||
private static final String TAG = Cocos2dxWebViewHelper.class.getSimpleName();
|
||||
private static Handler sHandler;
|
||||
private static Cocos2dxActivity sCocos2dxActivity;
|
||||
private static FrameLayout sLayout;
|
||||
|
||||
private static SparseArray<Cocos2dxWebView> webViews;
|
||||
private static int viewTag = 0;
|
||||
|
||||
public Cocos2dxWebViewHelper(FrameLayout layout) {
|
||||
Cocos2dxWebViewHelper.sLayout = layout;
|
||||
Cocos2dxWebViewHelper.sHandler = new Handler(Looper.myLooper());
|
||||
|
||||
Cocos2dxWebViewHelper.sCocos2dxActivity = (Cocos2dxActivity) Cocos2dxActivity.getContext();
|
||||
Cocos2dxWebViewHelper.webViews = new SparseArray<Cocos2dxWebView>();
|
||||
}
|
||||
|
||||
private static native boolean shouldStartLoading(int index, String message);
|
||||
|
||||
public static boolean _shouldStartLoading(int index, String message) {
|
||||
return !shouldStartLoading(index, message);
|
||||
}
|
||||
|
||||
private static native void didFinishLoading(int index, String message);
|
||||
|
||||
public static void _didFinishLoading(int index, String message) {
|
||||
didFinishLoading(index, message);
|
||||
}
|
||||
|
||||
private static native void didFailLoading(int index, String message);
|
||||
|
||||
public static void _didFailLoading(int index, String message) {
|
||||
didFailLoading(index, message);
|
||||
}
|
||||
|
||||
private static native void onJsCallback(int index, String message);
|
||||
|
||||
public static void _onJsCallback(int index, String message) {
|
||||
onJsCallback(index, message);
|
||||
}
|
||||
|
||||
public static int createWebView() {
|
||||
final int index = viewTag;
|
||||
sCocos2dxActivity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Cocos2dxWebView webView = new Cocos2dxWebView(sCocos2dxActivity, index);
|
||||
FrameLayout.LayoutParams lParams = new FrameLayout.LayoutParams(
|
||||
FrameLayout.LayoutParams.WRAP_CONTENT,
|
||||
FrameLayout.LayoutParams.WRAP_CONTENT);
|
||||
sLayout.addView(webView, lParams);
|
||||
|
||||
webViews.put(index, webView);
|
||||
}
|
||||
});
|
||||
return viewTag++;
|
||||
}
|
||||
|
||||
public static void removeWebView(final int index) {
|
||||
sCocos2dxActivity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Cocos2dxWebView webView = webViews.get(index);
|
||||
if (webView != null) {
|
||||
webViews.remove(index);
|
||||
sLayout.removeView(webView);
|
||||
webView.destroy();
|
||||
webView = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void setVisible(final int index, final boolean visible) {
|
||||
sCocos2dxActivity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Cocos2dxWebView webView = webViews.get(index);
|
||||
if (webView != null) {
|
||||
webView.setVisibility(visible ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void setWebViewRect(final int index, final int left, final int top, final int maxWidth, final int maxHeight) {
|
||||
sCocos2dxActivity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Cocos2dxWebView webView = webViews.get(index);
|
||||
if (webView != null) {
|
||||
webView.setWebViewRect(left, top, maxWidth, maxHeight);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void setBackgroundTransparent(final int index, final boolean isTransparent) {
|
||||
sCocos2dxActivity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Cocos2dxWebView webView = webViews.get(index);
|
||||
if (webView != null) {
|
||||
webView.setBackgroundColor(isTransparent ? Color.TRANSPARENT : Color.WHITE);
|
||||
webView.setLayerType(WebView.LAYER_TYPE_SOFTWARE, null);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void setJavascriptInterfaceScheme(final int index, final String scheme) {
|
||||
sCocos2dxActivity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Cocos2dxWebView webView = webViews.get(index);
|
||||
if (webView != null) {
|
||||
webView.setJavascriptInterfaceScheme(scheme);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void loadData(final int index, final String data, final String mimeType, final String encoding, final String baseURL) {
|
||||
sCocos2dxActivity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Cocos2dxWebView webView = webViews.get(index);
|
||||
if (webView != null) {
|
||||
webView.loadDataWithBaseURL(baseURL, data, mimeType, encoding, null);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void loadHTMLString(final int index, final String data, final String baseUrl) {
|
||||
sCocos2dxActivity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Cocos2dxWebView webView = webViews.get(index);
|
||||
if (webView != null) {
|
||||
webView.loadDataWithBaseURL(baseUrl, data, null, null, null);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void loadUrl(final int index, final String url) {
|
||||
sCocos2dxActivity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Cocos2dxWebView webView = webViews.get(index);
|
||||
if (webView != null) {
|
||||
webView.loadUrl(url);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void loadFile(final int index, final String filePath) {
|
||||
sCocos2dxActivity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Cocos2dxWebView webView = webViews.get(index);
|
||||
if (webView != null) {
|
||||
webView.loadUrl(filePath);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void stopLoading(final int index) {
|
||||
sCocos2dxActivity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Cocos2dxWebView webView = webViews.get(index);
|
||||
if (webView != null) {
|
||||
webView.stopLoading();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public static void reload(final int index) {
|
||||
sCocos2dxActivity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Cocos2dxWebView webView = webViews.get(index);
|
||||
if (webView != null) {
|
||||
webView.reload();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static <T> T callInMainThread(Callable<T> call) throws ExecutionException, InterruptedException {
|
||||
FutureTask<T> task = new FutureTask<T>(call);
|
||||
sHandler.post(task);
|
||||
return task.get();
|
||||
}
|
||||
|
||||
public static boolean canGoBack(final int index) {
|
||||
Callable<Boolean> callable = new Callable<Boolean>() {
|
||||
@Override
|
||||
public Boolean call() throws Exception {
|
||||
Cocos2dxWebView webView = webViews.get(index);
|
||||
return webView != null && webView.canGoBack();
|
||||
}
|
||||
};
|
||||
try {
|
||||
return callInMainThread(callable);
|
||||
} catch (ExecutionException e) {
|
||||
return false;
|
||||
} catch (InterruptedException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean canGoForward(final int index) {
|
||||
Callable<Boolean> callable = new Callable<Boolean>() {
|
||||
@Override
|
||||
public Boolean call() throws Exception {
|
||||
Cocos2dxWebView webView = webViews.get(index);
|
||||
return webView != null && webView.canGoForward();
|
||||
}
|
||||
};
|
||||
try {
|
||||
return callInMainThread(callable);
|
||||
} catch (ExecutionException e) {
|
||||
return false;
|
||||
} catch (InterruptedException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static void goBack(final int index) {
|
||||
sCocos2dxActivity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Cocos2dxWebView webView = webViews.get(index);
|
||||
if (webView != null) {
|
||||
webView.goBack();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void goForward(final int index) {
|
||||
sCocos2dxActivity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Cocos2dxWebView webView = webViews.get(index);
|
||||
if (webView != null) {
|
||||
webView.goForward();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void evaluateJS(final int index, final String js) {
|
||||
sCocos2dxActivity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Cocos2dxWebView webView = webViews.get(index);
|
||||
if (webView != null) {
|
||||
webView.loadUrl("javascript:" + js);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void setScalesPageToFit(final int index, final boolean scalesPageToFit) {
|
||||
sCocos2dxActivity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Cocos2dxWebView webView = webViews.get(index);
|
||||
if (webView != null) {
|
||||
webView.setScalesPageToFit(scalesPageToFit);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@@ -0,0 +1,63 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
package org.cocos2dx.lib;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Build;
|
||||
import android.view.View;
|
||||
|
||||
public class Utils {
|
||||
private static Activity sActivity = null;
|
||||
|
||||
public static void setActivity(final Activity activity) {
|
||||
Utils.sActivity = activity;
|
||||
}
|
||||
|
||||
public static void hideVirtualButton() {
|
||||
if (Build.VERSION.SDK_INT >= 19 &&
|
||||
null != Utils.sActivity) {
|
||||
// use reflection to remove dependence of API level
|
||||
|
||||
Class viewClass = View.class;
|
||||
final int SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = Cocos2dxReflectionHelper.<Integer>getConstantValue(viewClass, "SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION");
|
||||
final int SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = Cocos2dxReflectionHelper.<Integer>getConstantValue(viewClass, "SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN");
|
||||
final int SYSTEM_UI_FLAG_HIDE_NAVIGATION = Cocos2dxReflectionHelper.<Integer>getConstantValue(viewClass, "SYSTEM_UI_FLAG_HIDE_NAVIGATION");
|
||||
final int SYSTEM_UI_FLAG_FULLSCREEN = Cocos2dxReflectionHelper.<Integer>getConstantValue(viewClass, "SYSTEM_UI_FLAG_FULLSCREEN");
|
||||
final int SYSTEM_UI_FLAG_IMMERSIVE_STICKY = Cocos2dxReflectionHelper.<Integer>getConstantValue(viewClass, "SYSTEM_UI_FLAG_IMMERSIVE_STICKY");
|
||||
final int SYSTEM_UI_FLAG_LAYOUT_STABLE = Cocos2dxReflectionHelper.<Integer>getConstantValue(viewClass, "SYSTEM_UI_FLAG_LAYOUT_STABLE");
|
||||
|
||||
// getWindow().getDecorView().setSystemUiVisibility();
|
||||
final Object[] parameters = new Object[]{SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||
| SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
| SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
| SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav bar
|
||||
| SYSTEM_UI_FLAG_FULLSCREEN // hide status bar
|
||||
| SYSTEM_UI_FLAG_IMMERSIVE_STICKY};
|
||||
Cocos2dxReflectionHelper.<Void>invokeInstanceMethod(Utils.sActivity.getWindow().getDecorView(),
|
||||
"setSystemUiVisibility",
|
||||
new Class[]{Integer.TYPE},
|
||||
parameters);
|
||||
}
|
||||
}
|
||||
}
|
319
cocos2d-x/cocos/platform/android/jni/JniHelper.cpp
Normal file
319
cocos2d-x/cocos/platform/android/jni/JniHelper.cpp
Normal file
@@ -0,0 +1,319 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2010-2012 cocos2d-x.org
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
#include "platform/android/jni/JniHelper.h"
|
||||
#include <android/log.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "base/ccUTF8.h"
|
||||
|
||||
#define LOG_TAG "JniHelper"
|
||||
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
|
||||
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
|
||||
|
||||
static pthread_key_t g_key;
|
||||
|
||||
jclass _getClassID(const char *className) {
|
||||
if (nullptr == className) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JNIEnv* env = cocos2d::JniHelper::getEnv();
|
||||
|
||||
jstring _jstrClassName = env->NewStringUTF(className);
|
||||
|
||||
jclass _clazz = (jclass) env->CallObjectMethod(cocos2d::JniHelper::classloader,
|
||||
cocos2d::JniHelper::loadclassMethod_methodID,
|
||||
_jstrClassName);
|
||||
|
||||
if (nullptr == _clazz || env->ExceptionCheck()) {
|
||||
LOGE("Classloader failed to find class of %s", className);
|
||||
env->ExceptionClear();
|
||||
_clazz = nullptr;
|
||||
}
|
||||
|
||||
env->DeleteLocalRef(_jstrClassName);
|
||||
|
||||
return _clazz;
|
||||
}
|
||||
|
||||
void _detachCurrentThread(void* a) {
|
||||
cocos2d::JniHelper::getJavaVM()->DetachCurrentThread();
|
||||
}
|
||||
|
||||
namespace cocos2d {
|
||||
|
||||
JavaVM* JniHelper::_psJavaVM = nullptr;
|
||||
jmethodID JniHelper::loadclassMethod_methodID = nullptr;
|
||||
jobject JniHelper::classloader = nullptr;
|
||||
std::function<void()> JniHelper::classloaderCallback = nullptr;
|
||||
|
||||
jobject JniHelper::_activity = nullptr;
|
||||
|
||||
JavaVM* JniHelper::getJavaVM() {
|
||||
pthread_t thisthread = pthread_self();
|
||||
LOGD("JniHelper::getJavaVM(), pthread_self() = %ld", thisthread);
|
||||
return _psJavaVM;
|
||||
}
|
||||
|
||||
void JniHelper::setJavaVM(JavaVM *javaVM) {
|
||||
pthread_t thisthread = pthread_self();
|
||||
LOGD("JniHelper::setJavaVM(%p), pthread_self() = %ld", javaVM, thisthread);
|
||||
_psJavaVM = javaVM;
|
||||
|
||||
pthread_key_create(&g_key, _detachCurrentThread);
|
||||
}
|
||||
|
||||
JNIEnv* JniHelper::cacheEnv(JavaVM* jvm) {
|
||||
JNIEnv* _env = nullptr;
|
||||
// get jni environment
|
||||
jint ret = jvm->GetEnv((void**)&_env, JNI_VERSION_1_4);
|
||||
|
||||
switch (ret) {
|
||||
case JNI_OK :
|
||||
// Success!
|
||||
pthread_setspecific(g_key, _env);
|
||||
return _env;
|
||||
|
||||
case JNI_EDETACHED :
|
||||
// Thread not attached
|
||||
if (jvm->AttachCurrentThread(&_env, nullptr) < 0)
|
||||
{
|
||||
LOGE("Failed to get the environment using AttachCurrentThread()");
|
||||
|
||||
return nullptr;
|
||||
} else {
|
||||
// Success : Attached and obtained JNIEnv!
|
||||
pthread_setspecific(g_key, _env);
|
||||
return _env;
|
||||
}
|
||||
|
||||
case JNI_EVERSION :
|
||||
// Cannot recover from this error
|
||||
LOGE("JNI interface version 1.4 not supported");
|
||||
default :
|
||||
LOGE("Failed to get the environment using GetEnv()");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
JNIEnv* JniHelper::getEnv() {
|
||||
JNIEnv *_env = (JNIEnv *)pthread_getspecific(g_key);
|
||||
if (_env == nullptr)
|
||||
_env = JniHelper::cacheEnv(_psJavaVM);
|
||||
return _env;
|
||||
}
|
||||
|
||||
jobject JniHelper::getActivity() {
|
||||
return _activity;
|
||||
}
|
||||
|
||||
bool JniHelper::setClassLoaderFrom(jobject activityinstance) {
|
||||
JniMethodInfo _getclassloaderMethod;
|
||||
if (!JniHelper::getMethodInfo_DefaultClassLoader(_getclassloaderMethod,
|
||||
"android/content/Context",
|
||||
"getClassLoader",
|
||||
"()Ljava/lang/ClassLoader;")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
jobject _c = cocos2d::JniHelper::getEnv()->CallObjectMethod(activityinstance,
|
||||
_getclassloaderMethod.methodID);
|
||||
|
||||
if (nullptr == _c) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JniMethodInfo _m;
|
||||
if (!JniHelper::getMethodInfo_DefaultClassLoader(_m,
|
||||
"java/lang/ClassLoader",
|
||||
"loadClass",
|
||||
"(Ljava/lang/String;)Ljava/lang/Class;")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JniHelper::classloader = cocos2d::JniHelper::getEnv()->NewGlobalRef(_c);
|
||||
JniHelper::loadclassMethod_methodID = _m.methodID;
|
||||
JniHelper::_activity = cocos2d::JniHelper::getEnv()->NewGlobalRef(activityinstance);
|
||||
if (JniHelper::classloaderCallback != nullptr){
|
||||
JniHelper::classloaderCallback();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JniHelper::getStaticMethodInfo(JniMethodInfo &methodinfo,
|
||||
const char *className,
|
||||
const char *methodName,
|
||||
const char *paramCode) {
|
||||
if ((nullptr == className) ||
|
||||
(nullptr == methodName) ||
|
||||
(nullptr == paramCode)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JNIEnv *env = JniHelper::getEnv();
|
||||
if (!env) {
|
||||
LOGE("Failed to get JNIEnv");
|
||||
return false;
|
||||
}
|
||||
|
||||
jclass classID = _getClassID(className);
|
||||
if (! classID) {
|
||||
LOGE("Failed to find class %s", className);
|
||||
env->ExceptionClear();
|
||||
return false;
|
||||
}
|
||||
|
||||
jmethodID methodID = env->GetStaticMethodID(classID, methodName, paramCode);
|
||||
if (! methodID) {
|
||||
LOGE("Failed to find static method id of %s", methodName);
|
||||
env->ExceptionClear();
|
||||
return false;
|
||||
}
|
||||
|
||||
methodinfo.classID = classID;
|
||||
methodinfo.env = env;
|
||||
methodinfo.methodID = methodID;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JniHelper::getMethodInfo_DefaultClassLoader(JniMethodInfo &methodinfo,
|
||||
const char *className,
|
||||
const char *methodName,
|
||||
const char *paramCode) {
|
||||
if ((nullptr == className) ||
|
||||
(nullptr == methodName) ||
|
||||
(nullptr == paramCode)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JNIEnv *env = JniHelper::getEnv();
|
||||
if (!env) {
|
||||
return false;
|
||||
}
|
||||
|
||||
jclass classID = env->FindClass(className);
|
||||
if (! classID) {
|
||||
LOGE("Failed to find class %s", className);
|
||||
env->ExceptionClear();
|
||||
return false;
|
||||
}
|
||||
|
||||
jmethodID methodID = env->GetMethodID(classID, methodName, paramCode);
|
||||
if (! methodID) {
|
||||
LOGE("Failed to find method id of %s", methodName);
|
||||
env->ExceptionClear();
|
||||
return false;
|
||||
}
|
||||
|
||||
methodinfo.classID = classID;
|
||||
methodinfo.env = env;
|
||||
methodinfo.methodID = methodID;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JniHelper::getMethodInfo(JniMethodInfo &methodinfo,
|
||||
const char *className,
|
||||
const char *methodName,
|
||||
const char *paramCode) {
|
||||
if ((nullptr == className) ||
|
||||
(nullptr == methodName) ||
|
||||
(nullptr == paramCode)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JNIEnv *env = JniHelper::getEnv();
|
||||
if (!env) {
|
||||
return false;
|
||||
}
|
||||
|
||||
jclass classID = _getClassID(className);
|
||||
if (! classID) {
|
||||
LOGE("Failed to find class %s", className);
|
||||
env->ExceptionClear();
|
||||
return false;
|
||||
}
|
||||
|
||||
jmethodID methodID = env->GetMethodID(classID, methodName, paramCode);
|
||||
if (! methodID) {
|
||||
LOGE("Failed to find method id of %s", methodName);
|
||||
env->ExceptionClear();
|
||||
return false;
|
||||
}
|
||||
|
||||
methodinfo.classID = classID;
|
||||
methodinfo.env = env;
|
||||
methodinfo.methodID = methodID;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string JniHelper::jstring2string(jstring jstr) {
|
||||
if (jstr == nullptr) {
|
||||
return "";
|
||||
}
|
||||
|
||||
JNIEnv *env = JniHelper::getEnv();
|
||||
if (!env) {
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string strValue = cocos2d::StringUtils::getStringUTFCharsJNI(env, jstr);
|
||||
|
||||
return strValue;
|
||||
}
|
||||
|
||||
jstring JniHelper::convert(JniHelper::LocalRefMapType &localRefs, cocos2d::JniMethodInfo& t, const char* x) {
|
||||
jstring ret = nullptr;
|
||||
if (x)
|
||||
ret = cocos2d::StringUtils::newStringUTFJNI(t.env, x);
|
||||
|
||||
localRefs[t.env].push_back(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
jstring JniHelper::convert(JniHelper::LocalRefMapType &localRefs, cocos2d::JniMethodInfo& t, const std::string& x) {
|
||||
return convert(localRefs, t, x.c_str());
|
||||
}
|
||||
|
||||
void JniHelper::deleteLocalRefs(JNIEnv* env, JniHelper::LocalRefMapType &localRefs) {
|
||||
if (!env) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto& ref : localRefs[env]) {
|
||||
env->DeleteLocalRef(ref);
|
||||
}
|
||||
localRefs[env].clear();
|
||||
}
|
||||
|
||||
void JniHelper::reportError(const std::string& className, const std::string& methodName, const std::string& signature) {
|
||||
LOGE("Failed to find static java method. Class name: %s, method name: %s, signature: %s ", className.c_str(), methodName.c_str(), signature.c_str());
|
||||
}
|
||||
|
||||
} //namespace cocos2d
|
399
cocos2d-x/cocos/platform/android/jni/JniHelper.h
Normal file
399
cocos2d-x/cocos/platform/android/jni/JniHelper.h
Normal file
@@ -0,0 +1,399 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2010-2012 cocos2d-x.org
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
#ifndef __ANDROID_JNI_HELPER_H__
|
||||
#define __ANDROID_JNI_HELPER_H__
|
||||
|
||||
#include <jni.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <functional>
|
||||
#include "base/ccMacros.h"
|
||||
#include "math/Vec3.h"
|
||||
|
||||
//The macro must be used this way to find the native method. The principle is not well understood.
|
||||
#define JNI_METHOD2(CLASS2,FUNC2) Java_##CLASS2##_##FUNC2
|
||||
#define JNI_METHOD1(CLASS1,FUNC1) JNI_METHOD2(CLASS1,FUNC1)
|
||||
|
||||
NS_CC_BEGIN
|
||||
|
||||
typedef struct JniMethodInfo_
|
||||
{
|
||||
JNIEnv * env;
|
||||
jclass classID;
|
||||
jmethodID methodID;
|
||||
} JniMethodInfo;
|
||||
|
||||
|
||||
class CC_DLL JniHelper
|
||||
{
|
||||
public:
|
||||
|
||||
typedef std::unordered_map<JNIEnv *, std::vector<jobject >> LocalRefMapType;
|
||||
|
||||
static void setJavaVM(JavaVM *javaVM);
|
||||
static JavaVM* getJavaVM();
|
||||
static JNIEnv* getEnv();
|
||||
static jobject getActivity();
|
||||
|
||||
static bool setClassLoaderFrom(jobject activityInstance);
|
||||
static bool getStaticMethodInfo(JniMethodInfo &methodinfo,
|
||||
const char *className,
|
||||
const char *methodName,
|
||||
const char *paramCode);
|
||||
static bool getMethodInfo(JniMethodInfo &methodinfo,
|
||||
const char *className,
|
||||
const char *methodName,
|
||||
const char *paramCode);
|
||||
|
||||
static std::string jstring2string(jstring str);
|
||||
|
||||
static jmethodID loadclassMethod_methodID;
|
||||
static jobject classloader;
|
||||
static std::function<void()> classloaderCallback;
|
||||
|
||||
template <typename... Ts>
|
||||
static jobject newObject(const std::string& className, Ts... xs)
|
||||
{
|
||||
jobject ret = nullptr;
|
||||
static const char* methodName = "<init>";
|
||||
cocos2d::JniMethodInfo t;
|
||||
std::string signature = "(" + std::string(getJNISignature(xs...)) + ")V";
|
||||
if (cocos2d::JniHelper::getMethodInfo(t, className.c_str(), methodName, signature.c_str())) {
|
||||
LocalRefMapType localRefs;
|
||||
ret = t.env->NewObject(t.classID, t.methodID, convert(t, xs)...);
|
||||
t.env->DeleteLocalRef(t.classID);
|
||||
deleteLocalRefs(t.env, localRefs);
|
||||
} else {
|
||||
reportError(className, methodName, signature);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
static void callObjectVoidMethod(jobject object,
|
||||
const std::string& className,
|
||||
const std::string& methodName,
|
||||
Ts... xs) {
|
||||
cocos2d::JniMethodInfo t;
|
||||
std::string signature = "(" + std::string(getJNISignature(xs...)) + ")V";
|
||||
if (cocos2d::JniHelper::getMethodInfo(t, className.c_str(), methodName.c_str(), signature.c_str())) {
|
||||
LocalRefMapType localRefs;
|
||||
t.env->CallVoidMethod(object, t.methodID, convert(localRefs, t, xs)...);
|
||||
t.env->DeleteLocalRef(t.classID);
|
||||
deleteLocalRefs(t.env, localRefs);
|
||||
} else {
|
||||
reportError(className, methodName, signature);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
static float callObjectFloatMethod(jobject object,
|
||||
const std::string& className,
|
||||
const std::string& methodName,
|
||||
Ts... xs) {
|
||||
float ret = 0.0f;
|
||||
cocos2d::JniMethodInfo t;
|
||||
std::string signature = "(" + std::string(getJNISignature(xs...)) + ")F";
|
||||
if (cocos2d::JniHelper::getMethodInfo(t, className.c_str(), methodName.c_str(), signature.c_str())) {
|
||||
LocalRefMapType localRefs;
|
||||
ret = t.env->CallFloatMethod(object, t.methodID, convert(localRefs, t, xs)...);
|
||||
t.env->DeleteLocalRef(t.classID);
|
||||
deleteLocalRefs(t.env, localRefs);
|
||||
} else {
|
||||
reportError(className, methodName, signature);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
static jbyteArray callObjectByteArrayMethod(jobject object,
|
||||
const std::string& className,
|
||||
const std::string& methodName,
|
||||
Ts... xs) {
|
||||
jbyteArray ret = nullptr;
|
||||
cocos2d::JniMethodInfo t;
|
||||
std::string signature = "(" + std::string(getJNISignature(xs...)) + ")[B";
|
||||
if (cocos2d::JniHelper::getMethodInfo(t, className.c_str(), methodName.c_str(), signature.c_str())) {
|
||||
LocalRefMapType localRefs;
|
||||
ret = (jbyteArray)t.env->CallObjectMethod(object, t.methodID, convert(localRefs, t, xs)...);
|
||||
t.env->DeleteLocalRef(t.classID);
|
||||
deleteLocalRefs(t.env, localRefs);
|
||||
} else {
|
||||
reportError(className, methodName, signature);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
static void callStaticVoidMethod(const std::string& className,
|
||||
const std::string& methodName,
|
||||
Ts... xs) {
|
||||
cocos2d::JniMethodInfo t;
|
||||
std::string signature = "(" + std::string(getJNISignature(xs...)) + ")V";
|
||||
if (cocos2d::JniHelper::getStaticMethodInfo(t, className.c_str(), methodName.c_str(), signature.c_str())) {
|
||||
LocalRefMapType localRefs;
|
||||
t.env->CallStaticVoidMethod(t.classID, t.methodID, convert(localRefs, t, xs)...);
|
||||
t.env->DeleteLocalRef(t.classID);
|
||||
deleteLocalRefs(t.env, localRefs);
|
||||
} else {
|
||||
reportError(className, methodName, signature);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
static bool callStaticBooleanMethod(const std::string& className,
|
||||
const std::string& methodName,
|
||||
Ts... xs) {
|
||||
jboolean jret = JNI_FALSE;
|
||||
cocos2d::JniMethodInfo t;
|
||||
std::string signature = "(" + std::string(getJNISignature(xs...)) + ")Z";
|
||||
if (cocos2d::JniHelper::getStaticMethodInfo(t, className.c_str(), methodName.c_str(), signature.c_str())) {
|
||||
LocalRefMapType localRefs;
|
||||
jret = t.env->CallStaticBooleanMethod(t.classID, t.methodID, convert(localRefs, t, xs)...);
|
||||
t.env->DeleteLocalRef(t.classID);
|
||||
deleteLocalRefs(t.env, localRefs);
|
||||
} else {
|
||||
reportError(className, methodName, signature);
|
||||
}
|
||||
return (jret == JNI_TRUE);
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
static int callStaticIntMethod(const std::string& className,
|
||||
const std::string& methodName,
|
||||
Ts... xs) {
|
||||
jint ret = 0;
|
||||
cocos2d::JniMethodInfo t;
|
||||
std::string signature = "(" + std::string(getJNISignature(xs...)) + ")I";
|
||||
if (cocos2d::JniHelper::getStaticMethodInfo(t, className.c_str(), methodName.c_str(), signature.c_str())) {
|
||||
LocalRefMapType localRefs;
|
||||
ret = t.env->CallStaticIntMethod(t.classID, t.methodID, convert(t, xs)...);
|
||||
t.env->DeleteLocalRef(t.classID);
|
||||
deleteLocalRefs(t.env, localRefs);
|
||||
} else {
|
||||
reportError(className, methodName, signature);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
static float callStaticFloatMethod(const std::string& className,
|
||||
const std::string& methodName,
|
||||
Ts... xs) {
|
||||
jfloat ret = 0.0;
|
||||
cocos2d::JniMethodInfo t;
|
||||
std::string signature = "(" + std::string(getJNISignature(xs...)) + ")F";
|
||||
if (cocos2d::JniHelper::getStaticMethodInfo(t, className.c_str(), methodName.c_str(), signature.c_str())) {
|
||||
LocalRefMapType localRefs;
|
||||
ret = t.env->CallStaticFloatMethod(t.classID, t.methodID, convert(localRefs, t, xs)...);
|
||||
t.env->DeleteLocalRef(t.classID);
|
||||
deleteLocalRefs(t.env, localRefs);
|
||||
} else {
|
||||
reportError(className, methodName, signature);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
static float* callStaticFloatArrayMethod(const std::string& className,
|
||||
const std::string& methodName,
|
||||
Ts... xs) {
|
||||
static float ret[32];
|
||||
cocos2d::JniMethodInfo t;
|
||||
std::string signature = "(" + std::string(getJNISignature(xs...)) + ")[F";
|
||||
if (cocos2d::JniHelper::getStaticMethodInfo(t, className.c_str(), methodName.c_str(), signature.c_str())) {
|
||||
LocalRefMapType localRefs;
|
||||
jfloatArray array = (jfloatArray) t.env->CallStaticObjectMethod(t.classID, t.methodID, convert(localRefs, t, xs)...);
|
||||
jsize len = t.env->GetArrayLength(array);
|
||||
if (len <= 32) {
|
||||
jfloat* elems = t.env->GetFloatArrayElements(array, 0);
|
||||
if (elems) {
|
||||
memcpy(ret, elems, sizeof(float) * len);
|
||||
t.env->ReleaseFloatArrayElements(array, elems, 0);
|
||||
};
|
||||
}
|
||||
t.env->DeleteLocalRef(array);
|
||||
t.env->DeleteLocalRef(t.classID);
|
||||
deleteLocalRefs(t.env, localRefs);
|
||||
return &ret[0];
|
||||
} else {
|
||||
reportError(className, methodName, signature);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
static Vec3 callStaticVec3Method(const std::string& className,
|
||||
const std::string& methodName,
|
||||
Ts... xs) {
|
||||
Vec3 ret;
|
||||
cocos2d::JniMethodInfo t;
|
||||
std::string signature = "(" + std::string(getJNISignature(xs...)) + ")[F";
|
||||
if (cocos2d::JniHelper::getStaticMethodInfo(t, className.c_str(), methodName.c_str(), signature.c_str())) {
|
||||
LocalRefMapType localRefs;
|
||||
jfloatArray array = (jfloatArray) t.env->CallStaticObjectMethod(t.classID, t.methodID, convert(localRefs, t, xs)...);
|
||||
jsize len = t.env->GetArrayLength(array);
|
||||
if (len == 3) {
|
||||
jfloat* elems = t.env->GetFloatArrayElements(array, 0);
|
||||
ret.x = elems[0];
|
||||
ret.y = elems[1];
|
||||
ret.z = elems[2];
|
||||
t.env->ReleaseFloatArrayElements(array, elems, 0);
|
||||
}
|
||||
t.env->DeleteLocalRef(array);
|
||||
t.env->DeleteLocalRef(t.classID);
|
||||
deleteLocalRefs(t.env, localRefs);
|
||||
} else {
|
||||
reportError(className, methodName, signature);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
static double callStaticDoubleMethod(const std::string& className,
|
||||
const std::string& methodName,
|
||||
Ts... xs) {
|
||||
jdouble ret = 0.0;
|
||||
cocos2d::JniMethodInfo t;
|
||||
std::string signature = "(" + std::string(getJNISignature(xs...)) + ")D";
|
||||
if (cocos2d::JniHelper::getStaticMethodInfo(t, className.c_str(), methodName.c_str(), signature.c_str())) {
|
||||
LocalRefMapType localRefs;
|
||||
ret = t.env->CallStaticDoubleMethod(t.classID, t.methodID, convert(localRefs, t, xs)...);
|
||||
t.env->DeleteLocalRef(t.classID);
|
||||
deleteLocalRefs(t.env, localRefs);
|
||||
} else {
|
||||
reportError(className, methodName, signature);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
static std::string callStaticStringMethod(const std::string& className,
|
||||
const std::string& methodName,
|
||||
Ts... xs) {
|
||||
std::string ret;
|
||||
|
||||
cocos2d::JniMethodInfo t;
|
||||
std::string signature = "(" + std::string(getJNISignature(xs...)) + ")Ljava/lang/String;";
|
||||
if (cocos2d::JniHelper::getStaticMethodInfo(t, className.c_str(), methodName.c_str(), signature.c_str())) {
|
||||
LocalRefMapType localRefs;
|
||||
jstring jret = (jstring)t.env->CallStaticObjectMethod(t.classID, t.methodID, convert(localRefs, t, xs)...);
|
||||
ret = cocos2d::JniHelper::jstring2string(jret);
|
||||
t.env->DeleteLocalRef(t.classID);
|
||||
t.env->DeleteLocalRef(jret);
|
||||
deleteLocalRefs(t.env, localRefs);
|
||||
} else {
|
||||
reportError(className, methodName, signature);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
private:
|
||||
static JNIEnv* cacheEnv(JavaVM* jvm);
|
||||
|
||||
static bool getMethodInfo_DefaultClassLoader(JniMethodInfo &methodinfo,
|
||||
const char *className,
|
||||
const char *methodName,
|
||||
const char *paramCode);
|
||||
|
||||
static JavaVM* _psJavaVM;
|
||||
|
||||
static jobject _activity;
|
||||
|
||||
static jstring convert(LocalRefMapType &localRefs, cocos2d::JniMethodInfo& t, const char* x);
|
||||
|
||||
static jstring convert(LocalRefMapType &localRefs, cocos2d::JniMethodInfo& t, const std::string& x);
|
||||
|
||||
template <typename T>
|
||||
static T convert(LocalRefMapType &localRefs, cocos2d::JniMethodInfo&, T x) {
|
||||
return x;
|
||||
}
|
||||
|
||||
static void deleteLocalRefs(JNIEnv* env, LocalRefMapType &localRefs);
|
||||
|
||||
static std::string getJNISignature() {
|
||||
return "";
|
||||
}
|
||||
|
||||
static std::string getJNISignature(bool) {
|
||||
return "Z";
|
||||
}
|
||||
|
||||
// jchar is unsigned 16 bits, we do char => jchar conversion on purpose
|
||||
static std::string getJNISignature(char) {
|
||||
return "C";
|
||||
}
|
||||
|
||||
static std::string getJNISignature(jshort) {
|
||||
return "S";
|
||||
}
|
||||
|
||||
static std::string getJNISignature(jint) {
|
||||
return "I";
|
||||
}
|
||||
|
||||
static std::string getJNISignature(jlong) {
|
||||
return "J";
|
||||
}
|
||||
|
||||
static std::string getJNISignature(jfloat) {
|
||||
return "F";
|
||||
}
|
||||
|
||||
static std::string getJNISignature(jdouble) {
|
||||
return "D";
|
||||
}
|
||||
|
||||
static std::string getJNISignature(jbyteArray) {
|
||||
return "[B";
|
||||
}
|
||||
|
||||
static std::string getJNISignature(const char*) {
|
||||
return "Ljava/lang/String;";
|
||||
}
|
||||
|
||||
static std::string getJNISignature(const std::string&) {
|
||||
return "Ljava/lang/String;";
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static std::string getJNISignature(T x) {
|
||||
// This template should never be instantiated
|
||||
static_assert(sizeof(x) == 0, "Unsupported argument type");
|
||||
return "";
|
||||
}
|
||||
|
||||
template <typename T, typename... Ts>
|
||||
static std::string getJNISignature(T x, Ts... xs) {
|
||||
return getJNISignature(x) + getJNISignature(xs...);
|
||||
}
|
||||
|
||||
static void reportError(const std::string& className, const std::string& methodName, const std::string& signature);
|
||||
};
|
||||
|
||||
NS_CC_END
|
||||
|
||||
#endif // __ANDROID_JNI_HELPER_H__
|
680
cocos2d-x/cocos/platform/android/jni/JniImp.cpp
Normal file
680
cocos2d-x/cocos/platform/android/jni/JniImp.cpp
Normal file
@@ -0,0 +1,680 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated engine source code (the "Software"), a limited,
|
||||
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
|
||||
to use Cocos Creator solely to develop games on your target platforms. You shall
|
||||
not use Cocos Creator software for developing other software or tools that's
|
||||
used for developing games. You are not granted to publish, distribute,
|
||||
sublicense, and/or sell copies of Cocos Creator.
|
||||
|
||||
The software or tools in this License Agreement are licensed, not sold.
|
||||
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
#include "JniImp.h"
|
||||
#include <unordered_map>
|
||||
#include <android/log.h>
|
||||
#include <android/asset_manager_jni.h>
|
||||
#include <jni.h>
|
||||
#include <mutex>
|
||||
#include "JniHelper.h"
|
||||
#include "platform/CCApplication.h"
|
||||
#include "scripting/js-bindings/jswrapper/SeApi.h"
|
||||
#include "scripting/js-bindings/event/EventDispatcher.h"
|
||||
#include "platform/android/CCFileUtils-android.h"
|
||||
#include "base/CCScheduler.h"
|
||||
#include "base/CCAutoreleasePool.h"
|
||||
#include "base/CCGLUtils.h"
|
||||
|
||||
#define JNI_IMP_LOG_TAG "JniImp"
|
||||
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,JNI_IMP_LOG_TAG,__VA_ARGS__)
|
||||
|
||||
#ifndef ORG_RENDER_CLASS_NAME
|
||||
#define ORG_RENDER_CLASS_NAME org_cocos2dx_lib_Cocos2dxRenderer
|
||||
#endif
|
||||
#define JNI_RENDER(FUNC) JNI_METHOD1(ORG_RENDER_CLASS_NAME,FUNC)
|
||||
|
||||
#ifndef ORG_ACTIVITY_CLASS_NAME
|
||||
#define ORG_ACTIVITY_CLASS_NAME org_cocos2dx_lib_Cocos2dxActivity
|
||||
#endif
|
||||
#define JNI_ACTIVITY(FUNC) JNI_METHOD1(ORG_ACTIVITY_CLASS_NAME,FUNC)
|
||||
|
||||
#ifndef ORG_ACCELEROMETER_CLASS_NAME
|
||||
#define ORG_ACCELEROMETER_CLASS_NAME org_cocos2dx_lib_Cocos2dxAccelerometer
|
||||
#endif
|
||||
#define JNI_ACCELEROMETER(FUNC) JNI_METHOD1(ORG_ACCELEROMETER_CLASS_NAME,FUNC)
|
||||
|
||||
#ifndef ORG_HELPER_CLASS_NAME
|
||||
#define ORG_HELPER_CLASS_NAME org_cocos2dx_lib_Cocos2dxHelper
|
||||
#endif
|
||||
#define JNI_HELPER(FUNC) JNI_METHOD1(ORG_HELPER_CLASS_NAME,FUNC)
|
||||
|
||||
#ifndef ORG_AUDIOFOCUS_CLASS_NAME
|
||||
#define ORG_AUDIOFOCUS_CLASS_NAME org_cocos2dx_lib_Cocos2dxAudioFocusManager
|
||||
#endif
|
||||
#define JNI_AUDIO(FUNC) JNI_METHOD1(ORG_AUDIOFOCUS_CLASS_NAME,FUNC)
|
||||
|
||||
#ifndef JCLS_HELPER
|
||||
#define JCLS_HELPER "org/cocos2dx/lib/Cocos2dxHelper"
|
||||
#endif
|
||||
|
||||
#ifndef JCLS_RENDERER
|
||||
#define JCLS_RENDERER "org/cocos2dx/lib/Cocos2dxRenderer"
|
||||
#endif
|
||||
|
||||
|
||||
#define KEYCODE_BACK 0x04
|
||||
#define KEYCODE_MENU 0x52
|
||||
#define KEYCODE_DPAD_UP 0x13
|
||||
#define KEYCODE_DPAD_DOWN 0x14
|
||||
#define KEYCODE_DPAD_LEFT 0x15
|
||||
#define KEYCODE_DPAD_RIGHT 0x16
|
||||
#define KEYCODE_ENTER 0x42
|
||||
#define KEYCODE_DPAD_CENTER 0x17
|
||||
|
||||
using namespace cocos2d;
|
||||
|
||||
extern uint32_t __jsbInvocationCount;
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
bool __isOpenDebugView = false;
|
||||
bool __isGLOptModeEnabled = true;
|
||||
std::string g_apkPath;
|
||||
EditTextCallback s_editTextCallback = nullptr;
|
||||
void* s_ctx = nullptr;
|
||||
int g_deviceSampleRate = 44100;
|
||||
int g_deviceAudioBufferSizeInFrames = 192;
|
||||
int g_width = 0;
|
||||
int g_height = 0;
|
||||
bool g_isStarted = false;
|
||||
bool g_isGameFinished = false;
|
||||
int g_SDKInt = 0;
|
||||
|
||||
cocos2d::Application* g_app = nullptr;
|
||||
|
||||
bool setCanvasCallback(se::Object* global)
|
||||
{
|
||||
se::AutoHandleScope scope;
|
||||
se::ScriptEngine* se = se::ScriptEngine::getInstance();
|
||||
char commandBuf[200] = {0};
|
||||
uint8_t devicePixelRatio = Application::getInstance()->getDevicePixelRatio();
|
||||
sprintf(commandBuf, "window.innerWidth = %d; window.innerHeight = %d;",
|
||||
g_width / devicePixelRatio,
|
||||
g_height / devicePixelRatio);
|
||||
se->evalString(commandBuf);
|
||||
glViewport(0, 0, g_width / devicePixelRatio, g_height / devicePixelRatio);
|
||||
glDepthMask(GL_TRUE);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void cocos_jni_env_init (JNIEnv* env);
|
||||
|
||||
Application* cocos_android_app_init(JNIEnv* env, int width, int height);
|
||||
|
||||
extern "C"
|
||||
{
|
||||
void getSDKInt(JNIEnv* env)
|
||||
{
|
||||
if (env && g_SDKInt == 0)
|
||||
{
|
||||
// VERSION is a nested class within android.os.Build (hence "$" rather than "/")
|
||||
jclass versionClass = env->FindClass("android/os/Build$VERSION");
|
||||
if (NULL == versionClass)
|
||||
return;
|
||||
|
||||
jfieldID sdkIntFieldID = env->GetStaticFieldID(versionClass, "SDK_INT", "I");
|
||||
if (NULL == sdkIntFieldID)
|
||||
return;
|
||||
|
||||
g_SDKInt = env->GetStaticIntField(versionClass, sdkIntFieldID);
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved)
|
||||
{
|
||||
JniHelper::setJavaVM(vm);
|
||||
cocos_jni_env_init(JniHelper::getEnv());
|
||||
getSDKInt(JniHelper::getEnv());
|
||||
|
||||
return JNI_VERSION_1_4;
|
||||
}
|
||||
|
||||
/*****************************************************
|
||||
* Cocos2dxActivity native functions implementation.
|
||||
*****************************************************/
|
||||
|
||||
JNIEXPORT jintArray JNICALL JNI_ACTIVITY(getGLContextAttrs)(JNIEnv* env, jobject thiz)
|
||||
{
|
||||
//REFINE
|
||||
int tmp[7] = {8, 8, 8,
|
||||
8, 0, 0, 0};
|
||||
jintArray glContextAttrsJava = env->NewIntArray(7);
|
||||
env->SetIntArrayRegion(glContextAttrsJava, 0, 7, tmp);
|
||||
|
||||
return glContextAttrsJava;
|
||||
}
|
||||
|
||||
/*****************************************************
|
||||
* Cocos2dxRenderer native functions implementation.
|
||||
*****************************************************/
|
||||
|
||||
JNIEXPORT void JNICALL JNI_RENDER(nativeInit)(JNIEnv* env, jobject thiz, jint w, jint h, jstring jDefaultResourcePath)
|
||||
{
|
||||
g_width = w;
|
||||
g_height = h;
|
||||
|
||||
g_app = cocos_android_app_init(env, w, h);
|
||||
|
||||
g_isGameFinished = false;
|
||||
ccInvalidateStateCache();
|
||||
std::string defaultResourcePath = JniHelper::jstring2string(jDefaultResourcePath);
|
||||
LOGD("nativeInit: %d, %d, %s", w, h, defaultResourcePath.c_str());
|
||||
|
||||
|
||||
if (!defaultResourcePath.empty())
|
||||
FileUtils::getInstance()->setDefaultResourceRootPath(defaultResourcePath);
|
||||
|
||||
se::ScriptEngine* se = se::ScriptEngine::getInstance();
|
||||
se->addRegisterCallback(setCanvasCallback);
|
||||
|
||||
EventDispatcher::init();
|
||||
|
||||
g_app->start();
|
||||
g_isStarted = true;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL JNI_RENDER(nativeRender)(JNIEnv* env)
|
||||
{
|
||||
if (g_isGameFinished)
|
||||
{
|
||||
// with Application destructor called, native resource will be released
|
||||
delete g_app;
|
||||
g_app = nullptr;
|
||||
|
||||
JniHelper::callStaticVoidMethod(JCLS_HELPER, "endApplication");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (!g_isStarted)
|
||||
{
|
||||
auto scheduler = Application::getInstance()->getScheduler();
|
||||
scheduler->removeAllFunctionsToBePerformedInCocosThread();
|
||||
scheduler->unscheduleAll();
|
||||
|
||||
se::ScriptEngine::getInstance()->cleanup();
|
||||
cocos2d::PoolManager::getInstance()->getCurrentPool()->clear();
|
||||
|
||||
//REFINE: Wait HttpClient, WebSocket, Audio thread to exit
|
||||
|
||||
ccInvalidateStateCache();
|
||||
|
||||
se::ScriptEngine* se = se::ScriptEngine::getInstance();
|
||||
se->addRegisterCallback(setCanvasCallback);
|
||||
|
||||
EventDispatcher::init();
|
||||
|
||||
if(!g_app->applicationDidFinishLaunching())
|
||||
{
|
||||
g_isGameFinished = true;
|
||||
return;
|
||||
}
|
||||
|
||||
g_isStarted = true;
|
||||
}
|
||||
|
||||
static std::chrono::steady_clock::time_point prevTime;
|
||||
static std::chrono::steady_clock::time_point now;
|
||||
static float dt = 0.f;
|
||||
static float dtSum = 0.f;
|
||||
static uint32_t jsbInvocationTotalCount = 0;
|
||||
static uint32_t jsbInvocationTotalFrames = 0;
|
||||
bool downsampleEnabled = g_app->isDownsampleEnabled();
|
||||
|
||||
if (downsampleEnabled)
|
||||
g_app->getRenderTexture()->prepare();
|
||||
|
||||
g_app->getScheduler()->update(dt);
|
||||
EventDispatcher::dispatchTickEvent(dt);
|
||||
|
||||
if (downsampleEnabled)
|
||||
g_app->getRenderTexture()->draw();
|
||||
|
||||
PoolManager::getInstance()->getCurrentPool()->clear();
|
||||
|
||||
now = std::chrono::steady_clock::now();
|
||||
dt = std::chrono::duration_cast<std::chrono::microseconds>(now - prevTime).count() / 1000000.f;
|
||||
|
||||
prevTime = std::chrono::steady_clock::now();
|
||||
|
||||
if (__isOpenDebugView)
|
||||
{
|
||||
dtSum += dt;
|
||||
++jsbInvocationTotalFrames;
|
||||
jsbInvocationTotalCount += __jsbInvocationCount;
|
||||
|
||||
if (dtSum > 1.0f)
|
||||
{
|
||||
dtSum = 0.0f;
|
||||
setJSBInvocationCountJNI(jsbInvocationTotalCount / jsbInvocationTotalFrames);
|
||||
jsbInvocationTotalCount = 0;
|
||||
jsbInvocationTotalFrames = 0;
|
||||
}
|
||||
}
|
||||
__jsbInvocationCount = 0;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL JNI_RENDER(nativeOnPause)()
|
||||
{
|
||||
if (g_isGameFinished) {
|
||||
return;
|
||||
}
|
||||
if (g_app)
|
||||
g_app->onPause();
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL JNI_RENDER(nativeOnResume)()
|
||||
{
|
||||
if (g_isGameFinished) {
|
||||
return;
|
||||
}
|
||||
if (g_app)
|
||||
g_app->onResume();
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL JNI_RENDER(nativeInsertText)(JNIEnv* env, jobject thiz, jstring text)
|
||||
{
|
||||
//REFINE
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL JNI_RENDER(nativeDeleteBackward)(JNIEnv* env, jobject thiz)
|
||||
{
|
||||
//REFINE
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL JNI_RENDER(nativeGetContentText)()
|
||||
{
|
||||
//REFINE
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL JNI_RENDER(nativeOnSurfaceChanged)(JNIEnv* env, jobject thiz, jint w, jint h)
|
||||
{
|
||||
//REFINE
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
* Cocos2dxAccelerometer native functions implementation.
|
||||
***********************************************************/
|
||||
|
||||
JNIEXPORT void JNICALL JNI_ACCELEROMETER(onSensorChanged)(JNIEnv* env, jobject thiz, jfloat x, jfloat y, jfloat z, jlong timeStamp)
|
||||
{
|
||||
//REFINE
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
* Touches native functions implementation.
|
||||
***********************************************************/
|
||||
|
||||
static void dispatchTouchEventWithOnePoint(JNIEnv* env, cocos2d::TouchEvent::Type type, jint id, jfloat x, jfloat y)
|
||||
{
|
||||
if (g_isGameFinished) {
|
||||
return;
|
||||
}
|
||||
cocos2d::TouchEvent touchEvent;
|
||||
touchEvent.type = type;
|
||||
|
||||
uint8_t devicePixelRatio = Application::getInstance()->getDevicePixelRatio();
|
||||
cocos2d::TouchInfo touchInfo;
|
||||
touchInfo.index = id;
|
||||
touchInfo.x = x / devicePixelRatio;
|
||||
touchInfo.y = y / devicePixelRatio;
|
||||
touchEvent.touches.push_back(touchInfo);
|
||||
|
||||
cocos2d::EventDispatcher::dispatchTouchEvent(touchEvent);
|
||||
}
|
||||
|
||||
static void dispatchTouchEventWithPoints(JNIEnv* env, cocos2d::TouchEvent::Type type, jintArray ids, jfloatArray xs, jfloatArray ys)
|
||||
{
|
||||
if (g_isGameFinished) {
|
||||
return;
|
||||
}
|
||||
cocos2d::TouchEvent touchEvent;
|
||||
touchEvent.type = type;
|
||||
|
||||
int size = env->GetArrayLength(ids);
|
||||
jint id[size];
|
||||
jfloat x[size];
|
||||
jfloat y[size];
|
||||
|
||||
env->GetIntArrayRegion(ids, 0, size, id);
|
||||
env->GetFloatArrayRegion(xs, 0, size, x);
|
||||
env->GetFloatArrayRegion(ys, 0, size, y);
|
||||
|
||||
uint8_t devicePixelRatio = Application::getInstance()->getDevicePixelRatio();
|
||||
for(int i = 0; i < size; i++)
|
||||
{
|
||||
cocos2d::TouchInfo touchInfo;
|
||||
touchInfo.index = id[i];
|
||||
touchInfo.x = x[i] / devicePixelRatio;
|
||||
touchInfo.y = y[i] / devicePixelRatio;
|
||||
touchEvent.touches.push_back(touchInfo);
|
||||
}
|
||||
|
||||
cocos2d::EventDispatcher::dispatchTouchEvent(touchEvent);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL JNI_RENDER(nativeTouchesBegin)(JNIEnv * env, jobject thiz, jint id, jfloat x, jfloat y)
|
||||
{
|
||||
if (g_isGameFinished) {
|
||||
return;
|
||||
}
|
||||
dispatchTouchEventWithOnePoint(env, cocos2d::TouchEvent::Type::BEGAN, id, x, y);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL JNI_RENDER(nativeTouchesEnd)(JNIEnv * env, jobject thiz, jint id, jfloat x, jfloat y)
|
||||
{
|
||||
if (g_isGameFinished) {
|
||||
return;
|
||||
}
|
||||
dispatchTouchEventWithOnePoint(env, cocos2d::TouchEvent::Type::ENDED, id, x, y);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL JNI_RENDER(nativeTouchesMove)(JNIEnv * env, jobject thiz, jintArray ids, jfloatArray xs, jfloatArray ys)
|
||||
{
|
||||
if (g_isGameFinished) {
|
||||
return;
|
||||
}
|
||||
dispatchTouchEventWithPoints(env, cocos2d::TouchEvent::Type::MOVED, ids, xs, ys);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL JNI_RENDER(nativeTouchesCancel)(JNIEnv * env, jobject thiz, jintArray ids, jfloatArray xs, jfloatArray ys)
|
||||
{
|
||||
if (g_isGameFinished) {
|
||||
return;
|
||||
}
|
||||
dispatchTouchEventWithPoints(env, cocos2d::TouchEvent::Type::CANCELLED, ids, xs, ys);
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL JNI_RENDER(nativeKeyEvent)(JNIEnv * env, jobject thiz, jint keyCode, jboolean isPressed)
|
||||
{
|
||||
if (g_isGameFinished) {
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
int keyInWeb = -1;
|
||||
// key values in web, refer to http://docs.cocos.com/creator/api/en/enums/KEY.html
|
||||
switch(keyCode)
|
||||
{
|
||||
case KEYCODE_BACK:
|
||||
keyInWeb = 6;
|
||||
break;
|
||||
case KEYCODE_ENTER:
|
||||
keyInWeb = 13;
|
||||
break;
|
||||
case KEYCODE_MENU:
|
||||
keyInWeb = 18;
|
||||
break;
|
||||
case KEYCODE_DPAD_UP:
|
||||
keyInWeb = 1003;
|
||||
break;
|
||||
case KEYCODE_DPAD_DOWN:
|
||||
keyInWeb = 1004;
|
||||
break;
|
||||
case KEYCODE_DPAD_LEFT:
|
||||
keyInWeb = 1000;
|
||||
break;
|
||||
case KEYCODE_DPAD_RIGHT:
|
||||
keyInWeb = 1001;
|
||||
break;
|
||||
case KEYCODE_DPAD_CENTER:
|
||||
keyInWeb = 1005;
|
||||
break;
|
||||
default:
|
||||
keyInWeb = 0; // If the key can't be identified, this value is 0
|
||||
}
|
||||
KeyboardEvent event;
|
||||
event.key = keyInWeb;
|
||||
event.action = isPressed ? KeyboardEvent::Action::PRESS : KeyboardEvent::Action::RELEASE;
|
||||
EventDispatcher::dispatchKeyboardEvent(event);
|
||||
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
* Cocos2dxHelper native functions implementation.
|
||||
***********************************************************/
|
||||
|
||||
JNIEXPORT void JNICALL JNI_HELPER(nativeSetApkPath)(JNIEnv* env, jobject thiz, jstring apkPath)
|
||||
{
|
||||
g_apkPath = JniHelper::jstring2string(apkPath);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL JNI_HELPER(nativeSetContext)(JNIEnv* env, jobject thiz, jobject context, jobject assetManager)
|
||||
{
|
||||
JniHelper::setClassLoaderFrom(context);
|
||||
FileUtilsAndroid::setassetmanager(AAssetManager_fromJava(env, assetManager));
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL JNI_HELPER(nativeSetAudioDeviceInfo)(JNIEnv* env, jobject thiz, jboolean isSupportLowLatency, jint deviceSampleRate, jint deviceAudioBufferSizeInFrames)
|
||||
{
|
||||
g_deviceSampleRate = deviceSampleRate;
|
||||
g_deviceAudioBufferSizeInFrames = deviceAudioBufferSizeInFrames;
|
||||
LOGD("nativeSetAudioDeviceInfo: sampleRate: %d, bufferSizeInFrames: %d", g_deviceSampleRate, g_deviceAudioBufferSizeInFrames);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL JNI_HELPER(nativeSetEditTextDialogResult)(JNIEnv* env, jobject obj, jbyteArray text)
|
||||
{
|
||||
jsize size = env->GetArrayLength(text);
|
||||
|
||||
if (size > 0)
|
||||
{
|
||||
jbyte * data = (jbyte*)env->GetByteArrayElements(text, 0);
|
||||
char* buffer = (char*)malloc(size+1);
|
||||
if (buffer != nullptr)
|
||||
{
|
||||
memcpy(buffer, data, size);
|
||||
buffer[size] = '\0';
|
||||
// pass data to edittext's delegate
|
||||
if (s_editTextCallback)
|
||||
s_editTextCallback(buffer, s_ctx);
|
||||
free(buffer);
|
||||
}
|
||||
env->ReleaseByteArrayElements(text, data, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (s_editTextCallback)
|
||||
s_editTextCallback("", s_ctx);
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
* Cocos2dxAudioFocusManager native functions implementation.
|
||||
***********************************************************/
|
||||
|
||||
JNIEXPORT void JNICALL JNI_AUDIO(nativeOnAudioFocusChange)(JNIEnv* env, jobject thiz, jint focusChange)
|
||||
{
|
||||
// cocos_audioengine_focus_change(focusChange);
|
||||
}
|
||||
} // end of extern "C"
|
||||
|
||||
void restartJSVM()
|
||||
{
|
||||
g_isStarted = false;
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
* Functions invoke from cpp to Java.
|
||||
***********************************************************/
|
||||
|
||||
std::string getApkPathJNI()
|
||||
{
|
||||
return g_apkPath;
|
||||
}
|
||||
|
||||
std::string getPackageNameJNI()
|
||||
{
|
||||
return JniHelper::callStaticStringMethod(JCLS_HELPER, "getPackageName");
|
||||
}
|
||||
|
||||
int getObbAssetFileDescriptorJNI(const std::string& path, long* startOffset, long* size)
|
||||
{
|
||||
JniMethodInfo methodInfo;
|
||||
int fd = 0;
|
||||
|
||||
if (JniHelper::getStaticMethodInfo(methodInfo, JCLS_HELPER, "getObbAssetFileDescriptor", "(Ljava/lang/String;)[J"))
|
||||
{
|
||||
jstring stringArg = methodInfo.env->NewStringUTF(path.c_str());
|
||||
jlongArray newArray = (jlongArray)methodInfo.env->CallStaticObjectMethod(methodInfo.classID, methodInfo.methodID, stringArg);
|
||||
jsize theArrayLen = methodInfo.env->GetArrayLength(newArray);
|
||||
|
||||
if (3 == theArrayLen)
|
||||
{
|
||||
jboolean copy = JNI_FALSE;
|
||||
jlong *array = methodInfo.env->GetLongArrayElements(newArray, ©);
|
||||
fd = static_cast<int>(array[0]);
|
||||
*startOffset = array[1];
|
||||
*size = array[2];
|
||||
methodInfo.env->ReleaseLongArrayElements(newArray, array, 0);
|
||||
}
|
||||
|
||||
methodInfo.env->DeleteLocalRef(methodInfo.classID);
|
||||
methodInfo.env->DeleteLocalRef(stringArg);
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
int getDeviceSampleRateJNI()
|
||||
{
|
||||
return g_deviceSampleRate;
|
||||
}
|
||||
|
||||
int getDeviceAudioBufferSizeInFramesJNI()
|
||||
{
|
||||
return g_deviceAudioBufferSizeInFrames;
|
||||
}
|
||||
|
||||
void convertEncodingJNI(const std::string& src, int byteSize, const std::string& fromCharset, std::string& dst, const std::string& newCharset)
|
||||
{
|
||||
JniMethodInfo methodInfo;
|
||||
|
||||
if (JniHelper::getStaticMethodInfo(methodInfo, JCLS_HELPER, "conversionEncoding", "([BLjava/lang/String;Ljava/lang/String;)[B"))
|
||||
{
|
||||
jbyteArray strArray = methodInfo.env->NewByteArray(byteSize);
|
||||
methodInfo.env->SetByteArrayRegion(strArray, 0, byteSize, reinterpret_cast<const jbyte*>(src.c_str()));
|
||||
|
||||
jstring stringArg1 = methodInfo.env->NewStringUTF(fromCharset.c_str());
|
||||
jstring stringArg2 = methodInfo.env->NewStringUTF(newCharset.c_str());
|
||||
|
||||
jbyteArray newArray = (jbyteArray)methodInfo.env->CallStaticObjectMethod(methodInfo.classID, methodInfo.methodID, strArray, stringArg1, stringArg2);
|
||||
jsize theArrayLen = methodInfo.env->GetArrayLength(newArray);
|
||||
methodInfo.env->GetByteArrayRegion(newArray, 0, theArrayLen, (jbyte*)dst.c_str());
|
||||
|
||||
methodInfo.env->DeleteLocalRef(strArray);
|
||||
methodInfo.env->DeleteLocalRef(stringArg1);
|
||||
methodInfo.env->DeleteLocalRef(stringArg2);
|
||||
methodInfo.env->DeleteLocalRef(newArray);
|
||||
methodInfo.env->DeleteLocalRef(methodInfo.classID);
|
||||
}
|
||||
}
|
||||
|
||||
std::string getCurrentLanguageJNI()
|
||||
{
|
||||
return JniHelper::callStaticStringMethod(JCLS_HELPER, "getCurrentLanguage");
|
||||
}
|
||||
|
||||
std::string getCurrentLanguageCodeJNI()
|
||||
{
|
||||
return JniHelper::callStaticStringMethod(JCLS_HELPER, "getCurrentLanguageCode");
|
||||
}
|
||||
|
||||
std::string getSystemVersionJNI()
|
||||
{
|
||||
return JniHelper::callStaticStringMethod(JCLS_HELPER, "getSystemVersion");
|
||||
}
|
||||
|
||||
bool openURLJNI(const std::string& url)
|
||||
{
|
||||
return JniHelper::callStaticBooleanMethod(JCLS_HELPER, "openURL", url);
|
||||
}
|
||||
|
||||
void copyTextToClipboardJNI(const std::string& text)
|
||||
{
|
||||
JniHelper::callStaticVoidMethod(JCLS_HELPER, "copyTextToClipboard", text);
|
||||
}
|
||||
|
||||
void setPreferredFramesPerSecondJNI(int fps)
|
||||
{
|
||||
JniHelper::callStaticVoidMethod(JCLS_RENDERER, "setPreferredFramesPerSecond", fps);
|
||||
}
|
||||
|
||||
void setGameInfoDebugViewTextJNI(int index, const std::string& text)
|
||||
{
|
||||
if (!__isOpenDebugView)
|
||||
return;
|
||||
JniHelper::callStaticVoidMethod(JCLS_HELPER, "setGameInfoDebugViewText", index, text);
|
||||
}
|
||||
|
||||
void setJSBInvocationCountJNI(int count)
|
||||
{
|
||||
if (!__isOpenDebugView)
|
||||
return;
|
||||
JniHelper::callStaticVoidMethod(JCLS_HELPER, "setJSBInvocationCount", count);
|
||||
}
|
||||
|
||||
void openDebugViewJNI()
|
||||
{
|
||||
if (!__isOpenDebugView)
|
||||
{
|
||||
LOGD("openDebugViewJNI ...");
|
||||
__isOpenDebugView = true;
|
||||
JniHelper::callStaticVoidMethod(JCLS_HELPER, "openDebugView");
|
||||
if (!__isGLOptModeEnabled)
|
||||
{
|
||||
JniHelper::callStaticVoidMethod(JCLS_HELPER, "disableBatchGLCommandsToNative");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void disableBatchGLCommandsToNativeJNI()
|
||||
{
|
||||
__isGLOptModeEnabled = false;
|
||||
if (__isOpenDebugView)
|
||||
{
|
||||
JniHelper::callStaticVoidMethod(JCLS_HELPER, "disableBatchGLCommandsToNative");
|
||||
}
|
||||
}
|
||||
|
||||
void exitApplication()
|
||||
{
|
||||
g_isGameFinished = true;
|
||||
}
|
||||
|
||||
|
||||
bool getApplicationExited()
|
||||
{
|
||||
return g_isGameFinished;
|
||||
}
|
||||
|
||||
int getAndroidSDKInt()
|
||||
{
|
||||
return g_SDKInt;
|
||||
}
|
||||
|
||||
|
54
cocos2d-x/cocos/platform/android/jni/JniImp.h
Normal file
54
cocos2d-x/cocos/platform/android/jni/JniImp.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated engine source code (the "Software"), a limited,
|
||||
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
|
||||
to use Cocos Creator solely to develop games on your target platforms. You shall
|
||||
not use Cocos Creator software for developing other software or tools that's
|
||||
used for developing games. You are not granted to publish, distribute,
|
||||
sublicense, and/or sell copies of Cocos Creator.
|
||||
|
||||
The software or tools in this License Agreement are licensed, not sold.
|
||||
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
typedef void (*EditTextCallback)(const std::string& text, void* ctx);
|
||||
|
||||
extern bool getApplicationExited();
|
||||
|
||||
extern void restartJSVM();
|
||||
extern void exitApplication();
|
||||
|
||||
extern std::string getApkPathJNI();
|
||||
extern std::string getPackageNameJNI();
|
||||
extern int getObbAssetFileDescriptorJNI(const std::string& path, long* startOffset, long* size);
|
||||
extern void convertEncodingJNI(const std::string& src, int byteSize, const std::string& fromCharset, std::string& dst, const std::string& newCharset);
|
||||
|
||||
extern int getDeviceSampleRateJNI();
|
||||
extern int getDeviceAudioBufferSizeInFramesJNI();
|
||||
|
||||
extern std::string getCurrentLanguageJNI();
|
||||
extern std::string getCurrentLanguageCodeJNI();
|
||||
extern std::string getSystemVersionJNI();
|
||||
extern bool openURLJNI(const std::string& url);
|
||||
extern void copyTextToClipboardJNI(const std::string& text);
|
||||
extern void setPreferredFramesPerSecondJNI(int fps);
|
||||
extern void setGameInfoDebugViewTextJNI(int index, const std::string& text);
|
||||
extern void setJSBInvocationCountJNI(int count);
|
||||
extern void openDebugViewJNI();
|
||||
extern void disableBatchGLCommandsToNativeJNI();
|
||||
extern int getAndroidSDKInt();
|
7
cocos2d-x/cocos/platform/android/libcocos2dx/.gitignore
vendored
Normal file
7
cocos2d-x/cocos/platform/android/libcocos2dx/.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
.gradle
|
||||
/local.properties
|
||||
/.idea/workspace.xml
|
||||
/.idea/libraries
|
||||
.DS_Store
|
||||
/build
|
||||
/captures
|
@@ -0,0 +1,4 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.cocos2dx.lib">
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
</manifest>
|
34
cocos2d-x/cocos/platform/android/libcocos2dx/build.gradle
Normal file
34
cocos2d-x/cocos/platform/android/libcocos2dx/build.gradle
Normal file
@@ -0,0 +1,34 @@
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
compileSdkVersion PROP_COMPILE_SDK_VERSION.toInteger()
|
||||
buildToolsVersion PROP_BUILD_TOOLS_VERSION
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion PROP_MIN_SDK_VERSION
|
||||
targetSdkVersion PROP_TARGET_SDK_VERSION
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
}
|
||||
|
||||
sourceSets.main {
|
||||
aidl.srcDir "../java/src"
|
||||
java.srcDir "../java/src"
|
||||
manifest.srcFile "AndroidManifest.xml"
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(include: ['*.jar'], dir: '../java/libs')
|
||||
}
|
17
cocos2d-x/cocos/platform/android/libcocos2dx/proguard-rules.pro
vendored
Normal file
17
cocos2d-x/cocos/platform/android/libcocos2dx/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# By default, the flags in this file are appended to flags specified
|
||||
# in E:\developSoftware\Android\SDK/tools/proguard/proguard-android.txt
|
||||
# You can edit the include path and order by changing the proguardFiles
|
||||
# directive in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# Add any project specific keep options here:
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!--EditBox Confirm Button Name-->
|
||||
<string name="done" translatable="false">完成</string>
|
||||
<string name="next" translatable="false">下一个</string>
|
||||
<string name="search" translatable="false">搜索</string>
|
||||
<string name="go" translatable="false">前往</string>
|
||||
<string name="send" translatable="false">发送</string>
|
||||
</resources>
|
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!--EditBox Confirm Button Title-->
|
||||
<string name="done" translatable="false">Done</string>
|
||||
<string name="next" translatable="false">Next</string>
|
||||
<string name="search" translatable="false">Search</string>
|
||||
<string name="go" translatable="false">Go</string>
|
||||
<string name="send" translatable="false">Send</string>
|
||||
</resources>
|
Reference in New Issue
Block a user