Also start new activity in its own private process.
Change-Id: I4ad00730247ce39d9acf26eabb3f06ecc3d8e8b8
android:label="@string/app_name"
android:name="com.sec.dalidemo.DaliDemoApplication">
+ <activity android:name="com.sec.dalidemo.DaliDemoNativeActivity"
+ android:icon="@mipmap/dali_launcher"
+ android:label="DALi Example"
+ android:screenOrientation="portrait"
+ android:windowSoftInputMode="stateAlwaysVisible"
+ android:process=":example">
+ <!-- Tell NativeActivity the name of our .so -->
+ <meta-data android:name="android.app.lib_name"
+ android:value="native-activity" />
+ <meta-data android:name="start"
+ android:value="blocks.example" />
+ <intent-filter>
+ <action android:name="android.intent.action.RUN" />
+ </intent-filter>
+ </activity>
+
<!-- Our activity is the built-in NativeActivity framework class.
This will take care of integrating with our NDK code. -->
- <activity android:name="com.sec.dalidemo.DaliDemoNativeActivity"
+ <activity android:name="com.sec.dalidemo.DaliDemosNativeActivity"
android:icon="@mipmap/dali_launcher"
android:label="@string/demo_name"
android:screenOrientation="portrait"
- android:windowSoftInputMode="stateAlwaysVisible">
+ android:windowSoftInputMode="stateAlwaysVisible"
+ android:process=":dalidemos">
<!-- Tell NativeActivity the name of our .so -->
<meta-data android:name="android.app.lib_name"
android:value="native-activity" />
android:icon="@mipmap/dali_examples"
android:label="@string/examples_name"
android:screenOrientation="portrait"
- android:windowSoftInputMode="stateAlwaysVisible">
+ android:windowSoftInputMode="stateAlwaysVisible"
+ android:process=":daliexamples">
<!-- Tell NativeActivity the name of our .so -->
<meta-data android:name="android.app.lib_name"
android:value="native-activity" />
android:icon="@mipmap/dali_tests"
android:label="@string/tests_name"
android:screenOrientation="portrait"
- android:windowSoftInputMode="stateAlwaysVisible">
+ android:windowSoftInputMode="stateAlwaysVisible"
+ android:process=":dalitests">
<!-- Tell NativeActivity the name of our .so -->
<meta-data android:name="android.app.lib_name"
android:value="native-activity" />
TARGET_INCLUDE_DIRECTORIES(native-activity PRIVATE
${ANDROID_NDK}/sources/android/native_app_glue)
+INCLUDE_DIRECTORIES(.)
INCLUDE_DIRECTORIES(${DALI_ENV_DIR}/include)
INCLUDE_DIRECTORIES(${DALI_ENV_DIR}/include/dali)
--- /dev/null
+/*
+ * Copyright (c) 2020 Samsung Electronics 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.
+ */
+
+#ifndef ANDROID_DALI_DEMO_NATIVE_ACTIVITY_JNI_H
+#define ANDROID_DALI_DEMO_NATIVE_ACTIVITY_JNI_H
+
+#include <string>
+#include <android_native_app_glue.h>
+
+class DaliDemoNativeActivity
+{
+public:
+ DaliDemoNativeActivity(ANativeActivity* activity)
+ : activity(activity)
+ {
+ }
+
+ class JString
+ {
+ public:
+ JString(JNIEnv* env, const std::string& str)
+ : env(env),
+ string(env->NewStringUTF(str.c_str()))
+ {
+ }
+
+ JString(JNIEnv* env, jstring str)
+ : env(env),
+ string(str)
+ {
+ }
+
+ std::string ToString()
+ {
+ std::string out;
+ if (string)
+ {
+ const char* utf = env->GetStringUTFChars(string, 0);
+ out = std::string(utf);
+ env->ReleaseStringUTFChars(string, utf);
+ }
+ return out;
+ }
+
+ ~JString()
+ {
+ if (string)
+ {
+ env->DeleteLocalRef(string);
+ }
+ }
+
+ private:
+ friend class DaliDemoNativeActivity;
+ JNIEnv* env;
+ jstring string;
+ };
+
+ class NativeActivityJNI
+ {
+ public:
+ NativeActivityJNI(ANativeActivity* activity)
+ : activity(activity)
+ {
+ activity->vm->AttachCurrentThread(&env, nullptr);
+ clazz = env->GetObjectClass(activity->clazz);
+ }
+
+ ~NativeActivityJNI()
+ {
+ activity->vm->DetachCurrentThread();
+ }
+
+ std::string CallStringMethod(const std::string& name, const std::string& arg)
+ {
+ jmethodID methodID = env->GetMethodID(clazz, name.c_str(), "(Ljava/lang/String;)Ljava/lang/String;");
+ JString argument(env, arg);
+ JString returnValue(env, (jstring)env->CallObjectMethod(activity->clazz, methodID, argument.string));
+ return returnValue.ToString();
+ }
+
+ void CallVoidMethod(const std::string& name, const std::string& arg)
+ {
+ jmethodID methodID = env->GetMethodID(clazz, name.c_str(), "(Ljava/lang/String;)V");
+ JString argument(env, arg);
+ env->CallVoidMethod(activity->clazz, methodID, argument.string);
+ }
+
+ private:
+ ANativeActivity* activity;
+ JNIEnv* env;
+ jclass clazz;
+ };
+
+ std::string GetMetaData(const std::string& key)
+ {
+ NativeActivityJNI nativeActivityJNI(activity);
+ return nativeActivityJNI.CallStringMethod("getMetaData", key);
+ }
+
+ std::string GetIntentStringExtra(const std::string& key)
+ {
+ NativeActivityJNI nativeActivityJNI(activity);
+ return nativeActivityJNI.CallStringMethod("getIntentStringExtra", key);
+ }
+
+ void LaunchExample(const std::string& exampleName)
+ {
+ NativeActivityJNI nativeActivityJNI(activity);
+ return nativeActivityJNI.CallVoidMethod("launchExample", exampleName);
+ }
+
+private:
+ ANativeActivity* activity;
+};
+
+#endif //ANDROID_DALI_DEMO_NATIVE_ACTIVITY_JNI_H
#include <android/log.h>
#include <android_native_app_glue.h>
+#include <dali-demo-native-activity-jni.h>
#include <dali/devel-api/adaptor-framework/application-devel.h>
#include <dali/integration-api/debug.h>
#include <dali/integration-api/adaptor-framework/android/android-framework.h>
void free_saved_state(struct android_app *android_app)
{
- pthread_mutex_lock(&android_app->mutex);
+ LOGV("free_saved_state");
+ pthread_mutex_lock(&android_app->mutex);
- if (android_app->savedState != NULL)
- {
- free(android_app->savedState);
- android_app->savedState = NULL;
- android_app->savedStateSize = 0;
- }
+ if (android_app->savedState != NULL)
+ {
+ free(android_app->savedState);
+ android_app->savedState = NULL;
+ android_app->savedStateSize = 0;
+ }
- pthread_mutex_unlock(&android_app->mutex);
+ pthread_mutex_unlock(&android_app->mutex);
}
void android_app_destroy(struct android_app *android_app)
}
}
-class DaliDemoNativeActivity
-{
-public:
- ANativeActivity* activity;
- DaliDemoNativeActivity(ANativeActivity* activity)
- : activity(activity)
- {
- }
-
- class NativeActivityJNI
- {
- public:
- ANativeActivity* activity;
- JNIEnv* env;
- jclass clazz;
-
- NativeActivityJNI(ANativeActivity* activity)
- : activity(activity)
- {
- activity->vm->AttachCurrentThread(&env, NULL);
- clazz = env->GetObjectClass(activity->clazz);
- }
-
- ~NativeActivityJNI()
- {
- activity->vm->DetachCurrentThread();
- }
-
- jstring toJString(const std::string& str)
- {
- return env->NewStringUTF(str.c_str());
- }
-
- std::string toString(jstring jstr)
- {
- std::string out;
- if (jstr)
- {
- const char* utf = env->GetStringUTFChars(jstr, 0);
- out = std::string(utf);
- env->ReleaseStringUTFChars(jstr, utf);
- }
-
- return out;
- }
-
- std::string callStringMethod(const std::string& name, const std::string& arg)
- {
- jmethodID methodID = env->GetMethodID(clazz, name.c_str(), "(Ljava/lang/String;)Ljava/lang/String;");
- jstring jstr = (jstring)env->CallObjectMethod(activity->clazz, methodID, toJString(arg));
- return toString(jstr);
- }
- };
-
- std::string getMetaData(const std::string& key)
- {
- NativeActivityJNI nativeActivityJNI(activity);
- return nativeActivityJNI.callStringMethod("getMetaData", key);
- }
-
- std::string getIntentStringExtra(const std::string& key)
- {
- NativeActivityJNI nativeActivityJNI(activity);
- return nativeActivityJNI.callStringMethod("getIntentStringExtra", key);
- }
-};
-
extern "C" void FcConfigPathInit(const char* path, const char* file);
void android_main( struct android_app* state )
{
+ LOGV("android_main() >>");
+
std::string filesDir = state->activity->internalDataPath;
std::string fontconfigPath = filesDir + "/fonts";
}
Dali::Integration::AndroidFramework::New();
- Dali::Integration::AndroidFramework::Get().SetNativeApplication( state );
- Dali::Integration::AndroidFramework::Get().SetApplicationConfiguration( state->config );
- Dali::Integration::AndroidFramework::Get().SetApplicationAssets( state->activity->assetManager );
- Dali::Integration::AndroidFramework::Get().SetInternalDataPath( filesDir );
+ Dali::Integration::AndroidFramework::Get().SetNativeApplication(state);
+ Dali::Integration::AndroidFramework::Get().SetApplicationConfiguration(state->config);
+ Dali::Integration::AndroidFramework::Get().SetApplicationAssets(state->activity->assetManager);
+ Dali::Integration::AndroidFramework::Get().SetInternalDataPath(filesDir);
DaliDemoNativeActivity nativeActivity(state->activity);
int status = 0;
std::string libpath = "/data/data/com.sec.dalidemo/lib/libdali-demo.so";
- std::string callParam = nativeActivity.getIntentStringExtra("start");
+ std::string callParam = nativeActivity.GetIntentStringExtra("start");
if (callParam.empty())
{
- callParam = nativeActivity.getMetaData("start");
+ callParam = nativeActivity.GetMetaData("start");
}
if (!callParam.empty())
libpath = "/data/data/com.sec.dalidemo/lib/lib" + callParam + ".so";
}
- void* handle = dlopen( libpath.c_str(), RTLD_LAZY );
+ void* handle = dlopen(libpath.c_str(), RTLD_LAZY);
if (!handle)
{
std::exit(status);
Dali::Integration::AndroidFramework::Get().SetApplicationAssets(nullptr);
Dali::Integration::AndroidFramework::Delete();
- // We need to kill the application process manually, DALi cannot restart in the same process due to memory leaks
+ LOGV("android_main() <<");
+
+ // We need to kill the application process manually, DALi cannot exit the process properly due to memory leaks
std::exit(status);
}
import android.app.NativeActivity;
import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
public final String getIntentStringExtra(String key) {
return getIntent().getStringExtra(key);
}
+
+ public final void launchExample(String exampleName) {
+ Intent intent = new Intent(this, DaliDemoNativeActivity.class);
+ intent.putExtra("start", exampleName);
+ startActivity(intent);
+ }
}
--- /dev/null
+package com.sec.dalidemo;
+
+public class DaliDemosNativeActivity extends DaliDemoNativeActivity {
+}
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_C_FLAGS}")
INCLUDE_DIRECTORIES(${ROOT_SRC_DIR})
+IF(ANDROID)
+ INCLUDE_DIRECTORIES( ${ANDROID_NDK}/sources/android/native_app_glue )
+ INCLUDE_DIRECTORIES( ${ANDROID_NDK}/sysroot/usr )
+ INCLUDE_DIRECTORIES( ${ANDROID_NDK}/sysroot/usr/include/android )
+ INCLUDE_DIRECTORIES( ${ROOT_SRC_DIR}/build/android/app/src/main/cpp )
+ENDIF()
ADD_SUBDIRECTORY(demo)
ADD_SUBDIRECTORY(examples)
// EXTERNAL INCLUDES
#include <sstream>
#include <unistd.h>
+
#include <dali/public-api/common/dali-common.h>
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/adaptor-framework/android/android-framework.h>
+
+#include <android_native_app_glue.h>
+#include <dali-demo-native-activity-jni.h>
void ExecuteProcess( const std::string& processName, Dali::Application& application )
{
- std::stringstream stream;
- stream << "am start -a android.intent.action.MAIN -n com.sec.dalidemo/.DaliDemoNativeActivity --user 0 --es start " << processName.c_str();
- pid_t parentPID = getpid();
-
- pid_t pid = fork();
- if( pid == 0 )
+ struct android_app* nativeApp = Dali::Integration::AndroidFramework::Get().GetNativeApplication();
+ if (!nativeApp)
{
- do
- {
- sleep( 1 );
- }
- while( kill( parentPID, 0 ) == 0 );
-
- system( stream.str().c_str() );
- exit( 0 );
- }
- else
- {
- application.Quit();
+ DALI_LOG_ERROR("Couldn't get native app.");
+ return;
}
+
+ DaliDemoNativeActivity nativeActivity(nativeApp->activity);
+ nativeActivity.LaunchExample(processName);
}