Merge pull request #14883 from amerhifi/feature/quest

case:21032 Fixing Lifecycle of the android app
This commit is contained in:
Sam Gateau 2019-02-12 12:32:38 -08:00 committed by GitHub
commit a10cf9b620
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 158 additions and 177 deletions

View file

@ -1,3 +1,4 @@
package io.highfidelity.hifiinterface; package io.highfidelity.hifiinterface;
import android.app.Activity; import android.app.Activity;

View file

@ -31,14 +31,9 @@
<category android:name="android.intent.category.INFO" /> <category android:name="android.intent.category.INFO" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity
android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"
android:name=".QuestActivity"
android:launchMode="singleTask"
android:screenOrientation="landscape"/>
<activity <activity
android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|locale|fontScale|keyboard|keyboardHidden|navigation" android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|locale|fontScale|keyboard|keyboardHidden|navigation"
android:name=".MainActivity" android:name="io.highfidelity.oculus.OculusMobileActivity"
android:label="@string/app_name" android:label="@string/app_name"
android:launchMode="singleTask"> android:launchMode="singleTask">
<meta-data android:name="android.app.lib_name" android:value="questInterface"/> <meta-data android:name="android.app.lib_name" android:value="questInterface"/>

View file

@ -37,50 +37,73 @@ void initOculusPlatform(JNIEnv* env, jobject obj) {
}); });
} }
void getClassName(JNIEnv *env, jobject obj){
jclass cls = env->GetObjectClass(obj);
jmethodID mid = env->GetMethodID(cls,"getClass", "()Ljava/lang/Class;");
jobject clsObj = env->CallObjectMethod(obj, mid);
cls= env->GetObjectClass(clsObj);
mid= env->GetMethodID(cls, "getName", "()Ljava/lang/String;");
jstring strObj = (jstring) env->CallObjectMethod(clsObj, mid);
const char* str = env->GetStringUTFChars(strObj, NULL);
__android_log_print(ANDROID_LOG_ERROR,__FUNCTION__, "Native Class call: %s",str);
env->ReleaseStringUTFChars(strObj, str);
}
extern "C" { extern "C" {
JNIEXPORT void JNICALL
Java_io_highfidelity_oculus_OculusMobileActivity_nativeInitOculusPlatform(JNIEnv *env, jobject obj){
initOculusPlatform(env, obj);
}
QAndroidJniObject __interfaceActivity;
JNIEXPORT void JNICALL
Java_io_highfidelity_oculus_OculusMobileActivity_questNativeOnCreate(JNIEnv *env, jobject obj) {
__android_log_print(ANDROID_LOG_INFO, "QQQ", __FUNCTION__);
initOculusPlatform(env, obj);
getClassName(env, obj);
JNIEXPORT void JNICALL __interfaceActivity = QAndroidJniObject(obj);
Java_io_highfidelity_questInterface_MainActivity_nativeInitOculusPlatform(JNIEnv* env, jobject obj) {
initOculusPlatform(env, obj); QObject::connect(&AndroidHelper::instance(), &AndroidHelper::qtAppLoadComplete, []() {
__interfaceActivity.callMethod<void>("onAppLoadedComplete", "()V");
QObject::disconnect(&AndroidHelper::instance(), &AndroidHelper::qtAppLoadComplete,
nullptr,
nullptr);
});
}
JNIEXPORT void Java_io_highfidelity_oculus_OculusMobileActivity_questOnAppAfterLoad(JNIEnv* env, jobject obj) {
AndroidHelper::instance().moveToThread(qApp->thread());
} }
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_io_highfidelity_questInterface_MainActivity_nativeOnCreate(JNIEnv* env, jobject obj) { Java_io_highfidelity_oculus_OculusMobileActivity_questNativeOnDestroy(JNIEnv *env, jobject obj) {
initOculusPlatform(env, obj); }
qRegisterMetaType<QAndroidJniObject>("QAndroidJniObject");
QObject::connect(&AndroidHelper::instance(), &AndroidHelper::qtAppLoadComplete, []() {
qWarning() << "QQQ" << __FUNCTION__ << "scheduling onAppLoadedComplete";
AndroidHelper::instance().moveToThread(qApp->thread());
QtAndroid::androidActivity().callMethod<void>("onAppLoadedComplete", "()V");
QObject::disconnect(&AndroidHelper::instance(), &AndroidHelper::qtAppLoadComplete, nullptr, nullptr);
});
}
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_io_highfidelity_questInterface_MainActivity_nativeOnDestroy(JNIEnv* env, jobject obj) { Java_io_highfidelity_oculus_OculusMobileActivity_questNativeOnPause(JNIEnv *env, jobject obj) {
} AndroidHelper::instance().notifyEnterBackground();
}
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_io_highfidelity_questInterface_SplashActivity_registerLoadCompleteListener(JNIEnv *env, Java_io_highfidelity_oculus_OculusMobileActivity_questNativeOnResume(JNIEnv *env, jobject obj) {
jobject instance) { AndroidHelper::instance().notifyEnterForeground();
}
}
JNIEXPORT void JNICALL
JNIEXPORT void JNICALL Java_io_highfidelity_questInterface_receiver_HeadsetStateReceiver_notifyHeadsetOn(JNIEnv *env,
Java_io_highfidelity_questInterface_MainActivity_nativeOnPause(JNIEnv *env, jobject obj) { jobject instance,
AndroidHelper::instance().notifyEnterBackground(); jboolean pluggedIn) {
} AndroidHelper::instance().notifyHeadsetOn(pluggedIn);
}
JNIEXPORT void JNICALL
Java_io_highfidelity_questInterface_MainActivity_nativeOnResume(JNIEnv *env, jobject obj) {
AndroidHelper::instance().notifyEnterForeground();
}
JNIEXPORT void JNICALL
Java_io_highfidelity_questInterface_receiver_HeadsetStateReceiver_notifyHeadsetOn(JNIEnv *env,
jobject instance,
jboolean pluggedIn) {
AndroidHelper::instance().notifyHeadsetOn(pluggedIn);
}
} }

View file

@ -1,70 +0,0 @@
//
// MainActivity.java
// android/app/src/main/java
//
// Created by Stephen Birarda on 1/26/15.
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
package io.highfidelity.questInterface;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.WindowManager;
import org.qtproject.qt5.android.bindings.QtActivity;
import java.util.Timer;
import java.util.TimerTask;
import io.highfidelity.utils.HifiUtils;
public class MainActivity extends QtActivity {
private native void nativeOnCreate();
private native void nativeOnDestroy();
private native void nativeOnPause();
private native void nativeOnResume();
@Override
public void onCreate(Bundle savedInstanceState) {
super.isLoading = true;
super.keepInterfaceRunning = true;
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
HifiUtils.upackAssets(getAssets(), getCacheDir().getAbsolutePath());
nativeOnCreate();
}
public void onAppLoadedComplete() {
Log.w("QQQ", "Returning to quest activity");
runOnUiThread(()->{
startActivity(new Intent(MainActivity.this, QuestActivity.class));
//moveTaskToBack(true);
});
}
@Override
protected void onPause() {
super.onPause();
if (!super.isLoading) {
nativeOnPause();
}
}
@Override
protected void onResume() {
super.onResume();
nativeOnResume();
}
@Override
protected void onDestroy() {
super.onDestroy();
nativeOnDestroy();
}
}

View file

@ -6,6 +6,9 @@ import android.content.Intent;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.os.Bundle; import android.os.Bundle;
import io.highfidelity.oculus.OculusMobileActivity;
import io.highfidelity.utils.HifiUtils;
public class PermissionsChecker extends Activity { public class PermissionsChecker extends Activity {
private static final int REQUEST_PERMISSIONS = 20; private static final int REQUEST_PERMISSIONS = 20;
private static final String TAG = PermissionsChecker.class.getName(); private static final String TAG = PermissionsChecker.class.getName();
@ -44,7 +47,7 @@ public class PermissionsChecker extends Activity {
} }
private void launchActivityWithPermissions() { private void launchActivityWithPermissions() {
startActivity(new Intent(this, QuestActivity.class)); startActivity(new Intent(this, OculusMobileActivity.class));
finish(); finish();
} }

View file

@ -1,25 +0,0 @@
//
// MainActivity.java
// android/app/src/main/java
//
// Created by Stephen Birarda on 1/26/15.
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
package io.highfidelity.questInterface;
import android.content.Intent;
import android.os.Bundle;
import io.highfidelity.oculus.OculusMobileActivity;
public class QuestActivity extends OculusMobileActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
startActivity(new Intent(this, MainActivity.class));
}
}

View file

@ -6,7 +6,7 @@ buildscript {
jcenter() jcenter()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.2.1' classpath 'com.android.tools.build:gradle:3.3.0'
} }
} }

View file

@ -15,3 +15,7 @@ android {
targetCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8
} }
} }
dependencies {
compile project(path: ':qt')
}

View file

@ -10,79 +10,115 @@ package io.highfidelity.oculus;
import android.app.Activity; import android.app.Activity;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log; import android.util.Log;
import android.view.Surface; import android.view.Surface;
import android.view.SurfaceHolder; import android.view.SurfaceHolder;
import android.view.SurfaceView; import android.view.SurfaceView;
import android.view.WindowManager; import android.view.WindowManager;
import android.widget.LinearLayout;
import org.qtproject.qt5.android.bindings.QtActivity;
import io.highfidelity.utils.HifiUtils;
/** /**
* Contains a native surface and forwards the activity lifecycle and surface lifecycle * Contains a native surface and forwards the activity lifecycle and surface lifecycle
* events to the OculusMobileDisplayPlugin * events to the OculusMobileDisplayPlugin
*/ */
public class OculusMobileActivity extends Activity implements SurfaceHolder.Callback { public class OculusMobileActivity extends QtActivity implements SurfaceHolder.Callback {
private static final String TAG = OculusMobileActivity.class.getSimpleName(); private static final String TAG = OculusMobileActivity.class.getSimpleName();
static { System.loadLibrary("oculusMobile"); } static { System.loadLibrary("oculusMobile"); }
private native void nativeOnCreate(); private native void nativeOnCreate();
private native static void nativeOnResume(); private native static void nativeOnResume();
private native static void nativeOnPause(); private native static void nativeOnPause();
private native static void nativeOnDestroy(); private native static void nativeOnDestroy();
private native static void nativeOnSurfaceChanged(Surface s); private native static void nativeOnSurfaceChanged(Surface s);
private native void questNativeOnCreate();
private native void questNativeOnDestroy();
private native void questNativeOnPause();
private native void questNativeOnResume();
private native void questOnAppAfterLoad();
private SurfaceView mView; private SurfaceView mView;
private SurfaceHolder mSurfaceHolder; private SurfaceHolder mSurfaceHolder;
boolean isLoading =false;
public static void launch(Activity activity) {
if (activity != null) {
activity.runOnUiThread(()->{
activity.startActivity(new Intent(activity, OculusMobileActivity.class));
});
}
}
@Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
Log.w(TAG, "QQQ onCreate"); isLoading=true;
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); HifiUtils.upackAssets(getAssets(), getCacheDir().getAbsolutePath());
Log.w(TAG, "QQQ onCreate");
// Create a native surface for VR rendering (Qt GL surfaces are not suitable // Create a native surface for VR rendering (Qt GL surfaces are not suitable
// because of the lack of fine control over the surface callbacks) // because of the lack of fine control over the surface callbacks)
// Forward the create message to the JNI code
mView = new SurfaceView(this); mView = new SurfaceView(this);
setContentView(mView);
mView.getHolder().addCallback(this); mView.getHolder().addCallback(this);
// Forward the create message to the JNI code
nativeOnCreate(); nativeOnCreate();
questNativeOnCreate();
}
public void onAppLoadedComplete() {
Log.w(TAG, "QQQ Load Completed");
isLoading=false;
//isLoading=false;
runOnUiThread(() -> {
setContentView(mView); setContentView(mView);
questOnAppAfterLoad();
});
} }
@Override @Override
protected void onDestroy() { protected void onDestroy() {
Log.w(TAG, "QQQ onDestroy"); Log.w(TAG, "QQQ onDestroy");
super.onDestroy();
if (mSurfaceHolder != null) { if (mSurfaceHolder != null) {
nativeOnSurfaceChanged(null); nativeOnSurfaceChanged(null);
} }
nativeOnDestroy(); nativeOnDestroy();
super.onDestroy(); questNativeOnDestroy();
} }
@Override @Override
protected void onResume() { protected void onResume() {
Log.w(TAG, "QQQ onResume"); Log.w(TAG, "QQQ onResume");
super.onResume(); super.onResume();
questNativeOnResume();
nativeOnResume(); nativeOnResume();
} }
@Override @Override
protected void onPause() { protected void onPause() {
Log.w(TAG, "QQQ onPause"); Log.w(TAG, "QQQ onPause");
nativeOnPause();
super.onPause(); super.onPause();
if (!isLoading) {
questNativeOnPause();
nativeOnPause();
}
}
@Override
protected void onRestart(){
super.onRestart();
nativeOnCreate();
} }
@Override @Override
public void surfaceCreated(SurfaceHolder holder) { public void surfaceCreated(SurfaceHolder holder) {
Log.w(TAG, "QQQ surfaceCreated"); Log.w(TAG, "QQQ surfaceCreated ************************************");
nativeOnSurfaceChanged(holder.getSurface()); nativeOnSurfaceChanged(holder.getSurface());
mSurfaceHolder = holder; mSurfaceHolder = holder;
} }
@ -96,7 +132,7 @@ public class OculusMobileActivity extends Activity implements SurfaceHolder.Call
@Override @Override
public void surfaceDestroyed(SurfaceHolder holder) { public void surfaceDestroyed(SurfaceHolder holder) {
Log.w(TAG, "QQQ surfaceDestroyed"); Log.w(TAG, "QQQ surfaceDestroyed ***************************************************");
nativeOnSurfaceChanged(null); nativeOnSurfaceChanged(null);
mSurfaceHolder = null; mSurfaceHolder = null;
} }

View file

@ -70,9 +70,6 @@ public class QtActivity extends Activity {
public final String QT_ANDROID_DEFAULT_THEME = QT_ANDROID_THEMES[0]; // sets the default theme. public final String QT_ANDROID_DEFAULT_THEME = QT_ANDROID_THEMES[0]; // sets the default theme.
private QtActivityLoader m_loader = new QtActivityLoader(this); private QtActivityLoader m_loader = new QtActivityLoader(this);
public boolean isLoading;
public boolean keepInterfaceRunning;
public QtActivity() { public QtActivity() {
} }
@ -229,10 +226,13 @@ public class QtActivity extends Activity {
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
protected void onCreateHook(Bundle savedInstanceState) { protected void onCreateHook(Bundle savedInstanceState) {
m_loader.APPLICATION_PARAMETERS = APPLICATION_PARAMETERS; m_loader.APPLICATION_PARAMETERS = APPLICATION_PARAMETERS;
m_loader.ENVIRONMENT_VARIABLES = ENVIRONMENT_VARIABLES; m_loader.ENVIRONMENT_VARIABLES = ENVIRONMENT_VARIABLES;
m_loader.QT_ANDROID_THEMES = QT_ANDROID_THEMES; m_loader.QT_ANDROID_THEMES = QT_ANDROID_THEMES;
m_loader.QT_ANDROID_DEFAULT_THEME = QT_ANDROID_DEFAULT_THEME; m_loader.QT_ANDROID_DEFAULT_THEME = QT_ANDROID_DEFAULT_THEME;
m_loader.onCreate(savedInstanceState); m_loader.onCreate(savedInstanceState);
} }
@ -506,9 +506,7 @@ public class QtActivity extends Activity {
super.onPause(); super.onPause();
// GC: this trick allow us to show a splash activity until Qt app finishes // GC: this trick allow us to show a splash activity until Qt app finishes
// loading // loading
if (!isLoading && !keepInterfaceRunning) { QtApplication.invokeDelegate();
QtApplication.invokeDelegate();
}
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@ -647,11 +645,7 @@ public class QtActivity extends Activity {
@Override @Override
protected void onStop() { protected void onStop() {
super.onStop(); super.onStop();
if (!keepInterfaceRunning) { QtApplication.invokeDelegate();
QtApplication.invokeDelegate();
}
QtNative.terminateQt();
QtNative.setActivity(null,null);
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

View file

@ -12,8 +12,8 @@ project(':qt').projectDir = new File(settingsDir, 'libraries/qt')
// Applications // Applications
// //
include ':interface' //include ':interface'
project(':interface').projectDir = new File(settingsDir, 'apps/interface') //project(':interface').projectDir = new File(settingsDir, 'apps/interface')
include ':questInterface' include ':questInterface'
project(':questInterface').projectDir = new File(settingsDir, 'apps/questInterface') project(':questInterface').projectDir = new File(settingsDir, 'apps/questInterface')
@ -22,8 +22,8 @@ project(':questInterface').projectDir = new File(settingsDir, 'apps/questInterfa
// Test projects // Test projects
// //
include ':framePlayer' //include ':framePlayer'
project(':framePlayer').projectDir = new File(settingsDir, 'apps/framePlayer') //project(':framePlayer').projectDir = new File(settingsDir, 'apps/framePlayer')
include ':questFramePlayer' //include ':questFramePlayer'
project(':questFramePlayer').projectDir = new File(settingsDir, 'apps/questFramePlayer') //project(':questFramePlayer').projectDir = new File(settingsDir, 'apps/questFramePlayer')

View file

@ -2428,6 +2428,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
connect(&AndroidHelper::instance(), &AndroidHelper::enterForeground, this, &Application::enterForeground); connect(&AndroidHelper::instance(), &AndroidHelper::enterForeground, this, &Application::enterForeground);
AndroidHelper::instance().notifyLoadComplete(); AndroidHelper::instance().notifyLoadComplete();
#endif #endif
AndroidHelper::instance().notifyLoadComplete();
pauseUntilLoginDetermined(); pauseUntilLoginDetermined();
} }

View file

@ -27,6 +27,25 @@ using namespace ovr;
static thread_local bool isRenderThread { false }; static thread_local bool isRenderThread { false };
static void getClassName(JNIEnv *env, jobject obj){
jclass cls = env->GetObjectClass(obj);
jmethodID mid = env->GetMethodID(cls,"getClass", "()Ljava/lang/Class;");
jobject clsObj = env->CallObjectMethod(obj, mid);
cls= env->GetObjectClass(clsObj);
mid= env->GetMethodID(cls, "getName", "()Ljava/lang/String;");
jstring strObj = (jstring) env->CallObjectMethod(clsObj, mid);
const char* str = env->GetStringUTFChars(strObj, NULL);
__android_log_print(ANDROID_LOG_ERROR,__FUNCTION__, "VRHandler class: %s",str);
env->ReleaseStringUTFChars(strObj, str);
}
struct VrSurface : public TaskQueue { struct VrSurface : public TaskQueue {
using HandlerTask = VrHandler::HandlerTask; using HandlerTask = VrHandler::HandlerTask;