diff --git a/android/app/CMakeLists.txt b/android/app/CMakeLists.txt index 9930a9e152..19dce330c1 100644 --- a/android/app/CMakeLists.txt +++ b/android/app/CMakeLists.txt @@ -1,6 +1,6 @@ set(TARGET_NAME native-lib) setup_hifi_library() -link_hifi_libraries(shared task networking gl gpu qml image fbx render-utils physics entities octree ${PLATFORM_GL_BACKEND}) +link_hifi_libraries(shared task networking gl gpu qml image fbx hfm render-utils physics entities octree ${PLATFORM_GL_BACKEND}) target_opengl() target_bullet() diff --git a/android/app/build.gradle b/android/app/build.gradle index c04bf37438..cbc31479ec 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -51,6 +51,9 @@ android { debug { buildConfigField "String", "BACKTRACE_URL", "\"" + (System.getenv("CMAKE_BACKTRACE_URL") ? System.getenv("CMAKE_BACKTRACE_URL") : '') + "\"" buildConfigField "String", "BACKTRACE_TOKEN", "\"" + (System.getenv("CMAKE_BACKTRACE_TOKEN") ? System.getenv("CMAKE_BACKTRACE_TOKEN") : '') + "\"" + buildConfigField "String", "OAUTH_CLIENT_ID", "\"" + (System.getenv("OAUTH_CLIENT_ID") ? System.getenv("OAUTH_CLIENT_ID") : '') + "\"" + buildConfigField "String", "OAUTH_CLIENT_SECRET", "\"" + (System.getenv("OAUTH_CLIENT_SECRET") ? System.getenv("OAUTH_CLIENT_SECRET") : '') + "\"" + buildConfigField "String", "OAUTH_REDIRECT_URI", "\"" + (System.getenv("OAUTH_REDIRECT_URI") ? System.getenv("OAUTH_REDIRECT_URI") : '') + "\"" } release { minifyEnabled false @@ -61,6 +64,9 @@ android { project.hasProperty("HIFI_ANDROID_KEY_PASSWORD")? signingConfigs.release : null buildConfigField "String", "BACKTRACE_URL", "\"" + (System.getenv("CMAKE_BACKTRACE_URL") ? System.getenv("CMAKE_BACKTRACE_URL") : '') + "\"" buildConfigField "String", "BACKTRACE_TOKEN", "\"" + (System.getenv("CMAKE_BACKTRACE_TOKEN") ? System.getenv("CMAKE_BACKTRACE_TOKEN") : '') + "\"" + buildConfigField "String", "OAUTH_CLIENT_ID", "\"" + (System.getenv("OAUTH_CLIENT_ID") ? System.getenv("OAUTH_CLIENT_ID") : '') + "\"" + buildConfigField "String", "OAUTH_CLIENT_SECRET", "\"" + (System.getenv("OAUTH_CLIENT_SECRET") ? System.getenv("OAUTH_CLIENT_SECRET") : '') + "\"" + buildConfigField "String", "OAUTH_REDIRECT_URI", "\"" + (System.getenv("OAUTH_REDIRECT_URI") ? System.getenv("OAUTH_REDIRECT_URI") : '') + "\"" } } diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index b216819ed0..57e708068f 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -71,6 +71,10 @@ android:screenOrientation="portrait" android:theme="@style/Theme.AppCompat.Translucent.NoActionBar" /> + + #include +#define AUTO_LOGOUT_SETTING_NAME "wallet/autoLogout" +#define WALLET_USERNAME_SETTING_NAME "wallet/savedUsername" + QAndroidJniObject __interfaceActivity; QAndroidJniObject __loginCompletedListener; QAndroidJniObject __signupCompletedListener; @@ -210,11 +213,13 @@ JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeOnDest JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeGotoUrl(JNIEnv* env, jobject obj, jstring url) { QAndroidJniObject jniUrl("java/lang/String", "(Ljava/lang/String;)V", url); DependencyManager::get()->loadSettings(jniUrl.toString()); + AndroidHelper::instance().muteMic(); } JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeGoToUser(JNIEnv* env, jobject obj, jstring username) { QAndroidJniObject jniUsername("java/lang/String", "(Ljava/lang/String;)V", username); DependencyManager::get()->goToUser(jniUsername.toString(), false); + AndroidHelper::instance().muteMic(); } JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeOnPause(JNIEnv* env, jobject obj) { @@ -259,7 +264,56 @@ JNIEXPORT jstring JNICALL Java_io_highfidelity_hifiinterface_fragment_HomeFragme } JNIEXPORT void JNICALL -Java_io_highfidelity_hifiinterface_fragment_LoginFragment_nativeCancelLogin(JNIEnv *env, jobject instance) { +Java_io_highfidelity_hifiinterface_HifiUtils_updateHifiSetting(JNIEnv *env, jobject instance, + jstring group_, jstring key_, + jboolean value_) { + const char *c_group = env->GetStringUTFChars(group_, 0); + const char *c_key = env->GetStringUTFChars(key_, 0); + + const QString group = QString::fromUtf8(c_group); + const QString key = QString::fromUtf8(c_key); + + env->ReleaseStringUTFChars(group_, c_group); + env->ReleaseStringUTFChars(key_, c_key); + + bool value = value_; + + Setting::Handle setting { QStringList() << group << key , !value }; + setting.set(value); +} + +JNIEXPORT jboolean JNICALL +Java_io_highfidelity_hifiinterface_HifiUtils_getHifiSettingBoolean(JNIEnv *env, + jobject instance, + jstring group_, + jstring key_, + jboolean defaultValue) { + const char *c_group = env->GetStringUTFChars(group_, 0); + const char *c_key = env->GetStringUTFChars(key_, 0); + + const QString group = QString::fromUtf8(c_group); + const QString key = QString::fromUtf8(c_key); + + env->ReleaseStringUTFChars(group_, c_group); + env->ReleaseStringUTFChars(key_, c_key); + + Setting::Handle setting { QStringList() << group << key , defaultValue}; + return setting.get(); +} + +JNIEXPORT jboolean JNICALL +Java_io_highfidelity_hifiinterface_HifiUtils_isUserLoggedIn(JNIEnv *env, jobject instance) { + return DependencyManager::get()->isLoggedIn(); +} + +JNIEXPORT jboolean JNICALL +Java_io_highfidelity_hifiinterface_HifiUtils_isKeepingLoggedIn(JNIEnv *env, jobject instance) { + Setting::Handle setting(AUTO_LOGOUT_SETTING_NAME, true); + return !setting.get(); +} + +JNIEXPORT void JNICALL +Java_io_highfidelity_hifiinterface_fragment_LoginFragment_cancelLogin(JNIEnv *env, jobject instance) { auto accountManager = DependencyManager::get(); @@ -269,17 +323,16 @@ Java_io_highfidelity_hifiinterface_fragment_LoginFragment_nativeCancelLogin(JNIE } JNIEXPORT void JNICALL -Java_io_highfidelity_hifiinterface_fragment_SignupFragment_nativeCancelLogin(JNIEnv *env, +Java_io_highfidelity_hifiinterface_fragment_SignupFragment_cancelLogin(JNIEnv *env, jobject instance) { - Java_io_highfidelity_hifiinterface_fragment_LoginFragment_nativeCancelLogin(env, instance); + Java_io_highfidelity_hifiinterface_fragment_LoginFragment_cancelLogin(env, instance); } - JNIEXPORT void JNICALL -Java_io_highfidelity_hifiinterface_fragment_LoginFragment_nativeLogin(JNIEnv *env, jobject instance, +Java_io_highfidelity_hifiinterface_fragment_LoginFragment_login(JNIEnv *env, jobject instance, jstring username_, jstring password_, - jobject usernameChangedListener) { + jboolean keepLoggedIn) { const char *c_username = env->GetStringUTFChars(username_, 0); const char *c_password = env->GetStringUTFChars(password_, 0); QString username = QString(c_username); @@ -290,7 +343,53 @@ Java_io_highfidelity_hifiinterface_fragment_LoginFragment_nativeLogin(JNIEnv *en auto accountManager = DependencyManager::get(); __loginCompletedListener = QAndroidJniObject(instance); - __usernameChangedListener = QAndroidJniObject(usernameChangedListener); + + QObject::connect(accountManager.data(), &AccountManager::loginComplete, [username, keepLoggedIn](const QUrl& authURL) { + jboolean jSuccess = (jboolean) true; + if (__loginCompletedListener.isValid()) { + __loginCompletedListener.callMethod("handleLoginCompleted", "(Z)V", jSuccess); + } + Setting::Handle(AUTO_LOGOUT_SETTING_NAME).set(!keepLoggedIn); + QString usernameToSave = keepLoggedIn ? username : ""; + Setting::Handle(WALLET_USERNAME_SETTING_NAME).set(usernameToSave); + }); + + QObject::connect(accountManager.data(), &AccountManager::loginFailed, []() { + jboolean jSuccess = (jboolean) false; + if (__loginCompletedListener.isValid()) { + __loginCompletedListener.callMethod("handleLoginCompleted", "(Z)V", jSuccess); + } + }); + + QMetaObject::invokeMethod(accountManager.data(), "requestAccessToken", + Q_ARG(const QString&, username), Q_ARG(const QString&, password)); +} + +JNIEXPORT void JNICALL +Java_io_highfidelity_hifiinterface_fragment_LoginFragment_retrieveAccessToken(JNIEnv *env, + jobject instance, + jstring authCode_, + jstring clientId_, + jstring clientSecret_, + jstring redirectUri_) { + const char *c_authCode = env->GetStringUTFChars(authCode_, 0); + const char *c_clientId = env->GetStringUTFChars(clientId_, 0); + const char *c_clientSecret = env->GetStringUTFChars(clientSecret_, 0); + const char *c_redirectUri = env->GetStringUTFChars(redirectUri_, 0); + + QString authCode = QString(c_authCode); + QString clientId = QString(c_clientId); + QString clientSecret = QString(c_clientSecret); + QString redirectUri = QString(c_redirectUri); + + env->ReleaseStringUTFChars(authCode_, c_authCode); + env->ReleaseStringUTFChars(clientId_, c_clientId); + env->ReleaseStringUTFChars(clientSecret_, c_clientSecret); + env->ReleaseStringUTFChars(redirectUri_, c_redirectUri); + + auto accountManager = DependencyManager::get(); + + __loginCompletedListener = QAndroidJniObject(instance); // TODO: use a different listener? QObject::connect(accountManager.data(), &AccountManager::loginComplete, [](const QUrl& authURL) { jboolean jSuccess = (jboolean) true; @@ -306,24 +405,19 @@ Java_io_highfidelity_hifiinterface_fragment_LoginFragment_nativeLogin(JNIEnv *en } }); - QObject::connect(accountManager.data(), &AccountManager::usernameChanged, [](const QString& username) { - QAndroidJniObject string = QAndroidJniObject::fromString(username); - if (__usernameChangedListener.isValid()) { - __usernameChangedListener.callMethod("handleUsernameChanged", "(Ljava/lang/String;)V", string.object()); - } - }); + QMetaObject::invokeMethod(accountManager.data(), "requestAccessTokenWithAuthCode", + Q_ARG(const QString&, authCode), Q_ARG(const QString&, clientId), + Q_ARG(const QString&, clientSecret), Q_ARG(const QString&, redirectUri)); - QMetaObject::invokeMethod(accountManager.data(), "requestAccessToken", - Q_ARG(const QString&, username), Q_ARG(const QString&, password)); } JNIEXPORT void JNICALL -Java_io_highfidelity_hifiinterface_fragment_SignupFragment_nativeLogin(JNIEnv *env, +Java_io_highfidelity_hifiinterface_fragment_SignupFragment_login(JNIEnv *env, jobject instance, jstring username_, jstring password_, - jobject usernameChangedListener) { - Java_io_highfidelity_hifiinterface_fragment_LoginFragment_nativeLogin(env, instance, username_, password_, usernameChangedListener); + jboolean keepLoggedIn) { + Java_io_highfidelity_hifiinterface_fragment_LoginFragment_login(env, instance, username_, password_, keepLoggedIn); } JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeInitAfterAppLoaded(JNIEnv* env, jobject obj) { @@ -331,7 +425,7 @@ JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeInitAf } JNIEXPORT void JNICALL -Java_io_highfidelity_hifiinterface_fragment_SignupFragment_nativeSignup(JNIEnv *env, jobject instance, +Java_io_highfidelity_hifiinterface_fragment_SignupFragment_signup(JNIEnv *env, jobject instance, jstring email_, jstring username_, jstring password_) { @@ -359,8 +453,6 @@ Java_io_highfidelity_hifiinterface_fragment_SignupFragment_nativeSignup(JNIEnv * }); QObject::connect(&AndroidHelper::instance(), &AndroidHelper::handleSignupFailed, [](QString errorString) { - jboolean jSuccess = (jboolean) false; - jstring jError = QAndroidJniObject::fromString(errorString).object(); if (__signupCompletedListener.isValid()) { QAndroidJniObject string = QAndroidJniObject::fromString(errorString); __signupCompletedListener.callMethod("handleSignupFailed", "(Ljava/lang/String;)V", string.object()); @@ -371,19 +463,13 @@ Java_io_highfidelity_hifiinterface_fragment_SignupFragment_nativeSignup(JNIEnv * } JNIEXPORT void JNICALL -Java_io_highfidelity_hifiinterface_fragment_SignupFragment_nativeCancelSignup(JNIEnv *env, jobject instance) { +Java_io_highfidelity_hifiinterface_fragment_SignupFragment_cancelSignup(JNIEnv *env, jobject instance) { QObject::disconnect(&AndroidHelper::instance(), &AndroidHelper::handleSignupCompleted, nullptr, nullptr); QObject::disconnect(&AndroidHelper::instance(), &AndroidHelper::handleSignupFailed, nullptr, nullptr); __signupCompletedListener = nullptr; } -JNIEXPORT jboolean JNICALL -Java_io_highfidelity_hifiinterface_fragment_FriendsFragment_nativeIsLoggedIn(JNIEnv *env, jobject instance) { - auto accountManager = DependencyManager::get(); - return accountManager->isLoggedIn(); -} - JNIEXPORT jstring JNICALL Java_io_highfidelity_hifiinterface_fragment_FriendsFragment_nativeGetAccessToken(JNIEnv *env, jobject instance) { auto accountManager = DependencyManager::get(); @@ -406,23 +492,40 @@ Java_io_highfidelity_hifiinterface_SplashActivity_registerLoadCompleteListener(J }); } -JNIEXPORT jboolean JNICALL -Java_io_highfidelity_hifiinterface_MainActivity_nativeIsLoggedIn(JNIEnv *env, jobject instance) { - return DependencyManager::get()->isLoggedIn(); -} JNIEXPORT void JNICALL -Java_io_highfidelity_hifiinterface_MainActivity_nativeLogout(JNIEnv *env, jobject instance) { +Java_io_highfidelity_hifiinterface_MainActivity_logout(JNIEnv *env, jobject instance) { DependencyManager::get()->logout(); } JNIEXPORT jstring JNICALL -Java_io_highfidelity_hifiinterface_MainActivity_nativeGetDisplayName(JNIEnv *env, +Java_io_highfidelity_hifiinterface_MainActivity_getUsername(JNIEnv *env, jobject instance) { QString username = DependencyManager::get()->getAccountInfo().getUsername(); return env->NewStringUTF(username.toLatin1().data()); } +JNIEXPORT void JNICALL +Java_io_highfidelity_hifiinterface_MainActivity_setUsernameChangedListener(JNIEnv *env, + jobject instance, + jobject usernameChangedListener) { + __usernameChangedListener = QAndroidJniObject(usernameChangedListener); + + if (!__usernameChangedListener.isValid()) { + return; + } + + auto accountManager = DependencyManager::get(); + + QObject::connect(accountManager.data(), &AccountManager::usernameChanged, [](const QString& username) { + QAndroidJniObject string = QAndroidJniObject::fromString(username); + if (__usernameChangedListener.isValid()) { + __usernameChangedListener.callMethod("handleUsernameChanged", "(Ljava/lang/String;)V", string.object()); + } + }); + +} + JNIEXPORT void JNICALL Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeBeforeEnterBackground(JNIEnv *env, jobject obj) { AndroidHelper::instance().notifyBeforeEnterBackground(); @@ -443,46 +546,6 @@ JNIEXPORT void Java_io_highfidelity_hifiinterface_WebViewActivity_nativeProcessU AndroidHelper::instance().processURL(QString::fromUtf8(nativeString)); } -JNIEXPORT void JNICALL -Java_io_highfidelity_hifiinterface_fragment_SettingsFragment_updateHifiSetting(JNIEnv *env, - jobject instance, - jstring group_, - jstring key_, - jboolean value_) { - const char *c_group = env->GetStringUTFChars(group_, 0); - const char *c_key = env->GetStringUTFChars(key_, 0); - - const QString group = QString::fromUtf8(c_group); - const QString key = QString::fromUtf8(c_key); - - env->ReleaseStringUTFChars(group_, c_group); - env->ReleaseStringUTFChars(key_, c_key); - - bool value = value_; - - Setting::Handle setting { QStringList() << group << key , !value }; - setting.set(value); -} - -JNIEXPORT jboolean JNICALL -Java_io_highfidelity_hifiinterface_fragment_SettingsFragment_getHifiSettingBoolean(JNIEnv *env, - jobject instance, - jstring group_, - jstring key_, - jboolean defaultValue) { - const char *c_group = env->GetStringUTFChars(group_, 0); - const char *c_key = env->GetStringUTFChars(key_, 0); - - const QString group = QString::fromUtf8(c_group); - const QString key = QString::fromUtf8(c_key); - - env->ReleaseStringUTFChars(group_, c_group); - env->ReleaseStringUTFChars(key_, c_key); - - Setting::Handle setting { QStringList() << group << key , defaultValue}; - return setting.get(); -} - JNIEXPORT void JNICALL Java_io_highfidelity_hifiinterface_receiver_HeadsetStateReceiver_notifyHeadsetOn(JNIEnv *env, jobject instance, diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/HifiUtils.java b/android/app/src/main/java/io/highfidelity/hifiinterface/HifiUtils.java index f92cd0a385..a85e18d9a9 100644 --- a/android/app/src/main/java/io/highfidelity/hifiinterface/HifiUtils.java +++ b/android/app/src/main/java/io/highfidelity/hifiinterface/HifiUtils.java @@ -64,4 +64,10 @@ public class HifiUtils { public native String protocolVersionSignature(); + public native boolean isUserLoggedIn(); + + public native void updateHifiSetting(String group, String key, boolean value); + public native boolean getHifiSettingBoolean(String group, String key, boolean defaultValue); + + public native boolean isKeepingLoggedIn(); } diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/InterfaceActivity.java b/android/app/src/main/java/io/highfidelity/hifiinterface/InterfaceActivity.java index 90e411173b..50aea59663 100644 --- a/android/app/src/main/java/io/highfidelity/hifiinterface/InterfaceActivity.java +++ b/android/app/src/main/java/io/highfidelity/hifiinterface/InterfaceActivity.java @@ -76,7 +76,7 @@ public class InterfaceActivity extends QtActivity implements WebViewFragment.OnW private static boolean inVrMode; private boolean nativeEnterBackgroundCallEnqueued = false; - private SlidingDrawer webSlidingDrawer; + private SlidingDrawer mWebSlidingDrawer; // private GvrApi gvrApi; // Opaque native pointer to the Application C++ object. // This object is owned by the InterfaceActivity instance and passed to the native methods. @@ -116,17 +116,6 @@ public class InterfaceActivity extends QtActivity implements WebViewFragment.OnW //nativeGvrApi = nativeOnCreate(this, assetManager /*, gvrApi.getNativeGvrContext()*/); - Point size = new Point(); - getWindowManager().getDefaultDisplay().getRealSize(size); - - try { - PackageInfo pInfo = this.getPackageManager().getPackageInfo(getPackageName(), 0); - String version = pInfo.versionName; -// setAppVersion(version); - } catch (PackageManager.NameNotFoundException e) { - Log.e("GVR", "Error getting application version", e); - } - final View rootView = getWindow().getDecorView().findViewById(android.R.id.content); // This is a workaround to hide the menu bar when the virtual keyboard is shown from Qt @@ -137,26 +126,6 @@ public class InterfaceActivity extends QtActivity implements WebViewFragment.OnW }); startActivity(new Intent(this, SplashActivity.class)); mVibrator = (Vibrator) this.getSystemService(VIBRATOR_SERVICE); - - FrameLayout mainLayout = findViewById(android.R.id.content); - LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); - webSlidingDrawer = (SlidingDrawer) inflater.inflate(R.layout.web_drawer, mainLayout, false); - QtLayout qtLayout = (QtLayout) mainLayout.getChildAt(0); - QtLayout.LayoutParams layoutParams = new QtLayout.LayoutParams(webSlidingDrawer.getLayoutParams()); - webSlidingDrawer.setOnDrawerCloseListener(() -> { - WebViewFragment webViewFragment = (WebViewFragment) getFragmentManager().findFragmentByTag("webViewFragment"); - webViewFragment.close(); - }); - int widthPx = Math.max(size.x, size.y); - int heightPx = Math.min(size.x, size.y); - - layoutParams.x = (int) (widthPx - WEB_DRAWER_RIGHT_MARGIN * getResources().getDisplayMetrics().xdpi / NORMAL_DPI); - layoutParams.y = (int) (heightPx - WEB_DRAWER_BOTTOM_MARGIN * getResources().getDisplayMetrics().ydpi / NORMAL_DPI); - - layoutParams.resolveLayoutDirection(View.LAYOUT_DIRECTION_RTL); - qtLayout.addView(webSlidingDrawer, layoutParams); - webSlidingDrawer.setVisibility(View.GONE); - headsetStateReceiver = new HeadsetStateReceiver(); } @@ -289,14 +258,47 @@ public class InterfaceActivity extends QtActivity implements WebViewFragment.OnW protected void onNewIntent(Intent intent) { super.onNewIntent(intent); if (intent.hasExtra(DOMAIN_URL)) { - webSlidingDrawer.setVisibility(View.GONE); + hideWebDrawer(); nativeGotoUrl(intent.getStringExtra(DOMAIN_URL)); } else if (intent.hasExtra(EXTRA_GOTO_USERNAME)) { - webSlidingDrawer.setVisibility(View.GONE); + hideWebDrawer(); nativeGoToUser(intent.getStringExtra(EXTRA_GOTO_USERNAME)); } } + private void hideWebDrawer() { + if (mWebSlidingDrawer != null) { + mWebSlidingDrawer.setVisibility(View.GONE); + } + } + + public void showWebDrawer() { + if (mWebSlidingDrawer == null) { + FrameLayout mainLayout = findViewById(android.R.id.content); + LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); + QtLayout qtLayout = (QtLayout) mainLayout.getChildAt(0); + mWebSlidingDrawer = (SlidingDrawer) inflater.inflate(R.layout.web_drawer, mainLayout, false); + + QtLayout.LayoutParams layoutParams = new QtLayout.LayoutParams(mWebSlidingDrawer.getLayoutParams()); + mWebSlidingDrawer.setOnDrawerCloseListener(() -> { + WebViewFragment webViewFragment = (WebViewFragment) getFragmentManager().findFragmentByTag("webViewFragment"); + webViewFragment.close(); + }); + + Point size = new Point(); + getWindowManager().getDefaultDisplay().getRealSize(size); + int widthPx = Math.max(size.x, size.y); + int heightPx = Math.min(size.x, size.y); + + layoutParams.x = (int) (widthPx - WEB_DRAWER_RIGHT_MARGIN * getResources().getDisplayMetrics().xdpi / NORMAL_DPI); + layoutParams.y = (int) (heightPx - WEB_DRAWER_BOTTOM_MARGIN * getResources().getDisplayMetrics().ydpi / NORMAL_DPI); + + layoutParams.resolveLayoutDirection(View.LAYOUT_DIRECTION_RTL); + qtLayout.addView(mWebSlidingDrawer, layoutParams); + } + mWebSlidingDrawer.setVisibility(View.VISIBLE); + } + public void openAndroidActivity(String activityName, boolean backToScene) { openAndroidActivity(activityName, backToScene, null); } @@ -313,29 +315,29 @@ public class InterfaceActivity extends QtActivity implements WebViewFragment.OnW break; case "Login": nativeBeforeEnterBackground(); - Intent loginIntent = new Intent(this, MainActivity.class); - loginIntent.putExtra(MainActivity.EXTRA_FRAGMENT, activityName); - loginIntent.putExtra(MainActivity.EXTRA_BACK_TO_SCENE, backToScene); + Intent loginIntent = new Intent(this, LoginMenuActivity.class); + loginIntent.putExtra(LoginMenuActivity.EXTRA_BACK_TO_SCENE, backToScene); + loginIntent.putExtra(LoginMenuActivity.EXTRA_BACK_ON_SKIP, true); if (args != null && args.containsKey(DOMAIN_URL)) { - loginIntent.putExtra(DOMAIN_URL, (String) args.get(DOMAIN_URL)); + loginIntent.putExtra(LoginMenuActivity.EXTRA_DOMAIN_URL, (String) args.get(DOMAIN_URL)); } startActivity(loginIntent); break; case "WebView": runOnUiThread(() -> { - webSlidingDrawer.setVisibility(View.VISIBLE); - if (!webSlidingDrawer.isOpened()) { - webSlidingDrawer.animateOpen(); + showWebDrawer(); + if (!mWebSlidingDrawer.isOpened()) { + mWebSlidingDrawer.animateOpen(); } if (args != null && args.containsKey(WebViewActivity.WEB_VIEW_ACTIVITY_EXTRA_URL)) { WebViewFragment webViewFragment = (WebViewFragment) getFragmentManager().findFragmentByTag("webViewFragment"); webViewFragment.loadUrl((String) args.get(WebViewActivity.WEB_VIEW_ACTIVITY_EXTRA_URL), true); webViewFragment.setToolbarVisible(true); webViewFragment.setCloseAction(() -> { - if (webSlidingDrawer.isOpened()) { - webSlidingDrawer.animateClose(); + if (mWebSlidingDrawer.isOpened()) { + mWebSlidingDrawer.animateClose(); } - webSlidingDrawer.setVisibility(View.GONE); + hideWebDrawer(); }); } }); @@ -381,4 +383,7 @@ public class InterfaceActivity extends QtActivity implements WebViewFragment.OnW public void onExpand() { keepInterfaceRunning = true; } + + @Override + public void onOAuthAuthorizeCallback(Uri uri) { } } diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/LoginMenuActivity.java b/android/app/src/main/java/io/highfidelity/hifiinterface/LoginMenuActivity.java new file mode 100644 index 0000000000..5cb196249d --- /dev/null +++ b/android/app/src/main/java/io/highfidelity/hifiinterface/LoginMenuActivity.java @@ -0,0 +1,210 @@ +package io.highfidelity.hifiinterface; + + +import android.app.Fragment; +import android.app.FragmentManager; +import android.app.FragmentTransaction; +import android.content.Intent; +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.view.View; +import io.highfidelity.hifiinterface.fragment.LoginFragment; +import io.highfidelity.hifiinterface.fragment.OnBackPressedListener; +import io.highfidelity.hifiinterface.fragment.SignupFragment; +import io.highfidelity.hifiinterface.fragment.StartMenuFragment; + +public class LoginMenuActivity extends AppCompatActivity + implements StartMenuFragment.StartMenuInteractionListener, + LoginFragment.OnLoginInteractionListener, + SignupFragment.OnSignupInteractionListener { + + /** + * Set EXTRA_FINISH_ON_BACK to finish the app when back button is pressed + */ + public static final String EXTRA_FINISH_ON_BACK = "finishOnBack"; + + /** + * Set EXTRA_BACK_TO_SCENE to back to the scene + */ + public static final String EXTRA_BACK_TO_SCENE = "backToScene"; + + /** + * Set EXTRA_BACK_ON_SKIP to finish this activity when skip button is pressed + */ + public static final String EXTRA_BACK_ON_SKIP = "backOnSkip"; + + public static final String EXTRA_DOMAIN_URL = "url"; + + private boolean finishOnBack; + private boolean backToScene; + private boolean backOnSkip; + private String domainUrlToBack; + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_encourage_login); + + finishOnBack = getIntent().getBooleanExtra(EXTRA_FINISH_ON_BACK, false); + backToScene = getIntent().getBooleanExtra(EXTRA_BACK_TO_SCENE, false); + domainUrlToBack = getIntent().getStringExtra(EXTRA_DOMAIN_URL); + backOnSkip = getIntent().getBooleanExtra(EXTRA_BACK_ON_SKIP, false); + + if (savedInstanceState != null) { + finishOnBack = savedInstanceState.getBoolean(EXTRA_FINISH_ON_BACK, false); + backToScene = savedInstanceState.getBoolean(EXTRA_BACK_TO_SCENE, false); + backOnSkip = savedInstanceState.getBoolean(EXTRA_BACK_ON_SKIP, false); + domainUrlToBack = savedInstanceState.getString(EXTRA_DOMAIN_URL); + } + + loadMenuFragment(); + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putBoolean(EXTRA_FINISH_ON_BACK, finishOnBack); + outState.putBoolean(EXTRA_BACK_TO_SCENE, backToScene); + outState.putString(EXTRA_DOMAIN_URL, domainUrlToBack); + } + + @Override + protected void onRestoreInstanceState(Bundle savedInstanceState) { + super.onRestoreInstanceState(savedInstanceState); + finishOnBack = savedInstanceState.getBoolean(EXTRA_FINISH_ON_BACK, false); + backToScene = savedInstanceState.getBoolean(EXTRA_BACK_TO_SCENE, false); + backOnSkip = savedInstanceState.getBoolean(EXTRA_BACK_ON_SKIP, false); + domainUrlToBack = savedInstanceState.getString(EXTRA_DOMAIN_URL); + } + + private void loadMenuFragment() { + FragmentManager fragmentManager = getFragmentManager(); + FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); + Fragment fragment = StartMenuFragment.newInstance(); + fragmentTransaction.replace(R.id.content_frame, fragment); + fragmentTransaction.addToBackStack(fragment.toString()); + fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN); + fragmentTransaction.commit(); + hideStatusBar(); + } + + @Override + protected void onResume() { + super.onResume(); + hideStatusBar(); + } + + private void hideStatusBar() { + View decorView = getWindow().getDecorView(); + // Hide the status bar. + int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; + decorView.setSystemUiVisibility(uiOptions); + } + + @Override + public void onSignupButtonClicked() { + loadSignupFragment(); + } + + @Override + public void onLoginButtonClicked() { + loadLoginFragment(false); + } + + @Override + public void onSkipLoginClicked() { + if (backOnSkip) { + onBackPressed(); + } else { + loadMainActivity(); + } + } + + @Override + public void onSteamLoginButtonClicked() { + loadLoginFragment(true); + } + + private void loadSignupFragment() { + FragmentManager fragmentManager = getFragmentManager(); + FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); + Fragment fragment = SignupFragment.newInstance(); + String tag = getString(R.string.tagFragmentSignup); + fragmentTransaction.replace(R.id.content_frame, fragment, tag); + fragmentTransaction.addToBackStack(tag); + fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN); + fragmentTransaction.commit(); + hideStatusBar(); + } + + private void loadLoginFragment(boolean useOauth) { + FragmentManager fragmentManager = getFragmentManager(); + FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); + Fragment fragment = LoginFragment.newInstance(useOauth); + String tag = getString(R.string.tagFragmentLogin); + fragmentTransaction.replace(R.id.content_frame, fragment, tag); + fragmentTransaction.addToBackStack(tag); + fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN); + fragmentTransaction.commit(); + hideStatusBar(); + } + + @Override + public void onLoginCompleted() { + loadMainActivity(); + } + + @Override + public void onCancelLogin() { + getFragmentManager().popBackStack(); + } + + @Override + public void onCancelSignup() { + getFragmentManager().popBackStack(); + } + + private void loadMainActivity() { + finish(); + if (backToScene) { + backToScene = false; + goToDomain(domainUrlToBack != null? domainUrlToBack : ""); + } else { + startActivity(new Intent(this, MainActivity.class)); + } + } + + private void goToDomain(String domainUrl) { + Intent intent = new Intent(this, InterfaceActivity.class); + intent.putExtra(InterfaceActivity.DOMAIN_URL, domainUrl); + finish(); + intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); + startActivity(intent); + } + + + @Override + public void onSignupCompleted() { + loadMainActivity(); + } + + @Override + public void onBackPressed() { + FragmentManager fm = getFragmentManager(); + int index = fm.getBackStackEntryCount() - 1; + if (index > 0) { + FragmentManager.BackStackEntry backEntry = fm.getBackStackEntryAt(index); + String tag = backEntry.getName(); + Fragment topFragment = getFragmentManager().findFragmentByTag(tag); + if (!(topFragment instanceof OnBackPressedListener) || + !((OnBackPressedListener) topFragment).doBack()) { + super.onBackPressed(); + } + } else if (finishOnBack){ + finishAffinity(); + } else { + finish(); + } + } +} diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/MainActivity.java b/android/app/src/main/java/io/highfidelity/hifiinterface/MainActivity.java index 7df04100b0..e17b530f1c 100644 --- a/android/app/src/main/java/io/highfidelity/hifiinterface/MainActivity.java +++ b/android/app/src/main/java/io/highfidelity/hifiinterface/MainActivity.java @@ -1,5 +1,6 @@ package io.highfidelity.hifiinterface; +import android.app.Activity; import android.app.Fragment; import android.app.FragmentManager; import android.app.FragmentTransaction; @@ -29,23 +30,16 @@ import android.widget.TextView; import com.squareup.picasso.Callback; import com.squareup.picasso.Picasso; -import java.util.HashMap; -import java.util.Map; - import io.highfidelity.hifiinterface.fragment.FriendsFragment; import io.highfidelity.hifiinterface.fragment.HomeFragment; -import io.highfidelity.hifiinterface.fragment.LoginFragment; import io.highfidelity.hifiinterface.fragment.PolicyFragment; import io.highfidelity.hifiinterface.fragment.SettingsFragment; -import io.highfidelity.hifiinterface.fragment.SignedInFragment; -import io.highfidelity.hifiinterface.fragment.SignupFragment;import io.highfidelity.hifiinterface.task.DownloadProfileImageTask; +import io.highfidelity.hifiinterface.fragment.SignupFragment; +import io.highfidelity.hifiinterface.task.DownloadProfileImageTask; public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener, - LoginFragment.OnLoginInteractionListener, HomeFragment.OnHomeInteractionListener, - FriendsFragment.OnHomeInteractionListener, - SignupFragment.OnSignupInteractionListener, - SignedInFragment.OnSignedInInteractionListener { + FriendsFragment.OnHomeInteractionListener { private static final int PROFILE_PICTURE_PLACEHOLDER = R.drawable.default_profile_avatar; public static final String DEFAULT_FRAGMENT = "Home"; @@ -55,9 +49,9 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On private String TAG = "HighFidelity"; - public native boolean nativeIsLoggedIn(); - public native void nativeLogout(); - public native String nativeGetDisplayName(); + public native void logout(); + public native void setUsernameChangedListener(Activity usernameChangedListener); + public native String getUsername(); private DrawerLayout mDrawerLayout; private NavigationView mNavigationView; @@ -130,9 +124,6 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On private void loadFragment(String fragment) { switch (fragment) { - case "Login": - loadLoginFragment(); - break; case "Home": loadHomeFragment(true); break; @@ -153,19 +144,10 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On loadFragment(fragment, getString(R.string.home), getString(R.string.tagFragmentHome), addToBackStack, true); } - private void loadLoginFragment() { - Fragment fragment = LoginFragment.newInstance(); - loadFragment(fragment, getString(R.string.login), getString(R.string.tagFragmentLogin), true, true); - } - - private void loadSignedInFragment() { - Fragment fragment = SignedInFragment.newInstance(); - loadFragment(fragment, getString(R.string.welcome), getString(R.string.tagFragmentSignedIn), true, true); - } - - private void loadSignupFragment() { - Fragment fragment = SignupFragment.newInstance(); - loadFragment(fragment, getString(R.string.signup), getString(R.string.tagFragmentSignup), true, false); + private void startLoginMenuActivity() { + Intent intent = new Intent(this, LoginMenuActivity.class); + intent.putExtra(LoginMenuActivity.EXTRA_BACK_ON_SKIP, true); + startActivity(intent); } private void loadPrivacyPolicyFragment() { @@ -223,7 +205,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On private void updateLoginMenu() { - if (nativeIsLoggedIn()) { + if (HifiUtils.getInstance().isUserLoggedIn()) { mLoginPanel.setVisibility(View.GONE); mProfilePanel.setVisibility(View.VISIBLE); mLogoutOption.setVisibility(View.VISIBLE); @@ -239,7 +221,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On } private void updateProfileHeader() { - updateProfileHeader(nativeGetDisplayName()); + updateProfileHeader(getUsername()); } private void updateProfileHeader(String username) { if (!username.isEmpty()) { @@ -289,15 +271,22 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On @Override protected void onStart() { super.onStart(); + setUsernameChangedListener(this); updateLoginMenu(); } + @Override + protected void onStop() { + super.onStop(); + setUsernameChangedListener(null); + } + public void onLoginClicked(View view) { - loadLoginFragment(); + startLoginMenuActivity(); } public void onLogoutClicked(View view) { - nativeLogout(); + logout(); updateLoginMenu(); exitLoggedInFragment(); @@ -338,42 +327,6 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On startActivity(intent); } - @Override - public void onLoginCompleted() { - loadHomeFragment(false); - updateLoginMenu(); - if (backToScene) { - backToScene = false; - goToLastLocation(); - } - } - - @Override - public void onGettingStarted() { - loadHomeFragment(false); - if (backToScene) { - backToScene = false; - goToLastLocation(); - } - } - - @Override - public void onLoginRequested() { - // go back from signup to login - onBackPressed(); - } - - @Override - public void onSignupRequested() { - loadSignupFragment(); - } - - @Override - public void onSignupCompleted() { - loadSignedInFragment(); - updateLoginMenu(); - } - public void handleUsernameChanged(String username) { runOnUiThread(() -> updateProfileHeader(username)); } @@ -418,7 +371,6 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On public void onBackPressed() { // if a fragment needs to internally manage back presses.. FragmentManager fm = getFragmentManager(); - Log.d("[BACK]", "getBackStackEntryCount " + fm.getBackStackEntryCount()); Fragment friendsFragment = fm.findFragmentByTag(getString(R.string.tagFragmentPeople)); if (friendsFragment != null && friendsFragment instanceof FriendsFragment) { if (((FriendsFragment) friendsFragment).onBackPressed()) { diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/SplashActivity.java b/android/app/src/main/java/io/highfidelity/hifiinterface/SplashActivity.java index e0aa967aaa..bb42467ace 100644 --- a/android/app/src/main/java/io/highfidelity/hifiinterface/SplashActivity.java +++ b/android/app/src/main/java/io/highfidelity/hifiinterface/SplashActivity.java @@ -3,7 +3,6 @@ package io.highfidelity.hifiinterface; import android.app.Activity; import android.content.Intent; import android.os.Bundle; -import android.os.Handler; import android.view.View; public class SplashActivity extends Activity { @@ -37,7 +36,13 @@ public class SplashActivity extends Activity { } public void onAppLoadedComplete() { - startActivity(new Intent(this, MainActivity.class)); + if (HifiUtils.getInstance().isUserLoggedIn()) { + startActivity(new Intent(this, MainActivity.class)); + } else { + Intent menuIntent = new Intent(this, LoginMenuActivity.class); + menuIntent.putExtra(LoginMenuActivity.EXTRA_FINISH_ON_BACK, true); + startActivity(menuIntent); + } SplashActivity.this.finish(); } } diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/WebViewActivity.java b/android/app/src/main/java/io/highfidelity/hifiinterface/WebViewActivity.java index 5d65bcad51..e906c4b734 100644 --- a/android/app/src/main/java/io/highfidelity/hifiinterface/WebViewActivity.java +++ b/android/app/src/main/java/io/highfidelity/hifiinterface/WebViewActivity.java @@ -28,11 +28,18 @@ import java.net.MalformedURLException; import java.net.URL; import io.highfidelity.hifiinterface.fragment.WebViewFragment; +import io.highfidelity.hifiinterface.fragment.WebViewFragment.OnWebViewInteractionListener; -public class WebViewActivity extends Activity implements WebViewFragment.OnWebViewInteractionListener { +public class WebViewActivity extends Activity implements OnWebViewInteractionListener { public static final String WEB_VIEW_ACTIVITY_EXTRA_URL = "url"; + public static final String WEB_VIEW_ACTIVITY_EXTRA_CLEAR_COOKIES = "clear_cookies"; + public static final String RESULT_OAUTH_CODE = "code"; + public static final String RESULT_OAUTH_STATE = "state"; + private static final String FRAGMENT_TAG = "WebViewActivity_WebFragment"; + private static final String OAUTH_CODE = "code"; + private static final String OAUTH_STATE = "state"; private native void nativeProcessURL(String url); @@ -47,14 +54,15 @@ public class WebViewActivity extends Activity implements WebViewFragment.OnWebVi mActionBar = getActionBar(); mActionBar.setDisplayHomeAsUpEnabled(true); - loadWebViewFragment(getIntent().getStringExtra(WEB_VIEW_ACTIVITY_EXTRA_URL)); + loadWebViewFragment(getIntent().getStringExtra(WEB_VIEW_ACTIVITY_EXTRA_URL), getIntent().getBooleanExtra(WEB_VIEW_ACTIVITY_EXTRA_CLEAR_COOKIES, false)); } - private void loadWebViewFragment(String url) { + private void loadWebViewFragment(String url, boolean clearCookies) { WebViewFragment fragment = WebViewFragment.newInstance(); Bundle bundle = new Bundle(); bundle.putString(WebViewFragment.URL, url); bundle.putBoolean(WebViewFragment.TOOLBAR_VISIBLE, false); + bundle.putBoolean(WebViewFragment.CLEAR_COOKIES, clearCookies); fragment.setArguments(bundle); FragmentManager fragmentManager = getFragmentManager(); FragmentTransaction ft = fragmentManager.beginTransaction(); @@ -131,4 +139,13 @@ public class WebViewActivity extends Activity implements WebViewFragment.OnWebVi @Override public void onExpand() { } + @Override + public void onOAuthAuthorizeCallback(Uri uri) { + Intent result = new Intent(); + result.putExtra(RESULT_OAUTH_CODE, uri.getQueryParameter(OAUTH_CODE)); + result.putExtra(RESULT_OAUTH_STATE, uri.getQueryParameter(OAUTH_STATE)); + setResult(Activity.RESULT_OK, result); + finish(); + } + } diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/FriendsFragment.java b/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/FriendsFragment.java index 2475c4d887..e19a9c5a7a 100644 --- a/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/FriendsFragment.java +++ b/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/FriendsFragment.java @@ -23,8 +23,6 @@ import io.highfidelity.hifiinterface.view.UserListAdapter; public class FriendsFragment extends Fragment { - public native boolean nativeIsLoggedIn(); - public native String nativeGetAccessToken(); private RecyclerView mUsersView; diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/LoginFragment.java b/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/LoginFragment.java index f22e5cd6bb..28406d5986 100644 --- a/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/LoginFragment.java +++ b/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/LoginFragment.java @@ -2,41 +2,65 @@ package io.highfidelity.hifiinterface.fragment; import android.app.Activity; import android.app.Fragment; -import android.app.ProgressDialog; import android.content.Context; -import android.content.DialogInterface; import android.content.Intent; import android.net.Uri; import android.os.Bundle; +import android.support.annotation.Nullable; +import android.util.Log; +import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodManager; import android.widget.Button; +import android.widget.CheckBox; import android.widget.EditText; import android.widget.TextView; import org.qtproject.qt5.android.QtNative; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.Random; + +import io.highfidelity.hifiinterface.BuildConfig; +import io.highfidelity.hifiinterface.HifiUtils; import io.highfidelity.hifiinterface.R; +import io.highfidelity.hifiinterface.WebViewActivity; import static org.qtproject.qt5.android.QtActivityDelegate.ApplicationActive; import static org.qtproject.qt5.android.QtActivityDelegate.ApplicationInactive; -public class LoginFragment extends Fragment { +public class LoginFragment extends Fragment + implements OnBackPressedListener { + + private static final String ARG_USE_OAUTH = "use_oauth"; + private static final String TAG = "Interface"; + + private final String OAUTH_CLIENT_ID = BuildConfig.OAUTH_CLIENT_ID; + private final String OAUTH_REDIRECT_URI = BuildConfig.OAUTH_REDIRECT_URI; + private final String OAUTH_AUTHORIZE_BASE_URL = "https://highfidelity.com/oauth/authorize"; + private static final int OAUTH_AUTHORIZE_REQUEST = 1; private EditText mUsername; private EditText mPassword; private TextView mError; - private TextView mForgotPassword; - private TextView mSignup; private Button mLoginButton; + private CheckBox mKeepMeLoggedInCheckbox; + private ViewGroup mLoginForm; + private ViewGroup mLoggingInFrame; + private ViewGroup mLoggedInFrame; + private boolean mLoginInProgress; + private boolean mLoginSuccess; + private boolean mUseOauth; + private String mOauthState; - private ProgressDialog mDialog; + public native void login(String username, String password, boolean keepLoggedIn); + private native void retrieveAccessToken(String authCode, String clientId, String clientSecret, String redirectUri); - public native void nativeLogin(String username, String password, Activity usernameChangedListener); - public native void nativeCancelLogin(); + public native void cancelLogin(); private LoginFragment.OnLoginInteractionListener mListener; @@ -44,11 +68,22 @@ public class LoginFragment extends Fragment { // Required empty public constructor } - public static LoginFragment newInstance() { + public static LoginFragment newInstance(boolean useOauth) { LoginFragment fragment = new LoginFragment(); + Bundle args = new Bundle(); + args.putBoolean(ARG_USE_OAUTH, useOauth); + fragment.setArguments(args); return fragment; } + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (getArguments() != null) { + mUseOauth = getArguments().getBoolean(ARG_USE_OAUTH, false); + } + } + @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -58,22 +93,29 @@ public class LoginFragment extends Fragment { mPassword = rootView.findViewById(R.id.password); mError = rootView.findViewById(R.id.error); mLoginButton = rootView.findViewById(R.id.loginButton); - mForgotPassword = rootView.findViewById(R.id.forgotPassword); - mSignup = rootView.findViewById(R.id.signupButton); + mLoginForm = rootView.findViewById(R.id.loginForm); + mLoggingInFrame = rootView.findViewById(R.id.loggingInFrame); + mLoggedInFrame = rootView.findViewById(R.id.loggedInFrame); + mKeepMeLoggedInCheckbox = rootView.findViewById(R.id.keepMeLoggedIn); - mLoginButton.setOnClickListener(view -> login()); + rootView.findViewById(R.id.forgotPassword).setOnClickListener(view -> onForgotPasswordClicked()); - mForgotPassword.setOnClickListener(view -> forgotPassword()); - mSignup.setOnClickListener(view -> signup()); + rootView.findViewById(R.id.cancel).setOnClickListener(view -> onCancelLogin()); - mPassword.setOnEditorActionListener( - (textView, actionId, keyEvent) -> { - if (actionId == EditorInfo.IME_ACTION_DONE) { - mLoginButton.performClick(); - return true; - } - return false; - }); + rootView.findViewById(R.id.getStarted).setOnClickListener(view -> onGetStartedClicked()); + + mLoginButton.setOnClickListener(view -> onLoginButtonClicked()); + + rootView.findViewById(R.id.takeMeInWorld).setOnClickListener(view -> skipLogin()); + mPassword.setOnEditorActionListener((textView, actionId, keyEvent) -> onPasswordEditorAction(textView, actionId, keyEvent)); + + mKeepMeLoggedInCheckbox.setChecked(HifiUtils.getInstance().isKeepingLoggedIn()); + + if (mUseOauth) { + openWebForAuthorization(); + } else { + showLoginForm(); + } return rootView; } @@ -104,13 +146,57 @@ public class LoginFragment extends Fragment { @Override public void onStop() { super.onStop(); - cancelActivityIndicator(); // Leave the Qt app paused QtNative.setApplicationState(ApplicationInactive); hideKeyboard(); } - public void login() { + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode == OAUTH_AUTHORIZE_REQUEST) { + if (resultCode == Activity.RESULT_OK) { + String authCode = data.getStringExtra(WebViewActivity.RESULT_OAUTH_CODE); + String state = data.getStringExtra(WebViewActivity.RESULT_OAUTH_STATE); + if (state != null && state.equals(mOauthState) && mListener != null) { + mOauthState = null; + showActivityIndicator(); + mLoginInProgress = true; + retrieveAccessToken(authCode, BuildConfig.OAUTH_CLIENT_ID, BuildConfig.OAUTH_CLIENT_SECRET, BuildConfig.OAUTH_REDIRECT_URI); + } + } else { + onCancelLogin(); + } + } + + } + + private void onCancelLogin() { + if (mListener != null) { + mListener.onCancelLogin(); + } + } + + private boolean onPasswordEditorAction(TextView textView, int actionId, KeyEvent keyEvent) { + if (actionId == EditorInfo.IME_ACTION_DONE) { + mLoginButton.performClick(); + return true; + } + return false; + } + + private void skipLogin() { + if (mListener != null) { + mListener.onSkipLoginClicked(); + } + } + + private void onGetStartedClicked() { + if (mListener != null) { + mListener.onLoginCompleted(); + } + } + + public void onLoginButtonClicked() { String username = mUsername.getText().toString().trim(); String password = mPassword.getText().toString(); hideKeyboard(); @@ -120,13 +206,10 @@ public class LoginFragment extends Fragment { mLoginButton.setEnabled(false); hideError(); showActivityIndicator(); - nativeLogin(username, password, getActivity()); - } - } - - public void signup() { - if (mListener != null) { - mListener.onSignupRequested(); + mLoginInProgress = true; + mLoginSuccess = false; + boolean keepUserLoggedIn = mKeepMeLoggedInCheckbox.isChecked(); + login(username, password, keepUserLoggedIn); } } @@ -138,33 +221,32 @@ public class LoginFragment extends Fragment { } } - private void forgotPassword() { + private void onForgotPasswordClicked() { Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://highfidelity.com/users/password/new")); startActivity(intent); } private void showActivityIndicator() { - if (mDialog == null) { - mDialog = new ProgressDialog(getContext()); - } - mDialog.setMessage(getString(R.string.logging_in)); - mDialog.setCancelable(true); - mDialog.setOnCancelListener(new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface dialogInterface) { - nativeCancelLogin(); - cancelActivityIndicator(); - mLoginButton.setEnabled(true); - } - }); - mDialog.show(); + mLoginForm.setVisibility(View.GONE); + mLoggedInFrame.setVisibility(View.GONE); + mLoggingInFrame.setVisibility(View.VISIBLE); + mLoggingInFrame.bringToFront(); } - private void cancelActivityIndicator() { - if (mDialog != null) { - mDialog.cancel(); - } + private void showLoginForm() { + mLoggingInFrame.setVisibility(View.GONE); + mLoggedInFrame.setVisibility(View.GONE); + mLoginForm.setVisibility(View.VISIBLE); + mLoginForm.bringToFront(); } + + private void showLoggedInMessage() { + mLoginForm.setVisibility(View.GONE); + mLoggingInFrame.setVisibility(View.GONE); + mLoggedInFrame.setVisibility(View.VISIBLE); + mLoggedInFrame.bringToFront(); + } + private void showError(String error) { mError.setText(error); mError.setVisibility(View.VISIBLE); @@ -176,22 +258,71 @@ public class LoginFragment extends Fragment { } public void handleLoginCompleted(boolean success) { + mLoginInProgress = false; getActivity().runOnUiThread(() -> { mLoginButton.setEnabled(true); - cancelActivityIndicator(); if (success) { - if (mListener != null) { - mListener.onLoginCompleted(); - } + mLoginSuccess = true; + showLoggedInMessage(); } else { - showError(getString(R.string.login_username_or_password_incorrect)); + if (!mUseOauth) { + showLoginForm(); + showError(getString(R.string.login_username_or_password_incorrect)); + } else { + openWebForAuthorization(); + } } }); } + @Override + public boolean doBack() { + if (mLoginInProgress) { + cancelLogin(); + showLoginForm(); + mLoginInProgress = false; + mLoginButton.setEnabled(true); + return true; + } else if (mLoginSuccess) { + onGetStartedClicked(); + return true; + } else { + return false; + } + } + + private void updateOauthState() { + // as we only use oauth for steam that's ok for now + mOauthState = "steam-" + Long.toString(new Random().nextLong()); + } + + private String buildAuthorizeUrl() { + StringBuilder sb = new StringBuilder(OAUTH_AUTHORIZE_BASE_URL); + sb.append("?client_id=").append(OAUTH_CLIENT_ID); + try { + String redirectUri = URLEncoder.encode(OAUTH_REDIRECT_URI, "utf-8"); + sb.append("&redirect_uri=").append(redirectUri); + } catch (UnsupportedEncodingException e) { + Log.e(TAG, "Cannot build oauth autorization url", e); + } + sb.append("&response_type=code&scope=owner"); + sb.append("&state=").append(mOauthState); + return sb.toString(); + } + + private void openWebForAuthorization() { + Intent openUrlIntent = new Intent(getActivity(), WebViewActivity.class); + updateOauthState(); + openUrlIntent.putExtra(WebViewActivity.WEB_VIEW_ACTIVITY_EXTRA_URL, buildAuthorizeUrl()); + openUrlIntent.putExtra(WebViewActivity.WEB_VIEW_ACTIVITY_EXTRA_CLEAR_COOKIES, true); + startActivityForResult(openUrlIntent, OAUTH_AUTHORIZE_REQUEST); + } + + public interface OnLoginInteractionListener { void onLoginCompleted(); - void onSignupRequested(); + void onCancelLogin(); + void onSkipLoginClicked(); } } diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/OnBackPressedListener.java b/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/OnBackPressedListener.java new file mode 100644 index 0000000000..c160138cea --- /dev/null +++ b/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/OnBackPressedListener.java @@ -0,0 +1,11 @@ +package io.highfidelity.hifiinterface.fragment; + +public interface OnBackPressedListener { + + /** + * Processes the back pressed event and returns true if it was managed by this Fragment + * @return + */ + boolean doBack(); + +} diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/SettingsFragment.java b/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/SettingsFragment.java index cc23665e72..e32dc3b996 100644 --- a/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/SettingsFragment.java +++ b/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/SettingsFragment.java @@ -3,32 +3,35 @@ package io.highfidelity.hifiinterface.fragment; import android.content.SharedPreferences; import android.media.audiofx.AcousticEchoCanceler; import android.os.Bundle; -import android.preference.Preference; import android.preference.PreferenceFragment; +import android.preference.PreferenceManager; import android.support.annotation.Nullable; +import io.highfidelity.hifiinterface.HifiUtils; import io.highfidelity.hifiinterface.R; public class SettingsFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener { - public native void updateHifiSetting(String group, String key, boolean value); - public native boolean getHifiSettingBoolean(String group, String key, boolean defaultValue); - private final String HIFI_SETTINGS_ANDROID_GROUP = "Android"; private final String HIFI_SETTINGS_AEC_KEY = "aec"; private final String PREFERENCE_KEY_AEC = "aec"; + private final boolean DEFAULT_AEC_ENABLED = true; + @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.settings); + boolean aecAvailable = AcousticEchoCanceler.isAvailable(); + PreferenceManager.setDefaultValues(getContext(), R.xml.settings, false); - if (!AcousticEchoCanceler.isAvailable()) { - getPreferenceScreen().getPreferenceManager().findPreference("aec").setEnabled(false); + if (!aecAvailable) { + findPreference(PREFERENCE_KEY_AEC).setEnabled(false); + HifiUtils.getInstance().updateHifiSetting(HIFI_SETTINGS_ANDROID_GROUP, HIFI_SETTINGS_AEC_KEY, false); } getPreferenceScreen().getSharedPreferences().edit().putBoolean(PREFERENCE_KEY_AEC, - getHifiSettingBoolean(HIFI_SETTINGS_ANDROID_GROUP, HIFI_SETTINGS_AEC_KEY, false)); + aecAvailable && HifiUtils.getInstance().getHifiSettingBoolean(HIFI_SETTINGS_ANDROID_GROUP, HIFI_SETTINGS_AEC_KEY, DEFAULT_AEC_ENABLED)).commit(); } public static SettingsFragment newInstance() { @@ -46,15 +49,13 @@ public class SettingsFragment extends PreferenceFragment implements SharedPrefer public void onPause() { super.onPause(); getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this); - } @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { - Preference pref = findPreference(key); switch (key) { case "aec": - updateHifiSetting(HIFI_SETTINGS_ANDROID_GROUP, HIFI_SETTINGS_AEC_KEY, sharedPreferences.getBoolean(key, false)); + HifiUtils.getInstance().updateHifiSetting(HIFI_SETTINGS_ANDROID_GROUP, HIFI_SETTINGS_AEC_KEY, sharedPreferences.getBoolean(key, false)); break; default: break; diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/SignedInFragment.java b/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/SignedInFragment.java deleted file mode 100644 index 9ed2f1c7f5..0000000000 --- a/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/SignedInFragment.java +++ /dev/null @@ -1,73 +0,0 @@ -package io.highfidelity.hifiinterface.fragment; - -import android.app.Fragment; -import android.content.Context; -import android.os.Bundle; -import android.text.Html; -import android.text.Spanned; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.Button; -import android.widget.TextView; - -import java.io.IOException; -import java.io.InputStream; - -import io.highfidelity.hifiinterface.R; - -public class SignedInFragment extends Fragment { - - private Button mGetStartedButton; - private OnSignedInInteractionListener mListener; - - public SignedInFragment() { - // Required empty public constructor - } - - public static SignedInFragment newInstance() { - SignedInFragment fragment = new SignedInFragment(); - return fragment; - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - View rootView = inflater.inflate(R.layout.fragment_signedin, container, false); - mGetStartedButton = rootView.findViewById(R.id.getStarted); - - mGetStartedButton.setOnClickListener(view -> { - getStarted(); - }); - - return rootView; - } - - @Override - public void onAttach(Context context) { - super.onAttach(context); - if (context instanceof SignedInFragment.OnSignedInInteractionListener) { - mListener = (SignedInFragment.OnSignedInInteractionListener) context; - } else { - throw new RuntimeException(context.toString() - + " must implement OnSignedInInteractionListener"); - } - } - - @Override - public void onDetach() { - super.onDetach(); - mListener = null; - } - - public void getStarted() { - if (mListener != null) { - mListener.onGettingStarted(); - } - } - - public interface OnSignedInInteractionListener { - void onGettingStarted(); - } - -} diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/SignupFragment.java b/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/SignupFragment.java index 33644e5bda..a11ae31fa1 100644 --- a/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/SignupFragment.java +++ b/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/SignupFragment.java @@ -1,42 +1,50 @@ package io.highfidelity.hifiinterface.fragment; -import android.app.Activity; import android.app.Fragment; -import android.app.ProgressDialog; import android.content.Context; import android.os.Bundle; +import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodManager; import android.widget.Button; +import android.widget.CheckBox; import android.widget.EditText; import android.widget.TextView; import org.qtproject.qt5.android.QtNative; +import io.highfidelity.hifiinterface.HifiUtils; import io.highfidelity.hifiinterface.R; import static org.qtproject.qt5.android.QtActivityDelegate.ApplicationActive; import static org.qtproject.qt5.android.QtActivityDelegate.ApplicationInactive; -public class SignupFragment extends Fragment { +public class SignupFragment extends Fragment + implements OnBackPressedListener { private EditText mEmail; private EditText mUsername; private EditText mPassword; private TextView mError; - private TextView mCancelButton; - + private TextView mActivityText; private Button mSignupButton; + private CheckBox mKeepMeLoggedInCheckbox; - private ProgressDialog mDialog; + private ViewGroup mSignupForm; + private ViewGroup mLoggingInFrame; + private ViewGroup mLoggedInFrame; - public native void nativeSignup(String email, String username, String password); // move to SignupFragment - public native void nativeCancelSignup(); - public native void nativeLogin(String username, String password, Activity usernameChangedListener); - public native void nativeCancelLogin(); + private boolean mLoginInProgress; + private boolean mSignupInProgress; + private boolean mSignupSuccess; + + public native void signup(String email, String username, String password); // move to SignupFragment + public native void cancelSignup(); + public native void login(String username, String password, boolean keepLoggedIn); + public native void cancelLogin(); private SignupFragment.OnSignupInteractionListener mListener; @@ -59,18 +67,23 @@ public class SignupFragment extends Fragment { mPassword = rootView.findViewById(R.id.password); mError = rootView.findViewById(R.id.error); mSignupButton = rootView.findViewById(R.id.signupButton); - mCancelButton = rootView.findViewById(R.id.cancelButton); + mActivityText = rootView.findViewById(R.id.activityText); + mKeepMeLoggedInCheckbox = rootView.findViewById(R.id.keepMeLoggedIn); + + mSignupForm = rootView.findViewById(R.id.signupForm); + mLoggedInFrame = rootView.findViewById(R.id.loggedInFrame); + mLoggingInFrame = rootView.findViewById(R.id.loggingInFrame); + + rootView.findViewById(R.id.cancel).setOnClickListener(view -> onCancelSignup()); mSignupButton.setOnClickListener(view -> signup()); - mCancelButton.setOnClickListener(view -> login()); - mPassword.setOnEditorActionListener( - (textView, actionId, keyEvent) -> { - if (actionId == EditorInfo.IME_ACTION_DONE) { - mSignupButton.performClick(); - return true; - } - return false; - }); + + rootView.findViewById(R.id.getStarted).setOnClickListener(view -> onGetStartedClicked()); + + mPassword.setOnEditorActionListener((textView, actionId, keyEvent) -> onPasswordEditorAction(textView, actionId, keyEvent)); + + mKeepMeLoggedInCheckbox.setChecked(HifiUtils.getInstance().isKeepingLoggedIn()); + return rootView; } @@ -101,15 +114,22 @@ public class SignupFragment extends Fragment { @Override public void onStop() { super.onStop(); - cancelActivityIndicator(); // Leave the Qt app paused QtNative.setApplicationState(ApplicationInactive); hideKeyboard(); } - private void login() { + private boolean onPasswordEditorAction(TextView textView, int actionId, KeyEvent keyEvent) { + if (actionId == EditorInfo.IME_ACTION_DONE) { + mSignupButton.performClick(); + return true; + } + return false; + } + + private void onCancelSignup() { if (mListener != null) { - mListener.onLoginRequested(); + mListener.onCancelSignup(); } } @@ -123,8 +143,11 @@ public class SignupFragment extends Fragment { } else { mSignupButton.setEnabled(false); hideError(); + mActivityText.setText(R.string.creating_account); showActivityIndicator(); - nativeSignup(email, username, password); + mSignupInProgress = true; + mSignupSuccess = false; + signup(email, username, password); } } @@ -137,23 +160,21 @@ public class SignupFragment extends Fragment { } private void showActivityIndicator() { - if (mDialog == null) { - mDialog = new ProgressDialog(getContext()); - } - mDialog.setMessage(getString(R.string.creating_account)); - mDialog.setCancelable(true); - mDialog.setOnCancelListener(dialogInterface -> { - nativeCancelSignup(); - cancelActivityIndicator(); - mSignupButton.setEnabled(true); - }); - mDialog.show(); + mSignupForm.setVisibility(View.GONE); + mLoggedInFrame.setVisibility(View.GONE); + mLoggingInFrame.setVisibility(View.VISIBLE); } - private void cancelActivityIndicator() { - if (mDialog != null) { - mDialog.cancel(); - } + private void showLoggedInMessage() { + mSignupForm.setVisibility(View.GONE); + mLoggingInFrame.setVisibility(View.GONE); + mLoggedInFrame.setVisibility(View.VISIBLE); + } + + private void showSignupForm() { + mLoggingInFrame.setVisibility(View.GONE); + mLoggedInFrame.setVisibility(View.GONE); + mSignupForm.setVisibility(View.VISIBLE); } private void showError(String error) { mError.setText(error); @@ -167,51 +188,73 @@ public class SignupFragment extends Fragment { public interface OnSignupInteractionListener { void onSignupCompleted(); - void onLoginRequested(); + void onCancelSignup(); } + private void onGetStartedClicked() { + if (mListener != null) { + mListener.onSignupCompleted(); + } + } + + public void handleSignupCompleted() { + mSignupInProgress = false; String username = mUsername.getText().toString().trim(); String password = mPassword.getText().toString(); - mDialog.setMessage(getString(R.string.logging_in)); - mDialog.setCancelable(true); - mDialog.setOnCancelListener(dialogInterface -> { - nativeCancelLogin(); - cancelActivityIndicator(); - if (mListener != null) { - mListener.onLoginRequested(); - } + getActivity().runOnUiThread(() -> { + mActivityText.setText(R.string.logging_in); }); - mDialog.show(); - nativeLogin(username, password, getActivity()); + mLoginInProgress = true; + boolean keepUserLoggedIn = mKeepMeLoggedInCheckbox.isChecked(); + login(username, password, keepUserLoggedIn); } public void handleSignupFailed(String error) { + mSignupInProgress = false; getActivity().runOnUiThread(() -> { mSignupButton.setEnabled(true); - cancelActivityIndicator(); + showSignupForm(); mError.setText(error); mError.setVisibility(View.VISIBLE); }); } public void handleLoginCompleted(boolean success) { + mLoginInProgress = false; getActivity().runOnUiThread(() -> { mSignupButton.setEnabled(true); - cancelActivityIndicator(); - if (success) { - if (mListener != null) { - mListener.onSignupCompleted(); - } + mSignupSuccess = true; + showLoggedInMessage(); } else { // Registration was successful but login failed. // Let the user to login manually - mListener.onLoginRequested(); + mListener.onCancelSignup(); + showSignupForm(); } }); } + @Override + public boolean doBack() { + if (mSignupInProgress) { + cancelSignup(); + } else if (mLoginInProgress) { + cancelLogin(); + } - + if (mSignupInProgress || mLoginInProgress) { + showSignupForm(); + mLoginInProgress = false; + mSignupInProgress = false; + mSignupButton.setEnabled(true); + return true; + } else if (mSignupSuccess) { + onGetStartedClicked(); + return true; + } else { + return false; + } + } } diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/StartMenuFragment.java b/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/StartMenuFragment.java new file mode 100644 index 0000000000..fe77991962 --- /dev/null +++ b/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/StartMenuFragment.java @@ -0,0 +1,93 @@ +package io.highfidelity.hifiinterface.fragment; + +import android.app.Fragment; +import android.content.Context; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import io.highfidelity.hifiinterface.R; + +public class StartMenuFragment extends Fragment { + + private String TAG = "HighFidelity"; + private StartMenuInteractionListener mListener; + + public StartMenuFragment() { + // Required empty public constructor + } + + public static StartMenuFragment newInstance() { + StartMenuFragment fragment = new StartMenuFragment(); + return fragment; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + View rootView = inflater.inflate(R.layout.fragment_login_menu, container, false); + rootView.findViewById(R.id.signupButton).setOnClickListener(view -> { + if (mListener != null) { + mListener.onSignupButtonClicked(); + } + }); + + rootView.findViewById(R.id.loginButton).setOnClickListener(view -> { + if (mListener != null) { + mListener.onLoginButtonClicked(); + } + }); + + rootView.findViewById(R.id.steamLoginButton).setOnClickListener(view -> { + if (mListener != null) { + mListener.onSteamLoginButtonClicked(); + } + }); + + rootView.findViewById(R.id.takeMeInWorld).setOnClickListener(view -> { + if (mListener != null) { + mListener.onSkipLoginClicked(); + } + }); + + + + return rootView; + } + + @Override + public void onAttach(Context context) { + super.onAttach(context); + if (context instanceof StartMenuInteractionListener) { + mListener = (StartMenuInteractionListener) context; + } else { + throw new RuntimeException(context.toString() + + " must implement StartMenuInteractionListener"); + } + } + + @Override + public void onDetach() { + super.onDetach(); + mListener = null; + } + + /** + * This interface must be implemented by activities that contain this + * fragment to allow an interaction in this fragment to be communicated + * to the activity and potentially other fragments contained in that + * activity. + *

+ * See the Android Training lesson Communicating with Other Fragments for more information. + */ + public interface StartMenuInteractionListener { + void onSignupButtonClicked(); + void onLoginButtonClicked(); + void onSkipLoginClicked(); + void onSteamLoginButtonClicked(); + } +} diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/WebViewFragment.java b/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/WebViewFragment.java index 2d887d5a19..3614fe47e4 100644 --- a/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/WebViewFragment.java +++ b/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/WebViewFragment.java @@ -4,9 +4,11 @@ import android.app.Fragment; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; +import android.net.Uri; import android.net.http.SslError; import android.os.Bundle; import android.os.Handler; +import android.text.TextUtils; import android.view.GestureDetector; import android.view.KeyEvent; import android.view.LayoutInflater; @@ -14,6 +16,7 @@ import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.animation.AlphaAnimation; +import android.webkit.CookieManager; import android.webkit.SslErrorHandler; import android.webkit.WebChromeClient; import android.webkit.WebResourceError; @@ -25,6 +28,7 @@ import android.webkit.WebViewClient; import android.widget.ProgressBar; import android.widget.Toast; +import io.highfidelity.hifiinterface.BuildConfig; import io.highfidelity.hifiinterface.R; import io.highfidelity.hifiinterface.WebViewActivity; @@ -32,6 +36,7 @@ public class WebViewFragment extends Fragment implements GestureDetector.OnGestu public static final String URL = "url"; public static final String TOOLBAR_VISIBLE = "toolbar_visible"; + public static final String CLEAR_COOKIES = "clear_cookies"; private static final long DELAY_HIDE_TOOLBAR_MILLIS = 3000; private static final long FADE_OUT_DURATION = 2000; @@ -41,6 +46,7 @@ public class WebViewFragment extends Fragment implements GestureDetector.OnGestu private ProgressBar mProgressBar; private String mUrl; private boolean mToolbarVisible; + private boolean mClearCookies; private OnWebViewInteractionListener mListener; private Runnable mCloseAction; @@ -170,6 +176,7 @@ public class WebViewFragment extends Fragment implements GestureDetector.OnGestu if (getArguments() != null) { mUrl = getArguments().getString(URL); mToolbarVisible = getArguments().getBoolean(TOOLBAR_VISIBLE); + mClearCookies = getArguments().getBoolean(CLEAR_COOKIES); } } @@ -179,6 +186,10 @@ public class WebViewFragment extends Fragment implements GestureDetector.OnGestu View rootView = inflater.inflate(R.layout.fragment_web_view, container, false); mProgressBar = rootView.findViewById(R.id.toolbarProgressBar); myWebView = rootView.findViewById(R.id.web_view); + if (mClearCookies) { + CookieManager.getInstance().removeAllCookies(null); + } + mHandler = new Handler(); gestureDetector = new GestureDetector(this); gestureDetector.setOnDoubleTapListener(new GestureDetector.OnDoubleTapListener() { @@ -251,6 +262,7 @@ public class WebViewFragment extends Fragment implements GestureDetector.OnGestu void onWebLoaded(String url, SafenessLevel safenessLevel); void onTitleReceived(String title); void onExpand(); + void onOAuthAuthorizeCallback(Uri uri); } @@ -320,6 +332,18 @@ public class WebViewFragment extends Fragment implements GestureDetector.OnGestu super.onLoadResource(view, url); } } + + @Override + public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { + if (!TextUtils.isEmpty(BuildConfig.OAUTH_REDIRECT_URI) && + request.getUrl().toString().startsWith(BuildConfig.OAUTH_REDIRECT_URI)) { + if (mListener != null) { + mListener.onOAuthAuthorizeCallback(request.getUrl()); + } + return true; + } + return super.shouldOverrideUrlLoading(view, request); + } } class HiFiWebChromeClient extends WebChromeClient { diff --git a/android/app/src/main/res/drawable/encourage_login_background.jpg b/android/app/src/main/res/drawable/encourage_login_background.jpg new file mode 100644 index 0000000000..5382880c3e Binary files /dev/null and b/android/app/src/main/res/drawable/encourage_login_background.jpg differ diff --git a/android/app/src/main/res/drawable/hifi_header.xml b/android/app/src/main/res/drawable/hifi_header.xml index 9f7c85297a..7762fea81e 100644 --- a/android/app/src/main/res/drawable/hifi_header.xml +++ b/android/app/src/main/res/drawable/hifi_header.xml @@ -1,6 +1,6 @@ diff --git a/android/app/src/main/res/drawable/ic_right_arrow.xml b/android/app/src/main/res/drawable/ic_right_arrow.xml new file mode 100644 index 0000000000..e35d1a2733 --- /dev/null +++ b/android/app/src/main/res/drawable/ic_right_arrow.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/drawable/ic_steam.xml b/android/app/src/main/res/drawable/ic_steam.xml new file mode 100644 index 0000000000..9b739c1f73 --- /dev/null +++ b/android/app/src/main/res/drawable/ic_steam.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/drawable/rounded_button.xml b/android/app/src/main/res/drawable/rounded_button_color1.xml similarity index 100% rename from android/app/src/main/res/drawable/rounded_button.xml rename to android/app/src/main/res/drawable/rounded_button_color1.xml diff --git a/android/app/src/main/res/drawable/rounded_button_color3.xml b/android/app/src/main/res/drawable/rounded_button_color3.xml new file mode 100644 index 0000000000..6230885b30 --- /dev/null +++ b/android/app/src/main/res/drawable/rounded_button_color3.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/drawable/rounded_button_color4.xml b/android/app/src/main/res/drawable/rounded_button_color4.xml new file mode 100644 index 0000000000..679bf24513 --- /dev/null +++ b/android/app/src/main/res/drawable/rounded_button_color4.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/drawable/rounded_edit.xml b/android/app/src/main/res/drawable/rounded_edit.xml deleted file mode 100644 index 3c1cac4d1d..0000000000 --- a/android/app/src/main/res/drawable/rounded_edit.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/android/app/src/main/res/layout/activity_encourage_login.xml b/android/app/src/main/res/layout/activity_encourage_login.xml new file mode 100644 index 0000000000..d7c9ff6b4d --- /dev/null +++ b/android/app/src/main/res/layout/activity_encourage_login.xml @@ -0,0 +1,14 @@ + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/fragment_login.xml b/android/app/src/main/res/layout/fragment_login.xml index 6933ad1eb5..d12b84cc8d 100644 --- a/android/app/src/main/res/layout/fragment_login.xml +++ b/android/app/src/main/res/layout/fragment_login.xml @@ -6,6 +6,17 @@ android:layout_height="match_parent" android:background="@color/backgroundLight"> + + + + - - - - - - - - - -