diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index ed9caee58b..8828335cd1 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -47,8 +47,9 @@
-
+ android:theme="@style/AppTheme" />
+
+
+
diff --git a/android/app/src/main/cpp/native.cpp b/android/app/src/main/cpp/native.cpp
index 2e6da456eb..19d8b9ce7e 100644
--- a/android/app/src/main/cpp/native.cpp
+++ b/android/app/src/main/cpp/native.cpp
@@ -23,7 +23,9 @@
#include "AndroidHelper.h"
#include
-QAndroidJniObject __activity;
+QAndroidJniObject __interfaceActivity;
+QAndroidJniObject __loginActivity;
+QAndroidJniObject __loadCompleteListener;
void tempMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) {
if (!message.isEmpty()) {
@@ -143,16 +145,16 @@ void unpackAndroidAssets() {
extern "C" {
JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeOnCreate(JNIEnv* env, jobject obj, jobject instance, jobject asset_mgr) {
- qDebug() << "nativeOnCreate On thread " << QThread::currentThreadId();
g_assetManager = AAssetManager_fromJava(env, asset_mgr);
- __activity = QAndroidJniObject(instance);
+ qRegisterMetaType("QAndroidJniObject");
+ __interfaceActivity = QAndroidJniObject(instance);
auto oldMessageHandler = qInstallMessageHandler(tempMessageHandler);
unpackAndroidAssets();
qInstallMessageHandler(oldMessageHandler);
QObject::connect(&AndroidHelper::instance(), &AndroidHelper::androidActivityRequested, [](const QString& a) {
QAndroidJniObject string = QAndroidJniObject::fromString(a);
- __activity.callMethod("openGotoActivity", "(Ljava/lang/String;)V", string.object());
+ __interfaceActivity.callMethod("openGotoActivity", "(Ljava/lang/String;)V", string.object());
});
}
@@ -168,15 +170,12 @@ JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeGotoUr
}
JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeOnPause(JNIEnv* env, jobject obj) {
- qDebug() << "nativeOnPause";
}
JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeOnResume(JNIEnv* env, jobject obj) {
- qDebug() << "nativeOnResume";
}
JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeOnExitVr(JNIEnv* env, jobject obj) {
- qDebug() << "nativeOnCreate On thread " << QThread::currentThreadId();
}
JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeGoBackFromAndroidActivity(JNIEnv *env, jobject instance) {
@@ -209,4 +208,67 @@ JNIEXPORT jstring JNICALL Java_io_highfidelity_hifiinterface_HifiUtils_protocolV
return env->NewStringUTF(protocolVersionsSignatureBase64().toLatin1().data());
}
-}
\ No newline at end of file
+JNIEXPORT void JNICALL
+Java_io_highfidelity_hifiinterface_LoginActivity_nativeLogin(JNIEnv *env, jobject instance,
+ jstring username_, jstring password_) {
+ const char *c_username = env->GetStringUTFChars(username_, 0);
+ const char *c_password = env->GetStringUTFChars(password_, 0);
+ QString username = QString(c_username);
+ QString password = QString(c_password);
+ env->ReleaseStringUTFChars(username_, c_username);
+ env->ReleaseStringUTFChars(password_, c_password);
+
+ QSharedPointer accountManager = AndroidHelper::instance().getAccountManager();
+
+ __loginActivity = QAndroidJniObject(instance);
+
+ QObject::connect(accountManager.data(), &AccountManager::loginComplete, [](const QUrl& authURL) {
+ AndroidHelper::instance().notifyLoginComplete(true);
+ });
+
+ QObject::connect(accountManager.data(), &AccountManager::loginFailed, []() {
+ AndroidHelper::instance().notifyLoginComplete(false);
+ });
+
+ QObject::connect(&AndroidHelper::instance(), &AndroidHelper::loginComplete, [](bool success) {
+ jboolean jSuccess = (jboolean) success;
+ __loginActivity.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_SplashActivity_registerLoadCompleteListener(JNIEnv *env,
+ jobject instance) {
+
+ __loadCompleteListener = QAndroidJniObject(instance);
+
+ QObject::connect(&AndroidHelper::instance(), &AndroidHelper::qtAppLoadComplete, []() {
+
+ __loadCompleteListener.callMethod("onAppLoadedComplete", "()V");
+ __interfaceActivity.callMethod("onAppLoadedComplete", "()V");
+
+ QObject::disconnect(&AndroidHelper::instance(), &AndroidHelper::qtAppLoadComplete, nullptr,
+ nullptr);
+ });
+
+}
+JNIEXPORT jboolean JNICALL
+Java_io_highfidelity_hifiinterface_HomeActivity_nativeIsLoggedIn(JNIEnv *env, jobject instance) {
+ return AndroidHelper::instance().getAccountManager()->isLoggedIn();
+}
+
+JNIEXPORT void JNICALL
+Java_io_highfidelity_hifiinterface_HomeActivity_nativeLogout(JNIEnv *env, jobject instance) {
+ AndroidHelper::instance().getAccountManager()->logout();
+}
+
+JNIEXPORT jstring JNICALL
+Java_io_highfidelity_hifiinterface_HomeActivity_nativeGetDisplayName(JNIEnv *env,
+ jobject instance) {
+ QString username = AndroidHelper::instance().getAccountManager()->getAccountInfo().getUsername();
+ return env->NewStringUTF(username.toLatin1().data());
+}
+
+}
diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/GotoActivity.java b/android/app/src/main/java/io/highfidelity/hifiinterface/GotoActivity.java
index a83f93d080..f1ecc21d84 100644
--- a/android/app/src/main/java/io/highfidelity/hifiinterface/GotoActivity.java
+++ b/android/app/src/main/java/io/highfidelity/hifiinterface/GotoActivity.java
@@ -9,7 +9,6 @@ import android.support.v7.widget.Toolbar;
import android.view.KeyEvent;
import android.view.MenuItem;
import android.view.View;
-import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
import java.net.URI;
diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/HomeActivity.java b/android/app/src/main/java/io/highfidelity/hifiinterface/HomeActivity.java
index 35cf49151d..4a75eef98f 100644
--- a/android/app/src/main/java/io/highfidelity/hifiinterface/HomeActivity.java
+++ b/android/app/src/main/java/io/highfidelity/hifiinterface/HomeActivity.java
@@ -1,9 +1,7 @@
package io.highfidelity.hifiinterface;
-import android.app.ProgressDialog;
import android.content.Intent;
import android.graphics.Color;
-import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.NavigationView;
@@ -22,21 +20,23 @@ import android.widget.TabHost;
import android.widget.TabWidget;
import android.widget.TextView;
-import io.highfidelity.hifiinterface.QtPreloader.QtPreloader;
import io.highfidelity.hifiinterface.view.DomainAdapter;
public class HomeActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener {
+ public native boolean nativeIsLoggedIn();
+ public native void nativeLogout();
+ public native String nativeGetDisplayName();
+
/**
* Set this intent extra param to NOT start a new InterfaceActivity after a domain is selected"
*/
- public static final String PARAM_NOT_START_INTERFACE_ACTIVITY = "not_start_interface_activity";
+ //public static final String PARAM_NOT_START_INTERFACE_ACTIVITY = "not_start_interface_activity";
public static final int ENTER_DOMAIN_URL = 1;
private DomainAdapter domainAdapter;
private DrawerLayout mDrawerLayout;
- private ProgressDialog mDialog;
private NavigationView mNavigationView;
@Override
@@ -87,7 +87,7 @@ public class HomeActivity extends AppCompatActivity implements NavigationView.On
int numberOfColumns = 1;
GridLayoutManager gridLayoutMgr = new GridLayoutManager(this, numberOfColumns);
domainsView.setLayoutManager(gridLayoutMgr);
- domainAdapter = new DomainAdapter(this, "");
+ domainAdapter = new DomainAdapter(this, HifiUtils.getInstance().protocolVersionSignature());
domainAdapter.setClickListener(new DomainAdapter.ItemClickListener() {
@Override
@@ -107,63 +107,30 @@ public class HomeActivity extends AppCompatActivity implements NavigationView.On
searchTextView.setTextAppearance(R.style.SearchText);
}
- if (getIntent() == null ||
- !getIntent().hasExtra(PARAM_NOT_START_INTERFACE_ACTIVITY) ||
- !getIntent().getBooleanExtra(PARAM_NOT_START_INTERFACE_ACTIVITY, false)) {
- preloadQt();
- showActivityIndicator();
- }
+ updateLoginMenu();
}
+ private void updateLoginMenu() {
+ TextView loginOption = findViewById(R.id.login);
+ TextView logoutOption = findViewById(R.id.logout);
+ if (nativeIsLoggedIn()) {
+ loginOption.setVisibility(View.GONE);
+ logoutOption.setVisibility(View.VISIBLE);
+ } else {
+ loginOption.setVisibility(View.VISIBLE);
+ logoutOption.setVisibility(View.GONE);
+ }
+ }
+
private void gotoDomain(String domainUrl) {
Intent intent = new Intent(HomeActivity.this, InterfaceActivity.class);
intent.putExtra(InterfaceActivity.DOMAIN_URL, domainUrl);
HomeActivity.this.finish();
- if (getIntent() != null &&
- getIntent().hasExtra(PARAM_NOT_START_INTERFACE_ACTIVITY) &&
- getIntent().getBooleanExtra(PARAM_NOT_START_INTERFACE_ACTIVITY, false)) {
- intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
- }
+ intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);
}
- private void showActivityIndicator() {
- if (mDialog == null) {
- mDialog = new ProgressDialog(this);
- }
- mDialog.setMessage("Please wait...");
- mDialog.setCancelable(false);
- mDialog.show();
- }
-
- private void cancelActivityIndicator() {
- if (mDialog != null) {
- mDialog.cancel();
- }
- }
-
- private AsyncTask preloadTask;
-
- private void preloadQt() {
- if (preloadTask == null) {
- preloadTask = new AsyncTask() {
- @Override
- protected Object doInBackground(Object[] objects) {
- new QtPreloader(HomeActivity.this).initQt();
- runOnUiThread(new Runnable() {
- @Override
- public void run() {
- cancelActivityIndicator();
- }
- });
- return null;
- }
- };
- preloadTask.execute();
- }
- }
-
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
@@ -188,7 +155,6 @@ public class HomeActivity extends AppCompatActivity implements NavigationView.On
@Override
protected void onDestroy() {
- cancelActivityIndicator();
super.onDestroy();
}
@@ -199,8 +165,6 @@ public class HomeActivity extends AppCompatActivity implements NavigationView.On
Intent i = new Intent(this, GotoActivity.class);
startActivityForResult(i, ENTER_DOMAIN_URL);
return true;
- case R.id.action_settings:
- return true;
}
return false;
}
@@ -213,4 +177,19 @@ public class HomeActivity extends AppCompatActivity implements NavigationView.On
}
}
+ @Override
+ protected void onStart() {
+ super.onStart();
+ updateLoginMenu();
+ }
+
+ public void onLoginClicked(View view) {
+ Intent intent = new Intent(this, LoginActivity.class);
+ startActivity(intent);
+ }
+
+ public void onLogoutClicked(View view) {
+ nativeLogout();
+ updateLoginMenu();
+ }
}
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 678f7e8aac..2b86abc9da 100644
--- a/android/app/src/main/java/io/highfidelity/hifiinterface/InterfaceActivity.java
+++ b/android/app/src/main/java/io/highfidelity/hifiinterface/InterfaceActivity.java
@@ -63,6 +63,7 @@ public class InterfaceActivity extends QtActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
+ super.isLoading = true;
Intent intent = getIntent();
if (intent.hasExtra(DOMAIN_URL) && !intent.getStringExtra(DOMAIN_URL).isEmpty()) {
intent.putExtra("applicationArguments", "--url "+intent.getStringExtra(DOMAIN_URL));
@@ -112,6 +113,8 @@ public class InterfaceActivity extends QtActivity {
}
}
});
+ startActivity(new Intent(this, SplashActivity.class));
+
}
@Override
@@ -201,7 +204,6 @@ public class InterfaceActivity extends QtActivity {
switch (activityName) {
case "Goto": {
Intent intent = new Intent(this, HomeActivity.class);
- intent.putExtra(HomeActivity.PARAM_NOT_START_INTERFACE_ACTIVITY, true);
startActivity(intent);
break;
}
@@ -212,4 +214,8 @@ public class InterfaceActivity extends QtActivity {
}
}
+ public void onAppLoadedComplete() {
+ super.isLoading = false;
+ }
+
}
\ No newline at end of file
diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/LoginActivity.java b/android/app/src/main/java/io/highfidelity/hifiinterface/LoginActivity.java
new file mode 100644
index 0000000000..9fd256aa82
--- /dev/null
+++ b/android/app/src/main/java/io/highfidelity/hifiinterface/LoginActivity.java
@@ -0,0 +1,106 @@
+package io.highfidelity.hifiinterface;
+
+import android.app.ProgressDialog;
+import android.support.annotation.MainThread;
+import android.support.v7.app.AppCompatActivity;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.inputmethod.EditorInfo;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.Toast;
+
+public class LoginActivity extends AppCompatActivity {
+
+ public native void nativeLogin(String username, String password);
+
+ private EditText mUsername;
+ private EditText mPassword;
+ private TextView mError;
+ private Button mLoginButton;
+
+ private ProgressDialog mDialog;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_login);
+
+ mUsername = findViewById(R.id.username);
+ mPassword = findViewById(R.id.password);
+ mError = findViewById(R.id.error);
+ mLoginButton = findViewById(R.id.loginButton);
+
+ mPassword.setOnEditorActionListener(
+ new TextView.OnEditorActionListener() {
+ @Override
+ public boolean onEditorAction(TextView textView, int actionId, KeyEvent keyEvent) {
+ if (actionId == EditorInfo.IME_ACTION_DONE) {
+ mLoginButton.performClick();
+ return true;
+ }
+ return false;
+ }
+ });
+
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ cancelActivityIndicator();
+ }
+
+ public void login(View view) {
+ String username = mUsername.getText().toString();
+ String password = mPassword.getText().toString();
+ if (username.isEmpty() || password.isEmpty()) {
+ showError(getString(R.string.login_username_or_password_incorrect));
+ } else {
+ mLoginButton.setEnabled(false);
+ hideError();
+ showActivityIndicator();
+ nativeLogin(username, password);
+ }
+ }
+
+ private void showActivityIndicator() {
+ if (mDialog == null) {
+ mDialog = new ProgressDialog(this);
+ }
+ mDialog.setMessage(getString(R.string.logging_in));
+ mDialog.setCancelable(false);
+ mDialog.show();
+ }
+
+ private void cancelActivityIndicator() {
+ if (mDialog != null) {
+ mDialog.cancel();
+ }
+ }
+ private void showError(String error) {
+ mError.setText(error);
+ mError.setVisibility(View.VISIBLE);
+ }
+
+ private void hideError() {
+ mError.setText("");
+ mError.setVisibility(View.INVISIBLE);
+ }
+
+ public void handleLoginCompleted(boolean success) {
+ runOnUiThread(() -> {
+ mLoginButton.setEnabled(true);
+ cancelActivityIndicator();
+ if (success) {
+ finish();
+ } else {
+ showError(getString(R.string.login_username_or_password_incorrect));
+ }
+ });
+ }
+
+}
diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/PermissionChecker.java b/android/app/src/main/java/io/highfidelity/hifiinterface/PermissionChecker.java
index b1c5f570c8..2b48d85a48 100644
--- a/android/app/src/main/java/io/highfidelity/hifiinterface/PermissionChecker.java
+++ b/android/app/src/main/java/io/highfidelity/hifiinterface/PermissionChecker.java
@@ -64,7 +64,7 @@ public class PermissionChecker extends Activity {
private void launchActivityWithPermissions(){
finish();
- Intent i = new Intent(this, HomeActivity.class);
+ Intent i = new Intent(this, InterfaceActivity.class);
startActivity(i);
finish();
}
diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/QtPreloader/QtPreloader.java b/android/app/src/main/java/io/highfidelity/hifiinterface/QtPreloader/QtPreloader.java
deleted file mode 100644
index d9ecdb9710..0000000000
--- a/android/app/src/main/java/io/highfidelity/hifiinterface/QtPreloader/QtPreloader.java
+++ /dev/null
@@ -1,315 +0,0 @@
-package io.highfidelity.hifiinterface.QtPreloader;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.pm.ComponentInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.res.AssetManager;
-import android.os.Bundle;
-import android.util.Log;
-
-import org.qtproject.qt5.android.bindings.QtApplication;
-
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-
-import dalvik.system.DexClassLoader;
-
-/**
- * Created by Gabriel Calero & Cristian Duarte on 3/22/18.
- */
-
-public class QtPreloader {
-
- public String ENVIRONMENT_VARIABLES = "QT_USE_ANDROID_NATIVE_DIALOGS=1";
- private ComponentInfo m_contextInfo;
- private String[] m_qtLibs = null; // required qt libs
- private Context m_context;
-
- private static final String DEX_PATH_KEY = "dex.path";
- private static final String LIB_PATH_KEY = "lib.path";
- private static final String NATIVE_LIBRARIES_KEY = "native.libraries";
- private static final String ENVIRONMENT_VARIABLES_KEY = "environment.variables";
- private static final String BUNDLED_LIBRARIES_KEY = "bundled.libraries";
- private static final String BUNDLED_IN_LIB_RESOURCE_ID_KEY = "android.app.bundled_in_lib_resource_id";
- private static final String BUNDLED_IN_ASSETS_RESOURCE_ID_KEY = "android.app.bundled_in_assets_resource_id";
- private static final String MAIN_LIBRARY_KEY = "main.library";
-
- private static final int BUFFER_SIZE = 1024;
-
- public QtPreloader(Context context) {
- m_context = context;
- }
-
- public void initQt() {
-
- try {
- m_contextInfo = m_context.getPackageManager().getActivityInfo(new ComponentName("io.highfidelity.hifiinterface", "io.highfidelity.hifiinterface.InterfaceActivity"),
- PackageManager.GET_META_DATA);
-
- if (m_contextInfo.metaData.containsKey("android.app.qt_libs_resource_id")) {
- int resourceId = m_contextInfo.metaData.getInt("android.app.qt_libs_resource_id");
- m_qtLibs = m_context.getResources().getStringArray(resourceId);
- }
- ArrayList libraryList = new ArrayList<>();
- String localPrefix = m_context.getApplicationInfo().dataDir + "/";
- String pluginsPrefix = localPrefix + "qt-reserved-files/";
- cleanOldCacheIfNecessary(localPrefix, pluginsPrefix);
- extractBundledPluginsAndImports(pluginsPrefix);
-
- for (String lib : m_qtLibs) {
- libraryList.add(localPrefix + "lib/lib" + lib + ".so");
- }
-
- if (m_contextInfo.metaData.containsKey("android.app.load_local_libs")) {
- String[] extraLibs = m_contextInfo.metaData.getString("android.app.load_local_libs").split(":");
- for (String lib : extraLibs) {
- if (lib.length() > 0) {
- if (lib.startsWith("lib/")) {
- libraryList.add(localPrefix + lib);
- } else {
- libraryList.add(pluginsPrefix + lib);
- }
- }
- }
- }
-
- Bundle loaderParams = new Bundle();
- loaderParams.putString(DEX_PATH_KEY, new String());
-
- loaderParams.putStringArrayList(NATIVE_LIBRARIES_KEY, libraryList);
-
- loaderParams.putString(ENVIRONMENT_VARIABLES_KEY, ENVIRONMENT_VARIABLES
- + "\tQML2_IMPORT_PATH=" + pluginsPrefix + "/qml"
- + "\tQML_IMPORT_PATH=" + pluginsPrefix + "/imports"
- + "\tQT_PLUGIN_PATH=" + pluginsPrefix + "/plugins");
-
-
- // add all bundled Qt libs to loader params
- ArrayList libs = new ArrayList<>();
-
- String libName = m_contextInfo.metaData.getString("android.app.lib_name");
- loaderParams.putString(MAIN_LIBRARY_KEY, libName); //main library contains main() function
- loaderParams.putStringArrayList(BUNDLED_LIBRARIES_KEY, libs);
-
- // load and start QtLoader class
- DexClassLoader classLoader = new DexClassLoader(loaderParams.getString(DEX_PATH_KEY), // .jar/.apk files
- m_context.getDir("outdex", Context.MODE_PRIVATE).getAbsolutePath(), // directory where optimized DEX files should be written.
- loaderParams.containsKey(LIB_PATH_KEY) ? loaderParams.getString(LIB_PATH_KEY) : null, // libs folder (if exists)
- m_context.getClassLoader()); // parent loader
-
- Class> loaderClass = classLoader.loadClass(loaderClassName()); // load QtLoader class
- Object qtLoader = loaderClass.newInstance(); // create an instance
- Method prepareAppMethod = qtLoader.getClass().getMethod("loadApplication",
- contextClassName(),
- ClassLoader.class,
- Bundle.class);
- prepareAppMethod.invoke(qtLoader, m_context, classLoader, loaderParams);
-
- // now load the application library so it's accessible from this class loader
- if (libName != null) {
- System.loadLibrary(libName);
- }
- } catch (Exception e) {
- Log.e(QtApplication.QtTAG, "Error pre-loading HiFi Qt app", e);
- }
- }
-
- protected String loaderClassName() {
- return "org.qtproject.qt5.android.QtActivityDelegate";
- }
-
- protected Class> contextClassName() {
- return android.app.Activity.class;
- }
-
-
- private void deleteRecursively(File directory) {
- File[] files = directory.listFiles();
- if (files != null) {
- for (File file : files) {
- if (file.isDirectory()) {
- deleteRecursively(file);
- } else {
- file.delete();
- }
- }
-
- directory.delete();
- }
- }
-
- private void cleanOldCacheIfNecessary(String oldLocalPrefix, String localPrefix) {
- File newCache = new File(localPrefix);
- if (!newCache.exists()) {
- {
- File oldPluginsCache = new File(oldLocalPrefix + "plugins/");
- if (oldPluginsCache.exists() && oldPluginsCache.isDirectory()) {
- deleteRecursively(oldPluginsCache);
- }
- }
-
- {
- File oldImportsCache = new File(oldLocalPrefix + "imports/");
- if (oldImportsCache.exists() && oldImportsCache.isDirectory()) {
- deleteRecursively(oldImportsCache);
- }
- }
-
- {
- File oldQmlCache = new File(oldLocalPrefix + "qml/");
- if (oldQmlCache.exists() && oldQmlCache.isDirectory()) {
- deleteRecursively(oldQmlCache);
- }
- }
- }
- }
-
- static private void copyFile(InputStream inputStream, OutputStream outputStream)
- throws IOException {
- byte[] buffer = new byte[BUFFER_SIZE];
-
- int count;
- while ((count = inputStream.read(buffer)) > 0) {
- outputStream.write(buffer, 0, count);
- }
- }
-
- private void copyAsset(String source, String destination)
- throws IOException {
- // Already exists, we don't have to do anything
- File destinationFile = new File(destination);
- if (destinationFile.exists()) {
- return;
- }
-
- File parentDirectory = destinationFile.getParentFile();
- if (!parentDirectory.exists()) {
- parentDirectory.mkdirs();
- }
-
- destinationFile.createNewFile();
-
- AssetManager assetsManager = m_context.getAssets();
- InputStream inputStream = assetsManager.open(source);
- OutputStream outputStream = new FileOutputStream(destinationFile);
- copyFile(inputStream, outputStream);
-
- inputStream.close();
- outputStream.close();
- }
-
- private static void createBundledBinary(String source, String destination)
- throws IOException {
- // Already exists, we don't have to do anything
- File destinationFile = new File(destination);
- if (destinationFile.exists()) {
- return;
- }
-
- File parentDirectory = destinationFile.getParentFile();
- if (!parentDirectory.exists()) {
- parentDirectory.mkdirs();
- }
-
- destinationFile.createNewFile();
-
- InputStream inputStream = new FileInputStream(source);
- OutputStream outputStream = new FileOutputStream(destinationFile);
- copyFile(inputStream, outputStream);
-
- inputStream.close();
- outputStream.close();
- }
-
- private boolean cleanCacheIfNecessary(String pluginsPrefix, long packageVersion) {
- File versionFile = new File(pluginsPrefix + "cache.version");
-
- long cacheVersion = 0;
- if (versionFile.exists() && versionFile.canRead()) {
- try {
- DataInputStream inputStream = new DataInputStream(new FileInputStream(versionFile));
- cacheVersion = inputStream.readLong();
- inputStream.close();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- if (cacheVersion != packageVersion) {
- deleteRecursively(new File(pluginsPrefix));
- return true;
- } else {
- return false;
- }
- }
-
- private void extractBundledPluginsAndImports(String pluginsPrefix) throws IOException {
- String libsDir = m_context.getApplicationInfo().nativeLibraryDir + "/";
- long packageVersion = -1;
- try {
- PackageInfo packageInfo = m_context.getPackageManager().getPackageInfo(m_context.getPackageName(), 0);
- packageVersion = packageInfo.lastUpdateTime;
- } catch (Exception e) {
- e.printStackTrace();
- }
-
-
- if (!cleanCacheIfNecessary(pluginsPrefix, packageVersion)) {
- return;
- }
-
- {
- File versionFile = new File(pluginsPrefix + "cache.version");
-
- File parentDirectory = versionFile.getParentFile();
- if (!parentDirectory.exists()) {
- parentDirectory.mkdirs();
- }
-
- versionFile.createNewFile();
-
- DataOutputStream outputStream = new DataOutputStream(new FileOutputStream(versionFile));
- outputStream.writeLong(packageVersion);
- outputStream.close();
- }
-
- {
- String key = BUNDLED_IN_LIB_RESOURCE_ID_KEY;
- if (m_contextInfo.metaData.containsKey(key)) {
- String[] list = m_context.getResources().getStringArray(m_contextInfo.metaData.getInt(key));
-
- for (String bundledImportBinary : list) {
- String[] split = bundledImportBinary.split(":");
- String sourceFileName = libsDir + split[0];
- String destinationFileName = pluginsPrefix + split[1];
- createBundledBinary(sourceFileName, destinationFileName);
- }
- }
- }
-
- {
- String key = BUNDLED_IN_ASSETS_RESOURCE_ID_KEY;
- if (m_contextInfo.metaData.containsKey(key)) {
- String[] list = m_context.getResources().getStringArray(m_contextInfo.metaData.getInt(key));
-
- for (String fileName : list) {
- String[] split = fileName.split(":");
- String sourceFileName = split[0];
- String destinationFileName = pluginsPrefix + split[1];
- copyAsset(sourceFileName, destinationFileName);
- }
- }
-
- }
- }
-}
diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/SplashActivity.java b/android/app/src/main/java/io/highfidelity/hifiinterface/SplashActivity.java
new file mode 100644
index 0000000000..b663a3e396
--- /dev/null
+++ b/android/app/src/main/java/io/highfidelity/hifiinterface/SplashActivity.java
@@ -0,0 +1,32 @@
+package io.highfidelity.hifiinterface;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+
+public class SplashActivity extends Activity {
+
+ private native void registerLoadCompleteListener();
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_splash);
+ registerLoadCompleteListener();
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ }
+
+ public void onAppLoadedComplete() {
+ startActivity(new Intent(this, HomeActivity.class));
+ finish();
+ }
+}
diff --git a/android/app/src/main/java/org/qtproject/qt5/android/bindings/QtActivity.java b/android/app/src/main/java/org/qtproject/qt5/android/bindings/QtActivity.java
index ed55c16cde..887d27dba4 100644
--- a/android/app/src/main/java/org/qtproject/qt5/android/bindings/QtActivity.java
+++ b/android/app/src/main/java/org/qtproject/qt5/android/bindings/QtActivity.java
@@ -68,6 +68,8 @@ public class QtActivity extends Activity {
public final String QT_ANDROID_DEFAULT_THEME = QT_ANDROID_THEMES[0]; // sets the default theme.
private QtActivityLoader m_loader = new QtActivityLoader(this);
+ public boolean isLoading;
+
public QtActivity() {
}
@@ -499,7 +501,11 @@ public class QtActivity extends Activity {
@Override
protected void onPause() {
super.onPause();
- QtApplication.invokeDelegate();
+ // GC: this trick allow us to show a splash activity until Qt app finishes
+ // loading
+ if (!isLoading) {
+ QtApplication.invokeDelegate();
+ }
}
//---------------------------------------------------------------------------
diff --git a/android/app/src/main/res/drawable/hifi_header.xml b/android/app/src/main/res/drawable/hifi_header.xml
new file mode 100644
index 0000000000..9f7c85297a
--- /dev/null
+++ b/android/app/src/main/res/drawable/hifi_header.xml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ 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.xml
new file mode 100644
index 0000000000..11a9f90c8b
--- /dev/null
+++ b/android/app/src/main/res/drawable/rounded_button.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
new file mode 100644
index 0000000000..3c1cac4d1d
--- /dev/null
+++ b/android/app/src/main/res/drawable/rounded_edit.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/activity_home.xml b/android/app/src/main/res/layout/activity_home.xml
index 144ca84a0f..ea24faf823 100644
--- a/android/app/src/main/res/layout/activity_home.xml
+++ b/android/app/src/main/res/layout/activity_home.xml
@@ -33,6 +33,29 @@
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:menu="@menu/menu_home"
- />
+ >
+
+
+
+
+
diff --git a/android/app/src/main/res/layout/activity_login.xml b/android/app/src/main/res/layout/activity_login.xml
new file mode 100644
index 0000000000..ecf72b94bf
--- /dev/null
+++ b/android/app/src/main/res/layout/activity_login.xml
@@ -0,0 +1,106 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/app/src/main/res/layout/activity_splash.xml b/android/app/src/main/res/layout/activity_splash.xml
new file mode 100644
index 0000000000..b38fe3e53c
--- /dev/null
+++ b/android/app/src/main/res/layout/activity_splash.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
diff --git a/android/app/src/main/res/values/colors.xml b/android/app/src/main/res/values/colors.xml
index 0325881f1b..6e756a85fa 100644
--- a/android/app/src/main/res/values/colors.xml
+++ b/android/app/src/main/res/values/colors.xml
@@ -4,10 +4,15 @@
#272727
#000000
#54D7FD
+ #E3E3E3
+ #575757
#1EB5EC
+ #00B4EF
#333333
#4F4F4F
#33999999
#212121
#9e9e9e
+ #F2F2F2
+ #FF7171
diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml
index 6ce0670dd8..14f9100f07 100644
--- a/android/app/src/main/res/values/strings.xml
+++ b/android/app/src/main/res/values/strings.xml
@@ -13,5 +13,12 @@
Go To
Type a domain url
Go
+ Username or email
+ Password
+ Login
+ Logout
+ Forgot password?
+ Username or password incorrect.
+ Logging into High Fidelity
diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml
index 55c9b2af11..5b32de2465 100644
--- a/android/app/src/main/res/values/styles.xml
+++ b/android/app/src/main/res/values/styles.xml
@@ -7,7 +7,14 @@
- @color/colorPrimaryDark
- @color/colorAccent
-
+