diff --git a/android/app/build.gradle b/android/app/build.gradle
index 7a6f34b58b..c63f481f8c 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -104,6 +104,11 @@ dependencies {
implementation 'com.android.support:design:26.1.0'
implementation 'com.android.support:appcompat-v7:26.1.0'
compile 'com.android.support:recyclerview-v7:26.1.0'
+ compile 'com.android.support:cardview-v7:26.1.0'
+
+ compile 'com.squareup.retrofit2:retrofit:2.4.0'
+ compile 'com.squareup.retrofit2:converter-gson:2.4.0'
+ implementation 'com.squareup.picasso:picasso:2.71828'
implementation fileTree(include: ['*.jar'], dir: 'libs')
}
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index ed9caee58b..1b6f3b1304 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -42,18 +42,18 @@
android:name=".HomeActivity"
android:label="@string/home"
android:screenOrientation="portrait"
- android:theme="@style/AppTheme.NoActionBar">
+ android:theme="@style/Theme.AppCompat.Translucent.NoActionBar">
-
+ android:theme="@style/AppTheme" />
+
@@ -75,6 +75,11 @@
+
+
diff --git a/android/app/src/main/assets/hifi_domains.json b/android/app/src/main/assets/hifi_domains.json
deleted file mode 100644
index a63ef7b6aa..0000000000
--- a/android/app/src/main/assets/hifi_domains.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "hifi_domains" : [
- {
- "name": "Your last location",
- "url": "",
- "thumbnail": ""
- },
- {
- "name": "dev-mobile-master",
- "url": "hifi://dev-mobile-master",
- "thumbnail": ""
- },
- {
- "name": "dev-mobile",
- "url": "hifi://dev-mobile",
- "thumbnail": ""
- },
- {
- "name": "dev-welcome",
- "url": "hifi://dev-welcome",
- "thumbnail": ""
- }
- ]
-}
\ No newline at end of file
diff --git a/android/app/src/main/cpp/native.cpp b/android/app/src/main/cpp/native.cpp
index facf6bd4bd..9a5d29d675 100644
--- a/android/app/src/main/cpp/native.cpp
+++ b/android/app/src/main/cpp/native.cpp
@@ -21,8 +21,11 @@
#include
#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()) {
@@ -142,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("openAndroidActivity", "(Ljava/lang/String;)V", string.object());
+ __interfaceActivity.callMethod("openAndroidActivity", "(Ljava/lang/String;)V", string.object());
});
}
@@ -167,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) {
@@ -204,4 +204,68 @@ JNIEXPORT jstring JNICALL Java_io_highfidelity_hifiinterface_HifiUtils_getCurren
return env->NewStringUTF(str.toLatin1().data());
}
+JNIEXPORT jstring JNICALL Java_io_highfidelity_hifiinterface_HifiUtils_protocolVersionSignature(JNIEnv *env, jobject instance) {
+ return env->NewStringUTF(protocolVersionsSignatureBase64().toLatin1().data());
+}
+
+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);
+
+ auto accountManager = AndroidHelper::instance().getAccountManager();
+
+ __loginActivity = QAndroidJniObject(instance);
+
+ QObject::connect(accountManager.data(), &AccountManager::loginComplete, [](const QUrl& authURL) {
+ jboolean jSuccess = (jboolean) true;
+ __loginActivity.callMethod("handleLoginCompleted", "(Z)V", jSuccess);
+ });
+
+ QObject::connect(accountManager.data(), &AccountManager::loginFailed, []() {
+ jboolean jSuccess = (jboolean) false;
+ __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 995e64c2a5..125483da94 100644
--- a/android/app/src/main/java/io/highfidelity/hifiinterface/GotoActivity.java
+++ b/android/app/src/main/java/io/highfidelity/hifiinterface/GotoActivity.java
@@ -9,12 +9,8 @@ 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;
-import java.net.URISyntaxException;
-
public class GotoActivity extends AppCompatActivity {
public static final String PARAM_DOMAIN_URL = "domain_url";
@@ -61,15 +57,7 @@ public class GotoActivity extends AppCompatActivity {
private void actionGo() {
String urlString = mUrlEditText.getText().toString();
if (!urlString.trim().isEmpty()) {
- URI uri;
- try {
- uri = new URI(urlString);
- } catch (URISyntaxException e) {
- return;
- }
- if (uri.getScheme() == null || uri.getScheme().isEmpty()) {
- urlString = "hifi://" + urlString;
- }
+ urlString = HifiUtils.getInstance().sanitizeHifiUrl(urlString);
Intent intent = new Intent();
intent.putExtra(GotoActivity.PARAM_DOMAIN_URL, urlString);
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 15d716548f..368862bc49 100644
--- a/android/app/src/main/java/io/highfidelity/hifiinterface/HifiUtils.java
+++ b/android/app/src/main/java/io/highfidelity/hifiinterface/HifiUtils.java
@@ -1,11 +1,16 @@
package io.highfidelity.hifiinterface;
+import java.net.URI;
+import java.net.URISyntaxException;
+
/**
* Created by Gabriel Calero & Cristian Duarte on 4/13/18.
*/
public class HifiUtils {
+ public static final String BASE_URL = "https://metaverse.highfidelity.com";
+
private static HifiUtils instance;
private HifiUtils() {
@@ -18,6 +23,40 @@ public class HifiUtils {
return instance;
}
+ public String sanitizeHifiUrl(String urlString) {
+ urlString = urlString.trim();
+ if (!urlString.isEmpty()) {
+ URI uri;
+ try {
+ uri = new URI(urlString);
+ } catch (URISyntaxException e) {
+ return urlString;
+ }
+ if (uri.getScheme() == null || uri.getScheme().isEmpty()) {
+ urlString = "hifi://" + urlString;
+ }
+ }
+ return urlString;
+ }
+
+ public String absoluteHifiAssetUrl(String urlString) {
+ urlString = urlString.trim();
+ if (!urlString.isEmpty()) {
+ URI uri;
+ try {
+ uri = new URI(urlString);
+ } catch (URISyntaxException e) {
+ return urlString;
+ }
+ if (uri.getScheme() == null || uri.getScheme().isEmpty()) {
+ urlString = BASE_URL + urlString;
+ }
+ }
+ return urlString;
+ }
+
public native String getCurrentAddress();
+ public native String protocolVersionSignature();
+
}
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 611c8f50cc..62e487f8b7 100644
--- a/android/app/src/main/java/io/highfidelity/hifiinterface/HomeActivity.java
+++ b/android/app/src/main/java/io/highfidelity/hifiinterface/HomeActivity.java
@@ -1,12 +1,11 @@
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.os.Handler;
import android.support.annotation.NonNull;
import android.support.design.widget.NavigationView;
+import android.support.v4.content.ContextCompat;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBar;
@@ -14,30 +13,43 @@ import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
-import android.widget.SearchView;
-import android.widget.TabHost;
-import android.widget.TabWidget;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.EditText;
+import android.widget.ImageView;
import android.widget.TextView;
-import io.highfidelity.hifiinterface.QtPreloader.QtPreloader;
+import org.qtproject.qt5.android.bindings.QtActivity;
+
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 DomainAdapter mDomainAdapter;
private DrawerLayout mDrawerLayout;
- private ProgressDialog mDialog;
private NavigationView mNavigationView;
+ private RecyclerView mDomainsView;
+ private TextView searchNoResultsView;
+ private ImageView mSearchIconView;
+ private ImageView mClearSearch;
+ private EditText mSearchView;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -56,114 +68,111 @@ public class HomeActivity extends AppCompatActivity implements NavigationView.On
mNavigationView = (NavigationView) findViewById(R.id.nav_view);
mNavigationView.setNavigationItemSelectedListener(this);
- TabHost tabs = (TabHost)findViewById(R.id.tabhost);
- tabs.setup();
+ searchNoResultsView = findViewById(R.id.searchNoResultsView);
- TabHost.TabSpec spec=tabs.newTabSpec("featured");
- spec.setContent(R.id.featured);
- spec.setIndicator(getString(R.string.featured));
- tabs.addTab(spec);
-
- spec = tabs.newTabSpec("popular");
- spec.setContent(R.id.popular);
- spec.setIndicator(getString(R.string.popular));
- tabs.addTab(spec);
-
- spec = tabs.newTabSpec("bookmarks");
- spec.setContent(R.id.bookmarks);
- spec.setIndicator(getString(R.string.bookmarks));
- tabs.addTab(spec);
-
- tabs.setCurrentTab(0);
-
- TabWidget tabwidget=tabs.getTabWidget();
- for(int i=0; i 0) {
+ mSearchIconView.setVisibility(View.GONE);
+ mClearSearch.setVisibility(View.VISIBLE);
+ } else {
+ mSearchIconView.setVisibility(View.VISIBLE);
+ mClearSearch.setVisibility(View.GONE);
+ }
+ }
+ });
+ mSearchView.setOnKeyListener((view, i, keyEvent) -> {
+ if (i == KeyEvent.KEYCODE_ENTER) {
+ String urlString = mSearchView.getText().toString();
+ if (!urlString.trim().isEmpty()) {
+ urlString = HifiUtils.getInstance().sanitizeHifiUrl(urlString);
+ }
+ gotoDomain(urlString);
+ return true;
+ }
+ return false;
+ });
+
+ getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
+
+ updateLoginMenu();
+
+ Window window = getWindow();
+ window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+ window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
+ window.setStatusBarColor(ContextCompat.getColor(this, R.color.statusbar_color));
+ }
+
+ 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);
}
-
- if (getIntent() == null ||
- !getIntent().hasExtra(PARAM_NOT_START_INTERFACE_ACTIVITY) ||
- !getIntent().getBooleanExtra(PARAM_NOT_START_INTERFACE_ACTIVITY, false)) {
- preloadQt();
- showActivityIndicator();
- }
-
}
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 +197,6 @@ public class HomeActivity extends AppCompatActivity implements NavigationView.On
@Override
protected void onDestroy() {
- cancelActivityIndicator();
super.onDestroy();
}
@@ -199,8 +207,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,8 +219,27 @@ 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();
+ }
@Override
public void onBackPressed() {
finishAffinity();
}
+
+ public void onSearchClear(View view) {
+ mSearchView.setText("");
+ }
}
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 d2aff85323..419ba8c45e 100644
--- a/android/app/src/main/java/io/highfidelity/hifiinterface/InterfaceActivity.java
+++ b/android/app/src/main/java/io/highfidelity/hifiinterface/InterfaceActivity.java
@@ -36,8 +36,6 @@ public class InterfaceActivity extends QtActivity {
//public static native void handleHifiURL(String hifiURLString);
private native long nativeOnCreate(InterfaceActivity instance, AssetManager assetManager);
- //private native void nativeOnPause();
- //private native void nativeOnResume();
private native void nativeOnDestroy();
private native void nativeGotoUrl(String url);
private native void nativeGoBackFromAndroidActivity();
@@ -63,6 +61,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,31 +111,33 @@ public class InterfaceActivity extends QtActivity {
}
}
});
+ startActivity(new Intent(this, SplashActivity.class));
+
}
@Override
protected void onPause() {
super.onPause();
- //nativeOnPause();
+ nativeEnterBackground();
//gvrApi.pauseTracking();
}
@Override
protected void onStart() {
super.onStart();
- nativeEnterForeground();
+ setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
@Override
protected void onStop() {
super.onStop();
- nativeEnterBackground();
+
}
@Override
protected void onResume() {
super.onResume();
- //nativeOnResume();
+ nativeEnterForeground();
//gvrApi.resumeTracking();
}
@@ -201,7 +202,6 @@ public class InterfaceActivity extends QtActivity {
switch (activityName) {
case "Home": {
Intent intent = new Intent(this, HomeActivity.class);
- intent.putExtra(HomeActivity.PARAM_NOT_START_INTERFACE_ACTIVITY, true);
startActivity(intent);
break;
}
@@ -212,6 +212,10 @@ public class InterfaceActivity extends QtActivity {
}
}
+ public void onAppLoadedComplete() {
+ super.isLoading = false;
+ }
+
@Override
public void onBackPressed() {
openAndroidActivity("Home");
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..45060d6d0c 100644
--- a/android/app/src/main/java/io/highfidelity/hifiinterface/PermissionChecker.java
+++ b/android/app/src/main/java/io/highfidelity/hifiinterface/PermissionChecker.java
@@ -63,8 +63,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..122884b6be
--- /dev/null
+++ b/android/app/src/main/java/io/highfidelity/hifiinterface/SplashActivity.java
@@ -0,0 +1,33 @@
+package io.highfidelity.hifiinterface;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+
+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)); // + 2 sec
+ SplashActivity.this.finish();
+ }
+}
diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/provider/Callback.java b/android/app/src/main/java/io/highfidelity/hifiinterface/provider/Callback.java
new file mode 100644
index 0000000000..64ca6da816
--- /dev/null
+++ b/android/app/src/main/java/io/highfidelity/hifiinterface/provider/Callback.java
@@ -0,0 +1,9 @@
+package io.highfidelity.hifiinterface.provider;
+
+/**
+ * Created by cduarte on 4/18/18.
+ */
+
+public interface Callback {
+ public void callback(T t);
+}
diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/provider/DomainProvider.java b/android/app/src/main/java/io/highfidelity/hifiinterface/provider/DomainProvider.java
new file mode 100644
index 0000000000..7a2101a229
--- /dev/null
+++ b/android/app/src/main/java/io/highfidelity/hifiinterface/provider/DomainProvider.java
@@ -0,0 +1,19 @@
+package io.highfidelity.hifiinterface.provider;
+
+import java.util.List;
+
+import io.highfidelity.hifiinterface.view.DomainAdapter;
+
+/**
+ * Created by cduarte on 4/17/18.
+ */
+
+public interface DomainProvider {
+
+ void retrieve(String filterText, DomainCallback domainCallback);
+
+ interface DomainCallback {
+ void retrieveOk(List domain);
+ void retrieveError(Exception e, String message);
+ }
+}
diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/provider/UserStoryDomainProvider.java b/android/app/src/main/java/io/highfidelity/hifiinterface/provider/UserStoryDomainProvider.java
new file mode 100644
index 0000000000..1e29734243
--- /dev/null
+++ b/android/app/src/main/java/io/highfidelity/hifiinterface/provider/UserStoryDomainProvider.java
@@ -0,0 +1,235 @@
+package io.highfidelity.hifiinterface.provider;
+
+import android.util.Log;
+import android.util.MutableInt;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import io.highfidelity.hifiinterface.HifiUtils;
+import io.highfidelity.hifiinterface.view.DomainAdapter;
+import retrofit2.Call;
+import retrofit2.Response;
+import retrofit2.Retrofit;
+import retrofit2.converter.gson.GsonConverterFactory;
+import retrofit2.http.GET;
+import retrofit2.http.Query;
+
+/**
+ * Created by cduarte on 4/17/18.
+ */
+
+public class UserStoryDomainProvider implements DomainProvider {
+
+ public static final String BASE_URL = "https://metaverse.highfidelity.com/";
+
+ private static final String INCLUDE_ACTIONS_FOR_PLACES = "concurrency";
+ private static final String INCLUDE_ACTIONS_FOR_FULL_SEARCH = "concurrency,announcements,snapshot";
+ private static final int MAX_PAGES_TO_GET = 10;
+
+ private String mProtocol;
+ private Retrofit mRetrofit;
+ private UserStoryDomainProviderService mUserStoryDomainProviderService;
+
+ private boolean startedToGetFromAPI = false;
+ private List allStories; // All retrieved stories from the API
+ private List suggestions; // Filtered places to show
+
+ public UserStoryDomainProvider(String protocol) {
+ mRetrofit = new Retrofit.Builder()
+ .baseUrl(BASE_URL)
+ .addConverterFactory(GsonConverterFactory.create())
+ .build();
+ mUserStoryDomainProviderService = mRetrofit.create(UserStoryDomainProviderService.class);
+ mProtocol = protocol;
+ allStories = new ArrayList<>();
+ suggestions = new ArrayList<>();
+ }
+
+ private void fillDestinations(String filterText, DomainCallback domainCallback) {
+ StoriesFilter filter = new StoriesFilter(filterText);
+ final MutableInt counter = new MutableInt(0);
+ allStories.clear();
+ getUserStoryPage(1,
+ e -> {
+ allStories.subList(counter.value, allStories.size()).forEach(userStory -> {
+ filter.filterOrAdd(userStory);
+ });
+ if (domainCallback != null) {
+ domainCallback.retrieveOk(suggestions); //ended
+ }
+ },
+ a -> {
+ allStories.forEach(userStory -> {
+ counter.value++;
+ filter.filterOrAdd(userStory);
+ });
+ }
+ );
+ }
+
+ private void handleError(String url, Throwable t, Callback restOfPagesCallback) {
+ restOfPagesCallback.callback(new Exception("Error accessing url [" + url + "]", t));
+ }
+
+ private void getUserStoryPage(int pageNumber, Callback restOfPagesCallback, Callback firstPageCallback) {
+ Call userStories = mUserStoryDomainProviderService.getUserStories(
+ INCLUDE_ACTIONS_FOR_PLACES,
+ "open",
+ true,
+ mProtocol,
+ pageNumber);
+ Log.d("API-USER-STORY-DOMAINS", "Protocol [" + mProtocol + "] include_actions [" + INCLUDE_ACTIONS_FOR_PLACES + "]");
+ userStories.enqueue(new retrofit2.Callback() {
+ @Override
+ public void onResponse(Call call, Response response) {
+ UserStories data = response.body();
+ allStories.addAll(data.user_stories);
+ if (data.current_page < data.total_pages && data.current_page <= MAX_PAGES_TO_GET) {
+ if (pageNumber == 1 && firstPageCallback != null) {
+ firstPageCallback.callback(null);
+ }
+ getUserStoryPage(pageNumber + 1, restOfPagesCallback, null);
+ return;
+ }
+ restOfPagesCallback.callback(null);
+ }
+
+ @Override
+ public void onFailure(Call call, Throwable t) {
+ handleError(call.request().url().toString(), t, restOfPagesCallback);
+ }
+ });
+ }
+
+ private class StoriesFilter {
+ String[] mWords = new String[]{};
+ public StoriesFilter(String filterText) {
+ mWords = filterText.toUpperCase().split("\\s+");
+ }
+
+ private boolean matches(UserStory story) {
+ if (mWords.length <= 0) {
+ return true;
+ }
+
+ for (String word : mWords) {
+ if (!story.searchText().contains(word)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private void addToSuggestions(UserStory story) {
+ suggestions.add(story.toDomain());
+ }
+
+ public void filterOrAdd(UserStory story) {
+ if (matches(story)) {
+ addToSuggestions(story);
+ }
+ }
+ }
+
+ private void filterChoicesByText(String filterText, DomainCallback domainCallback) {
+ suggestions.clear();
+ StoriesFilter storiesFilter = new StoriesFilter(filterText);
+ allStories.forEach(story -> {
+ storiesFilter.filterOrAdd(story);
+ });
+ domainCallback.retrieveOk(suggestions);
+ }
+
+ @Override
+ public synchronized void retrieve(String filterText, DomainCallback domainCallback) {
+ if (!startedToGetFromAPI) {
+ startedToGetFromAPI = true;
+ fillDestinations(filterText, domainCallback);
+ } else {
+ filterChoicesByText(filterText, domainCallback);
+ }
+ }
+
+ public void retrieveNot(DomainCallback domainCallback) {
+ // TODO Call multiple pages
+ Call userStories = mUserStoryDomainProviderService.getUserStories(
+ INCLUDE_ACTIONS_FOR_PLACES,
+ "open",
+ true,
+ mProtocol,
+ 1);
+
+ Log.d("API-USER-STORY-DOMAINS", "Protocol [" + mProtocol + "] include_actions [" + INCLUDE_ACTIONS_FOR_PLACES + "]");
+ userStories.enqueue(new retrofit2.Callback() {
+
+ @Override
+ public void onResponse(Call call, Response response) {
+ UserStories userStories = response.body();
+ if (userStories == null) {
+ domainCallback.retrieveOk(new ArrayList<>(0));
+ }
+ List domains = new ArrayList<>(userStories.total_entries);
+ userStories.user_stories.forEach(userStory -> {
+ domains.add(userStory.toDomain());
+ });
+ domainCallback.retrieveOk(domains);
+ }
+
+ @Override
+ public void onFailure(Call call, Throwable t) {
+ domainCallback.retrieveError(new Exception(t), t.getMessage());
+ }
+
+ });
+ }
+
+ public interface UserStoryDomainProviderService {
+ @GET("api/v1/user_stories")
+ Call getUserStories(@Query("include_actions") String includeActions,
+ @Query("restriction") String restriction,
+ @Query("require_online") boolean requireOnline,
+ @Query("protocol") String protocol,
+ @Query("page") int pageNumber);
+ }
+
+ class UserStory {
+ public UserStory() {}
+ String place_name;
+ String path;
+ String thumbnail_url;
+ String place_id;
+ String domain_id;
+ private String searchText;
+
+ // New fields? tags, description
+
+ String searchText() {
+ if (searchText == null) {
+ searchText = place_name == null? "" : place_name.toUpperCase();
+ }
+ return searchText;
+ }
+ DomainAdapter.Domain toDomain() {
+ // TODO Proper url creation (it can or can't have hifi
+ // TODO Or use host value from api?
+ String absoluteThumbnailUrl = HifiUtils.getInstance().absoluteHifiAssetUrl(thumbnail_url);
+ DomainAdapter.Domain domain = new DomainAdapter.Domain(
+ place_name,
+ HifiUtils.getInstance().sanitizeHifiUrl(place_name) + "/" + path,
+ absoluteThumbnailUrl
+ );
+ return domain;
+ }
+ }
+
+ class UserStories {
+ String status;
+ int current_page;
+ int total_pages;
+ int total_entries;
+ List user_stories;
+ }
+
+}
diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/view/DomainAdapter.java b/android/app/src/main/java/io/highfidelity/hifiinterface/view/DomainAdapter.java
index 1129ec586f..461b71eb7c 100644
--- a/android/app/src/main/java/io/highfidelity/hifiinterface/view/DomainAdapter.java
+++ b/android/app/src/main/java/io/highfidelity/hifiinterface/view/DomainAdapter.java
@@ -1,6 +1,7 @@
package io.highfidelity.hifiinterface.view;
import android.content.Context;
+import android.net.Uri;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
@@ -9,6 +10,8 @@ import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
+import com.squareup.picasso.Picasso;
+
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
@@ -19,69 +22,59 @@ import java.util.ArrayList;
import java.util.List;
import io.highfidelity.hifiinterface.R;
+import io.highfidelity.hifiinterface.provider.DomainProvider;
+import io.highfidelity.hifiinterface.provider.UserStoryDomainProvider;
/**
* Created by Gabriel Calero & Cristian Duarte on 3/20/18.
*/
public class DomainAdapter extends RecyclerView.Adapter {
- private static final java.lang.String DOMAINS_FILE = "hifi_domains.json";
private static final String TAG = "HiFi Interface";
private Context mContext;
private LayoutInflater mInflater;
private ItemClickListener mClickListener;
-
- public class Domain {
- public String name;
- public String url;
- public String thumbnail;
- Domain(String name, String url, String thumbnail) {
- this.name = name;
- this.thumbnail = thumbnail;
- this.url = url;
- }
- }
+ private String mProtocol;
+ private UserStoryDomainProvider domainProvider;
+ private AdapterListener mAdapterListener;
// references to our domains
private Domain[] mDomains = {};
- public DomainAdapter(Context c) {
+ public DomainAdapter(Context c, String protocol) {
mContext = c;
this.mInflater = LayoutInflater.from(mContext);
- loadDomains();
+ mProtocol = protocol;
+ domainProvider = new UserStoryDomainProvider(mProtocol);
+ loadDomains("");
}
- private void loadDomains() {
- try {
- JSONObject json = new JSONObject(loadJSONFromAsset());
- JSONArray hifiDomains = json.getJSONArray("hifi_domains");
- List domains = new ArrayList<>();
- for (int i = 0; i < hifiDomains.length(); i++) {
- JSONObject jDomain = hifiDomains.getJSONObject(i);
+ public void setListener(AdapterListener adapterListener) {
+ mAdapterListener = adapterListener;
+ }
- String domainName = jDomain.getString("name");
- String domainUrl = jDomain.getString("url");
- String domainThumb = jDomain.getString("thumbnail");
-
- domains.add(new Domain(domainName, domainUrl, domainThumb));
+ public void loadDomains(String filterText) {
+ domainProvider.retrieve(filterText, new DomainProvider.DomainCallback() {
+ @Override
+ public void retrieveOk(List domain) {
+ mDomains = new Domain[domain.size()];
+ mDomains = domain.toArray(mDomains);
+ notifyDataSetChanged();
+ if (mAdapterListener != null) {
+ if (mDomains.length == 0) {
+ mAdapterListener.onEmptyAdapter();
+ } else {
+ mAdapterListener.onNonEmptyAdapter();
+ }
+ }
}
- mDomains = domains.toArray(mDomains);
- } catch (IOException e) {
- Log.e(TAG, "Error loading domains from local file", e);
- } catch (JSONException e) {
- Log.e(TAG, "Error loading domains from local file", e);
- }
- }
- public String loadJSONFromAsset() throws IOException {
- String json = null;
- InputStream is = mContext.getAssets().open(DOMAINS_FILE);
- int size = is.available();
- byte[] buffer = new byte[size];
- is.read(buffer);
- is.close();
- json = new String(buffer, "UTF-8");
- return json;
+ @Override
+ public void retrieveError(Exception e, String message) {
+ Log.e("DOMAINS", message, e);
+ if (mAdapterListener != null) mAdapterListener.onError(e, message);
+ }
+ });
}
@Override
@@ -94,7 +87,10 @@ public class DomainAdapter extends RecyclerView.Adapter
-
- -
-
-
-
-
-
-
-
\ No newline at end of file
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/ic_clear.xml b/android/app/src/main/res/drawable/ic_clear.xml
new file mode 100644
index 0000000000..94efe2bbdb
--- /dev/null
+++ b/android/app/src/main/res/drawable/ic_clear.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
diff --git a/android/app/src/main/res/drawable/ic_search.xml b/android/app/src/main/res/drawable/ic_search.xml
new file mode 100644
index 0000000000..099c8ea953
--- /dev/null
+++ b/android/app/src/main/res/drawable/ic_search.xml
@@ -0,0 +1,4 @@
+
+
+
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..91fb8603cd 100644
--- a/android/app/src/main/res/layout/activity_home.xml
+++ b/android/app/src/main/res/layout/activity_home.xml
@@ -18,8 +18,9 @@
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
- android:background="?attr/colorPrimary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
+ android:background="@color/colorPrimaryDark"
+ android:elevation="4dp"
+ />
@@ -32,7 +33,31 @@
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
+ android:background="@color/colorPrimaryDark"
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..5b4f91e733
--- /dev/null
+++ b/android/app/src/main/res/layout/activity_splash.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
diff --git a/android/app/src/main/res/layout/content_home.xml b/android/app/src/main/res/layout/content_home.xml
index f25d9d8f7b..4ebb4bbf01 100644
--- a/android/app/src/main/res/layout/content_home.xml
+++ b/android/app/src/main/res/layout/content_home.xml
@@ -2,75 +2,75 @@
-
+
+
+
+
+
+
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/searchView"
+ android:layout_marginTop="32dp"
+ android:text="@string/search_no_results"
+ android:visibility="gone"
+ />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/android/app/src/main/res/layout/domain_view.xml b/android/app/src/main/res/layout/domain_view.xml
index d0ed2d3a44..853124edb7 100644
--- a/android/app/src/main/res/layout/domain_view.xml
+++ b/android/app/src/main/res/layout/domain_view.xml
@@ -1,74 +1,44 @@
-
-
+
+
+ android:layout_height="match_parent">
-
+
-
+
-
-
-
-
-
-
\ No newline at end of file
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/values/colors.xml b/android/app/src/main/res/values/colors.xml
index 0325881f1b..15895e4355 100644
--- a/android/app/src/main/res/values/colors.xml
+++ b/android/app/src/main/res/values/colors.xml
@@ -1,13 +1,20 @@
#ffffff
- #272727
- #000000
+ @color/backgroundLight
+ @color/backgroundDark
#54D7FD
+ #E3E3E3
+ #575757
#1EB5EC
+ #00B4EF
#333333
#4F4F4F
#33999999
#212121
#9e9e9e
+ #F2F2F2
+ #FF7171
+ #99000000
+ #292929
diff --git a/android/app/src/main/res/values/dimens.xml b/android/app/src/main/res/values/dimens.xml
index 440adcf6b9..b2eaea5ee7 100644
--- a/android/app/src/main/res/values/dimens.xml
+++ b/android/app/src/main/res/values/dimens.xml
@@ -11,4 +11,26 @@
12dp
12dp
8dp
+ 4dp
+
+
+ 47.5dp
+ 11dp
+ 24dp
+ 51dp
+ 19sp
+ 16dp
+ 16dp
+ 22dp
+ 16dp
+ 16dp
+ 22dp
+
+ 163dp
+ 14dp
+ 14dp
+ 2dp
+ 6dp
+ 64dp
+
\ No newline at end of file
diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml
index 6ce0670dd8..cc06c12350 100644
--- a/android/app/src/main/res/values/strings.xml
+++ b/android/app/src/main/res/values/strings.xml
@@ -13,5 +13,14 @@
Go To
Type a domain url
Go
-
+ Username or email
+ Password
+ Login
+ Logout
+ Forgot password?
+ Username or password incorrect.
+ Logging into High Fidelity
+ Search for a place by name\u00A0
+ Loading places…
+ No places exist with that name
diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml
index 55c9b2af11..308c438fa6 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
-
+
diff --git a/interface/resources/html/raiseAndLowerKeyboard.js b/interface/resources/html/raiseAndLowerKeyboard.js
index a0aa1eb7fe..f40c0d7376 100644
--- a/interface/resources/html/raiseAndLowerKeyboard.js
+++ b/interface/resources/html/raiseAndLowerKeyboard.js
@@ -7,6 +7,9 @@
//
// Sends messages over the EventBridge when text input is required.
//
+
+/* global document, window, console, setTimeout, setInterval, EventBridge */
+
(function () {
var POLL_FREQUENCY = 500; // ms
var MAX_WARNINGS = 3;
@@ -37,22 +40,24 @@
}
return false;
}
- };
+ }
function shouldSetNumeric() {
return document.activeElement.type === "number";
- };
+ }
function scheduleBringToView(timeout) {
-
- var timer = setTimeout(function () {
- clearTimeout(timer);
-
+ setTimeout(function () {
+ // If the element is not visible because the keyboard has been raised over the top of it, scroll it up into view.
+ // If the element is not visible because the keyboard raising has moved it off screen, scroll it down into view.
var elementRect = document.activeElement.getBoundingClientRect();
- var absoluteElementTop = elementRect.top + window.scrollY;
- var middle = absoluteElementTop - (window.innerHeight / 2);
-
- window.scrollTo(0, middle);
+ var VISUAL_MARGIN = 3;
+ var delta = elementRect.y + elementRect.height + VISUAL_MARGIN - window.innerHeight;
+ if (delta > 0) {
+ window.scrollBy(0, delta);
+ } else if (elementRect.y < VISUAL_MARGIN) {
+ window.scrollBy(0, elementRect.y - VISUAL_MARGIN);
+ }
}, timeout);
}
@@ -62,11 +67,13 @@
var passwordField = shouldSetPasswordField();
if (isWindowFocused &&
- (keyboardRaised !== window.isKeyboardRaised || numericKeyboard !== window.isNumericKeyboard || passwordField !== window.isPasswordField)) {
+ (keyboardRaised !== window.isKeyboardRaised || numericKeyboard !== window.isNumericKeyboard
+ || passwordField !== window.isPasswordField)) {
if (typeof EventBridge !== "undefined" && EventBridge !== null) {
EventBridge.emitWebEvent(
- keyboardRaised ? ("_RAISE_KEYBOARD" + (numericKeyboard ? "_NUMERIC" : "") + (passwordField ? "_PASSWORD" : "")) : "_LOWER_KEYBOARD"
+ keyboardRaised ? ("_RAISE_KEYBOARD" + (numericKeyboard ? "_NUMERIC" : "")
+ + (passwordField ? "_PASSWORD" : "")) : "_LOWER_KEYBOARD"
);
} else {
if (numWarnings < MAX_WARNINGS) {
@@ -77,7 +84,7 @@
if (!window.isKeyboardRaised) {
scheduleBringToView(250); // Allow time for keyboard to be raised in QML.
- // 2DO: should it be rather done from 'client area height changed' event?
+ // 2DO: should it be rather done from 'client area height changed' event?
}
window.isKeyboardRaised = keyboardRaised;
diff --git a/interface/resources/qml/hifi/tablet/ControllerSettings.qml b/interface/resources/qml/hifi/tablet/ControllerSettings.qml
index ffd3d81b84..0beb28977e 100644
--- a/interface/resources/qml/hifi/tablet/ControllerSettings.qml
+++ b/interface/resources/qml/hifi/tablet/ControllerSettings.qml
@@ -172,7 +172,7 @@ StackView {
source: InputConfiguration.configurationLayout(box.currentText);
onLoaded: {
if (loader.item.hasOwnProperty("pluginName")) {
- if (box.currentText === "Vive") {
+ if (box.currentText === "HTC Vive") {
loader.item.pluginName = "OpenVR";
} else {
loader.item.pluginName = box.currentText;
diff --git a/interface/src/AndroidHelper.cpp b/interface/src/AndroidHelper.cpp
index b04a6ff2c4..825a45c21b 100644
--- a/interface/src/AndroidHelper.cpp
+++ b/interface/src/AndroidHelper.cpp
@@ -10,11 +10,42 @@
//
#include "AndroidHelper.h"
#include
+#include
+
+AndroidHelper::AndroidHelper() {
+}
+
+AndroidHelper::~AndroidHelper() {
+ workerThread.quit();
+ workerThread.wait();
+}
+
+void AndroidHelper::init() {
+ workerThread.start();
+ _accountManager = QSharedPointer(new AccountManager, &QObject::deleteLater);
+ _accountManager->setIsAgent(true);
+ _accountManager->setAuthURL(NetworkingConstants::METAVERSE_SERVER_URL());
+ _accountManager->setSessionID(DependencyManager::get()->getSessionID());
+ connect(_accountManager.data(), &AccountManager::loginComplete, [](const QUrl& authURL) {
+ DependencyManager::get()->setAccountInfo(AndroidHelper::instance().getAccountManager()->getAccountInfo());
+ DependencyManager::get()->setAuthURL(authURL);
+ });
+
+ connect(_accountManager.data(), &AccountManager::logoutComplete, [] () {
+ DependencyManager::get()->logout();
+ });
+ _accountManager->moveToThread(&workerThread);
+}
void AndroidHelper::requestActivity(const QString &activityName) {
emit androidActivityRequested(activityName);
}
+void AndroidHelper::notifyLoadComplete() {
+ emit qtAppLoadComplete();
+}
+
void AndroidHelper::goBackFromAndroidActivity() {
emit backFromAndroidActivity();
-}
\ No newline at end of file
+}
+
diff --git a/interface/src/AndroidHelper.h b/interface/src/AndroidHelper.h
index 34f32b461b..c5e15a31da 100644
--- a/interface/src/AndroidHelper.h
+++ b/interface/src/AndroidHelper.h
@@ -13,6 +13,8 @@
#define hifi_Android_Helper_h
#include
+#include
+#include
class AndroidHelper : public QObject {
Q_OBJECT
@@ -21,17 +23,24 @@ public:
static AndroidHelper instance;
return instance;
}
+ void init();
void requestActivity(const QString &activityName);
+ void notifyLoadComplete();
void goBackFromAndroidActivity();
+ QSharedPointer getAccountManager() { return _accountManager; }
AndroidHelper(AndroidHelper const&) = delete;
void operator=(AndroidHelper const&) = delete;
signals:
void androidActivityRequested(const QString &activityName);
void backFromAndroidActivity();
+ void qtAppLoadComplete();
private:
- AndroidHelper() {}
+ AndroidHelper();
+ ~AndroidHelper();
+ QSharedPointer _accountManager;
+ QThread workerThread;
};
#endif
\ No newline at end of file
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 42a6cbc790..ecfd5a9bf7 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -735,9 +735,9 @@ extern InputPluginList getInputPlugins();
extern void saveInputPluginSettings(const InputPluginList& plugins);
// Parameters used for running tests from teh command line
-const QString TEST_SCRIPT_COMMAND { "--testScript" };
-const QString TEST_QUIT_WHEN_FINISHED_OPTION { "quitWhenFinished" };
-const QString TEST_SNAPSHOT_LOCATION_COMMAND { "--testSnapshotLocation" };
+const QString TEST_SCRIPT_COMMAND{ "--testScript" };
+const QString TEST_QUIT_WHEN_FINISHED_OPTION{ "quitWhenFinished" };
+const QString TEST_RESULTS_LOCATION_COMMAND{ "--testResultsLocation" };
bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
const char** constArgv = const_cast(argv);
@@ -851,7 +851,11 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
DependencyManager::set();
DependencyManager::set();
DependencyManager::set();
+#if defined(Q_OS_ANDROID)
+ DependencyManager::set(); // use the default user agent getter
+#else
DependencyManager::set(std::bind(&Application::getUserAgent, qApp));
+#endif
DependencyManager::set();
DependencyManager::set(ScriptEngine::CLIENT_SCRIPT);
DependencyManager::set();
@@ -1015,22 +1019,25 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
// If the URL scheme is http(s) or ftp, then use as is, else - treat it as a local file
// This is done so as not break previous command line scripts
- if (testScriptPath.left(URL_SCHEME_HTTP.length()) == URL_SCHEME_HTTP || testScriptPath.left(URL_SCHEME_FTP.length()) == URL_SCHEME_FTP) {
+ if (testScriptPath.left(URL_SCHEME_HTTP.length()) == URL_SCHEME_HTTP ||
+ testScriptPath.left(URL_SCHEME_FTP.length()) == URL_SCHEME_FTP) {
+
setProperty(hifi::properties::TEST, QUrl::fromUserInput(testScriptPath));
} else if (QFileInfo(testScriptPath).exists()) {
setProperty(hifi::properties::TEST, QUrl::fromLocalFile(testScriptPath));
}
- // quite when finished parameter must directly follow the test script
+ // quite when finished parameter must directly follow the test script
if ((i + 2) < args.size() && args.at(i + 2) == TEST_QUIT_WHEN_FINISHED_OPTION) {
quitWhenFinished = true;
}
- } else if (args.at(i) == TEST_SNAPSHOT_LOCATION_COMMAND) {
+ } else if (args.at(i) == TEST_RESULTS_LOCATION_COMMAND) {
// Set test snapshot location only if it is a writeable directory
- QString pathname(args.at(i + 1));
- QFileInfo fileInfo(pathname);
+ QString path(args.at(i + 1));
+
+ QFileInfo fileInfo(path);
if (fileInfo.isDir() && fileInfo.isWritable()) {
- testSnapshotLocation = pathname;
+ TestScriptingInterface::getInstance()->setTestResultsLocation(path);
}
}
}
@@ -2249,6 +2256,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
_pendingRenderEvent = false;
qCDebug(interfaceapp) << "Metaverse session ID is" << uuidStringWithoutCurlyBraces(accountManager->getSessionID());
+
+#if defined(Q_OS_ANDROID)
+ AndroidHelper::instance().init();
+ AndroidHelper::instance().notifyLoadComplete();
+#endif
}
void Application::updateVerboseLogging() {
@@ -7588,7 +7600,9 @@ void Application::loadAvatarBrowser() const {
void Application::takeSnapshot(bool notify, bool includeAnimated, float aspectRatio, const QString& filename) {
postLambdaEvent([notify, includeAnimated, aspectRatio, filename, this] {
// Get a screenshot and save it
- QString path = Snapshot::saveSnapshot(getActiveDisplayPlugin()->getScreenshot(aspectRatio), filename, testSnapshotLocation);
+ QString path = Snapshot::saveSnapshot(getActiveDisplayPlugin()->getScreenshot(aspectRatio), filename,
+ TestScriptingInterface::getInstance()->getTestResultsLocation());
+
// If we're not doing an animated snapshot as well...
if (!includeAnimated) {
// Tell the dependency manager that the capture of the still snapshot has taken place.
@@ -7602,7 +7616,9 @@ void Application::takeSnapshot(bool notify, bool includeAnimated, float aspectRa
void Application::takeSecondaryCameraSnapshot(const QString& filename) {
postLambdaEvent([filename, this] {
- QString snapshotPath = Snapshot::saveSnapshot(getActiveDisplayPlugin()->getSecondaryCameraScreenshot(), filename, testSnapshotLocation);
+ QString snapshotPath = Snapshot::saveSnapshot(getActiveDisplayPlugin()->getSecondaryCameraScreenshot(), filename,
+ TestScriptingInterface::getInstance()->getTestResultsLocation());
+
emit DependencyManager::get()->stillSnapshotTaken(snapshotPath, true);
});
}
@@ -8255,17 +8271,17 @@ void Application::openAndroidActivity(const QString& activityName) {
void Application::enterBackground() {
QMetaObject::invokeMethod(DependencyManager::get().data(),
"stop", Qt::BlockingQueuedConnection);
- //GC: commenting it out until we fix it
- //getActiveDisplayPlugin()->deactivate();
+ if (getActiveDisplayPlugin()->isActive()) {
+ getActiveDisplayPlugin()->deactivate();
+ }
}
+
void Application::enterForeground() {
QMetaObject::invokeMethod(DependencyManager::get().data(),
"start", Qt::BlockingQueuedConnection);
- //GC: commenting it out until we fix it
- /*if (!getActiveDisplayPlugin() || !getActiveDisplayPlugin()->activate()) {
+ if (!getActiveDisplayPlugin() || getActiveDisplayPlugin()->isActive() || !getActiveDisplayPlugin()->activate()) {
qWarning() << "Could not re-activate display plugin";
- }*/
-
+ }
}
#endif
diff --git a/interface/src/Application.h b/interface/src/Application.h
index 4946dd7ad9..17e28f0e6e 100644
--- a/interface/src/Application.h
+++ b/interface/src/Application.h
@@ -419,7 +419,6 @@ public slots:
void updateVerboseLogging();
Q_INVOKABLE void openAndroidActivity(const QString& activityName);
-
private slots:
void onDesktopRootItemCreated(QQuickItem* qmlContext);
void onDesktopRootContextCreated(QQmlContext* qmlContext);
@@ -753,7 +752,6 @@ private:
std::atomic _pendingIdleEvent { true };
std::atomic _pendingRenderEvent { true };
- QString testSnapshotLocation;
bool quitWhenFinished { false };
};
#endif // hifi_Application_h
diff --git a/interface/src/LODManager.cpp b/interface/src/LODManager.cpp
index d06ba14bcf..da1f14c450 100644
--- a/interface/src/LODManager.cpp
+++ b/interface/src/LODManager.cpp
@@ -70,7 +70,7 @@ void LODManager::autoAdjustLOD(float realTimeDelta) {
// Note: we MUST clamp the blend to 1.0 for stability
float blend = (realTimeDelta < LOD_ADJUST_RUNNING_AVG_TIMESCALE) ? realTimeDelta / LOD_ADJUST_RUNNING_AVG_TIMESCALE : 1.0f;
_avgRenderTime = (1.0f - blend) * _avgRenderTime + blend * maxRenderTime; // msec
- if (!_automaticLODAdjust) {
+ if (!_automaticLODAdjust || _avgRenderTime == 0.0f) {
// early exit
return;
}
diff --git a/interface/src/Menu.h b/interface/src/Menu.h
index 20375a71b2..be3dd705f7 100644
--- a/interface/src/Menu.h
+++ b/interface/src/Menu.h
@@ -193,7 +193,6 @@ namespace MenuOption {
const QString ShowOtherLookAtVectors = "Show Other Eye Vectors";
const QString EnableLookAtSnapping = "Enable LookAt Snapping";
const QString ShowRealtimeEntityStats = "Show Realtime Entity Stats";
- const QString StandingHMDSensorMode = "Standing HMD Sensor Mode";
const QString SimulateEyeTracking = "Simulate";
const QString SMIEyeTracking = "SMI Eye Tracking";
const QString SparseTextureManagement = "Enable Sparse Texture Management";
diff --git a/interface/src/scripting/TestScriptingInterface.cpp b/interface/src/scripting/TestScriptingInterface.cpp
index 9e7c0e142e..700994c517 100644
--- a/interface/src/scripting/TestScriptingInterface.cpp
+++ b/interface/src/scripting/TestScriptingInterface.cpp
@@ -160,3 +160,29 @@ void TestScriptingInterface::clearCaches() {
qApp->reloadResourceCaches();
}
+// Writes a JSON object from javascript to a file
+void TestScriptingInterface::saveObject(QVariant variant, const QString& filename) {
+ if (_testResultsLocation.isNull()) {
+ return;
+ }
+
+ QJsonDocument jsonDocument;
+ jsonDocument = QJsonDocument::fromVariant(variant);
+ if (jsonDocument.isNull()) {
+ return;
+ }
+
+ QByteArray jsonData = jsonDocument.toJson();
+
+ // Append trailing slash if needed
+ if (_testResultsLocation.right(1) != "/") {
+ _testResultsLocation += "/";
+ }
+
+ QString filepath = QDir::cleanPath(_testResultsLocation + filename);
+ QFile file(filepath);
+
+ file.open(QFile::WriteOnly);
+ file.write(jsonData);
+ file.close();
+}
diff --git a/interface/src/scripting/TestScriptingInterface.h b/interface/src/scripting/TestScriptingInterface.h
index 687cb41689..5666417727 100644
--- a/interface/src/scripting/TestScriptingInterface.h
+++ b/interface/src/scripting/TestScriptingInterface.h
@@ -18,6 +18,10 @@ class QScriptValue;
class TestScriptingInterface : public QObject {
Q_OBJECT
+public:
+ void setTestResultsLocation(const QString path) { _testResultsLocation = path; }
+ const QString& getTestResultsLocation() { return _testResultsLocation; };
+
public slots:
static TestScriptingInterface* getInstance();
@@ -46,7 +50,6 @@ public slots:
*/
void waitIdle();
-
bool waitForConnection(qint64 maxWaitMs = 10000);
void wait(int milliseconds);
@@ -83,8 +86,14 @@ public slots:
*/
void clearCaches();
+ /**jsdoc
+ * Save a JSON object to a file in the test results location
+ */
+ void saveObject(QVariant v, const QString& filename);
+
private:
bool waitForCondition(qint64 maxWaitMs, std::function condition);
+ QString _testResultsLocation;
};
-#endif // hifi_TestScriptingInterface_h
+#endif // hifi_TestScriptingInterface_h
diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h
index cf1151b46a..3ff782da99 100644
--- a/interface/src/ui/overlays/Overlays.h
+++ b/interface/src/ui/overlays/Overlays.h
@@ -60,7 +60,7 @@ public:
bool intersects { false };
OverlayID overlayID { UNKNOWN_OVERLAY_ID };
float distance { 0 };
- BoxFace face;
+ BoxFace face { UNKNOWN_FACE };
glm::vec3 surfaceNormal;
glm::vec3 intersection;
QVariantMap extraInfo;
diff --git a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp
index 59cd637ca0..09b9b7f8f9 100644
--- a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp
+++ b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp
@@ -28,69 +28,76 @@ void Basic2DWindowOpenGLDisplayPlugin::customizeContext() {
qreal dpi = getFullscreenTarget()->physicalDotsPerInch();
_virtualPadPixelSize = dpi * VirtualPad::Manager::BASE_DIAMETER_PIXELS / VirtualPad::Manager::DPI;
- auto iconPath = PathUtils::resourcesPath() + "images/analog_stick.png";
- auto image = QImage(iconPath);
- if (image.format() != QImage::Format_ARGB32) {
- image = image.convertToFormat(QImage::Format_ARGB32);
- }
- if ((image.width() > 0) && (image.height() > 0)) {
- image = image.scaled(_virtualPadPixelSize, _virtualPadPixelSize, Qt::KeepAspectRatio);
+ if (!_virtualPadStickTexture) {
+ auto iconPath = PathUtils::resourcesPath() + "images/analog_stick.png";
+ auto image = QImage(iconPath);
+ if (image.format() != QImage::Format_ARGB32) {
+ image = image.convertToFormat(QImage::Format_ARGB32);
+ }
+ if ((image.width() > 0) && (image.height() > 0)) {
+ image = image.scaled(_virtualPadPixelSize, _virtualPadPixelSize, Qt::KeepAspectRatio);
- _virtualPadStickTexture = gpu::Texture::createStrict(
- gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA),
- image.width(), image.height(),
- gpu::Texture::MAX_NUM_MIPS,
- gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR));
- _virtualPadStickTexture->setSource("virtualPad stick");
- auto usage = gpu::Texture::Usage::Builder().withColor().withAlpha();
- _virtualPadStickTexture->setUsage(usage.build());
- _virtualPadStickTexture->setStoredMipFormat(gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA));
- _virtualPadStickTexture->assignStoredMip(0, image.byteCount(), image.constBits());
- _virtualPadStickTexture->setAutoGenerateMips(true);
+ _virtualPadStickTexture = gpu::Texture::createStrict(
+ gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA),
+ image.width(), image.height(),
+ gpu::Texture::MAX_NUM_MIPS,
+ gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR));
+ _virtualPadStickTexture->setSource("virtualPad stick");
+ auto usage = gpu::Texture::Usage::Builder().withColor().withAlpha();
+ _virtualPadStickTexture->setUsage(usage.build());
+ _virtualPadStickTexture->setStoredMipFormat(gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA));
+ _virtualPadStickTexture->assignStoredMip(0, image.byteCount(), image.constBits());
+ _virtualPadStickTexture->setAutoGenerateMips(true);
+ }
}
- iconPath = PathUtils::resourcesPath() + "images/analog_stick_base.png";
- image = QImage(iconPath);
- if (image.format() != QImage::Format_ARGB32) {
- image = image.convertToFormat(QImage::Format_ARGB32);
- }
- if ((image.width() > 0) && (image.height() > 0)) {
- image = image.scaled(_virtualPadPixelSize, _virtualPadPixelSize, Qt::KeepAspectRatio);
+ if (!_virtualPadStickBaseTexture) {
+ auto iconPath = PathUtils::resourcesPath() + "images/analog_stick_base.png";
+ auto image = QImage(iconPath);
+ if (image.format() != QImage::Format_ARGB32) {
+ image = image.convertToFormat(QImage::Format_ARGB32);
+ }
+ if ((image.width() > 0) && (image.height() > 0)) {
+ image = image.scaled(_virtualPadPixelSize, _virtualPadPixelSize, Qt::KeepAspectRatio);
- _virtualPadStickBaseTexture = gpu::Texture::createStrict(
- gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA),
- image.width(), image.height(),
- gpu::Texture::MAX_NUM_MIPS,
- gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR));
- _virtualPadStickBaseTexture->setSource("virtualPad base");
- auto usage = gpu::Texture::Usage::Builder().withColor().withAlpha();
- _virtualPadStickBaseTexture->setUsage(usage.build());
- _virtualPadStickBaseTexture->setStoredMipFormat(gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA));
- _virtualPadStickBaseTexture->assignStoredMip(0, image.byteCount(), image.constBits());
- _virtualPadStickBaseTexture->setAutoGenerateMips(true);
+ _virtualPadStickBaseTexture = gpu::Texture::createStrict(
+ gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA),
+ image.width(), image.height(),
+ gpu::Texture::MAX_NUM_MIPS,
+ gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR));
+ _virtualPadStickBaseTexture->setSource("virtualPad base");
+ auto usage = gpu::Texture::Usage::Builder().withColor().withAlpha();
+ _virtualPadStickBaseTexture->setUsage(usage.build());
+ _virtualPadStickBaseTexture->setStoredMipFormat(gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA));
+ _virtualPadStickBaseTexture->assignStoredMip(0, image.byteCount(), image.constBits());
+ _virtualPadStickBaseTexture->setAutoGenerateMips(true);
+ }
}
+
_virtualPadJumpBtnPixelSize = dpi * VirtualPad::Manager::JUMP_BTN_FULL_PIXELS / VirtualPad::Manager::DPI;
- iconPath = PathUtils::resourcesPath() + "images/fly.png";
- image = QImage(iconPath);
- if (image.format() != QImage::Format_ARGB32) {
- image = image.convertToFormat(QImage::Format_ARGB32);
- }
- if ((image.width() > 0) && (image.height() > 0)) {
- image = image.scaled(_virtualPadJumpBtnPixelSize, _virtualPadJumpBtnPixelSize, Qt::KeepAspectRatio);
- image = image.mirrored();
+ if (!_virtualPadJumpBtnTexture) {
+ auto iconPath = PathUtils::resourcesPath() + "images/fly.png";
+ auto image = QImage(iconPath);
+ if (image.format() != QImage::Format_ARGB32) {
+ image = image.convertToFormat(QImage::Format_ARGB32);
+ }
+ if ((image.width() > 0) && (image.height() > 0)) {
+ image = image.scaled(_virtualPadJumpBtnPixelSize, _virtualPadJumpBtnPixelSize, Qt::KeepAspectRatio);
+ image = image.mirrored();
- _virtualPadJumpBtnTexture = gpu::Texture::createStrict(
- gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA),
- image.width(), image.height(),
- gpu::Texture::MAX_NUM_MIPS,
- gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR));
- _virtualPadJumpBtnTexture->setSource("virtualPad jump");
- auto usage = gpu::Texture::Usage::Builder().withColor().withAlpha();
- _virtualPadJumpBtnTexture->setUsage(usage.build());
- _virtualPadJumpBtnTexture->setStoredMipFormat(gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA));
- _virtualPadJumpBtnTexture->assignStoredMip(0, image.byteCount(), image.constBits());
- _virtualPadJumpBtnTexture->setAutoGenerateMips(true);
+ _virtualPadJumpBtnTexture = gpu::Texture::createStrict(
+ gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA),
+ image.width(), image.height(),
+ gpu::Texture::MAX_NUM_MIPS,
+ gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR));
+ _virtualPadJumpBtnTexture->setSource("virtualPad jump");
+ auto usage = gpu::Texture::Usage::Builder().withColor().withAlpha();
+ _virtualPadJumpBtnTexture->setUsage(usage.build());
+ _virtualPadJumpBtnTexture->setStoredMipFormat(gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA));
+ _virtualPadJumpBtnTexture->assignStoredMip(0, image.byteCount(), image.constBits());
+ _virtualPadJumpBtnTexture->setAutoGenerateMips(true);
+ }
}
#endif
Parent::customizeContext();
@@ -124,44 +131,32 @@ void Basic2DWindowOpenGLDisplayPlugin::compositeExtra() {
// render stick base
auto stickBaseTransform = DependencyManager::get()->getPoint2DTransform(virtualPadManager.getLeftVirtualPad()->getFirstTouch(),
_virtualPadPixelSize, _virtualPadPixelSize);
- render([&](gpu::Batch& batch) {
- batch.enableStereo(false);
- batch.setProjectionTransform(mat4());
- batch.setPipeline(_cursorPipeline);
- batch.setResourceTexture(0, _virtualPadStickBaseTexture);
- batch.resetViewTransform();
- batch.setModelTransform(stickBaseTransform);
- batch.setViewportTransform(ivec4(uvec2(0), getRecommendedRenderSize()));
- batch.draw(gpu::TRIANGLE_STRIP, 4);
- });
- // render stick head
auto stickTransform = DependencyManager::get()->getPoint2DTransform(virtualPadManager.getLeftVirtualPad()->getCurrentTouch(),
- _virtualPadPixelSize, _virtualPadPixelSize);
+ _virtualPadPixelSize, _virtualPadPixelSize);
+ auto jumpTransform = DependencyManager::get()->getPoint2DTransform(virtualPadManager.getJumpButtonPosition(),
+ _virtualPadJumpBtnPixelSize, _virtualPadJumpBtnPixelSize);
+
render([&](gpu::Batch& batch) {
batch.enableStereo(false);
+ batch.setFramebuffer(_compositeFramebuffer);
+ batch.resetViewTransform();
batch.setProjectionTransform(mat4());
batch.setPipeline(_cursorPipeline);
- batch.setResourceTexture(0, _virtualPadStickTexture);
- batch.resetViewTransform();
- batch.setModelTransform(stickTransform);
- batch.setViewportTransform(ivec4(uvec2(0), getRecommendedRenderSize()));
+
+ batch.setResourceTexture(0, _virtualPadStickBaseTexture);
+ batch.setModelTransform(stickBaseTransform);
batch.draw(gpu::TRIANGLE_STRIP, 4);
- });
- if (!virtualPadManager.getLeftVirtualPad()->isBeingTouched()) {
- // render stick head
- auto jumpTransform = DependencyManager::get()->getPoint2DTransform(virtualPadManager.getJumpButtonPosition(),
- _virtualPadJumpBtnPixelSize, _virtualPadJumpBtnPixelSize);
- render([&](gpu::Batch& batch) {
- batch.enableStereo(false);
- batch.setProjectionTransform(mat4());
- batch.setPipeline(_cursorPipeline);
+
+ batch.setResourceTexture(0, _virtualPadStickTexture);
+ batch.setModelTransform(stickTransform);
+ batch.draw(gpu::TRIANGLE_STRIP, 4);
+
+ if (!virtualPadManager.getLeftVirtualPad()->isBeingTouched()) {
batch.setResourceTexture(0, _virtualPadJumpBtnTexture);
- batch.resetViewTransform();
batch.setModelTransform(jumpTransform);
- batch.setViewportTransform(ivec4(uvec2(0), getRecommendedRenderSize()));
batch.draw(gpu::TRIANGLE_STRIP, 4);
- });
- }
+ }
+ });
}
#endif
Parent::compositeExtra();
diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp
index 5a3caa55fe..5062162b6e 100644
--- a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp
@@ -251,7 +251,7 @@ void ZoneEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scen
updateAmbientLightFromEntity(entity);
}
- if (skyboxChanged) {
+ if (skyboxChanged || _proceduralUserData != entity->getUserData()) {
updateKeyBackgroundFromEntity(entity);
}
@@ -295,6 +295,10 @@ bool ZoneEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoint
return true;
}
+ if (entity->getUserData() != _proceduralUserData) {
+ return true;
+ }
+
#if 0
if (_typedEntity->getCompoundShapeURL() != _lastShapeURL) {
return true;
diff --git a/libraries/graphics/src/graphics/skybox.slf b/libraries/graphics/src/graphics/skybox.slf
index 7b25e36af7..153e73b9ef 100755
--- a/libraries/graphics/src/graphics/skybox.slf
+++ b/libraries/graphics/src/graphics/skybox.slf
@@ -35,8 +35,11 @@ void main(void) {
#ifdef PROCEDURAL
vec3 color = getSkyboxColor();
- // Procedural Shaders are expected to be Gamma corrected so let's bring back the RGB in linear space for the rest of the pipeline
- color = pow(color, vec3(2.2));
+ // Protect from NaNs and negative values
+ color = mix(color, vec3(0), isnan(color));
+ color = max(color, vec3(0));
+ // Procedural Shaders are expected to be Gamma corrected so let's bring back the RGB in linear space for the rest of the pipeline
+ color = pow(color, vec3(2.2));
_fragColor = vec4(color, 0.0);
// FIXME: scribe does not yet scrub out else statements
diff --git a/libraries/networking/src/AccountManager.cpp b/libraries/networking/src/AccountManager.cpp
index 049129b2ba..e70e3e26d0 100644
--- a/libraries/networking/src/AccountManager.cpp
+++ b/libraries/networking/src/AccountManager.cpp
@@ -453,6 +453,20 @@ void AccountManager::removeAccountFromFile() {
<< "from settings file.";
}
+void AccountManager::setAccountInfo(const DataServerAccountInfo &newAccountInfo) {
+ _accountInfo = newAccountInfo;
+ _pendingPrivateKey.clear();
+ if (_isAgent && !_accountInfo.getAccessToken().token.isEmpty() && !_accountInfo.hasProfile()) {
+ // we are missing profile information, request it now
+ requestProfile();
+ }
+
+ // prepare to refresh our token if it is about to expire
+ if (needsToRefreshToken()) {
+ refreshAccessToken();
+ }
+}
+
bool AccountManager::hasValidAccessToken() {
if (_accountInfo.getAccessToken().token.isEmpty() || _accountInfo.getAccessToken().isExpired()) {
diff --git a/libraries/networking/src/AccountManager.h b/libraries/networking/src/AccountManager.h
index 87b17d00d5..88ebaf5656 100644
--- a/libraries/networking/src/AccountManager.h
+++ b/libraries/networking/src/AccountManager.h
@@ -88,6 +88,7 @@ public:
void requestProfile();
DataServerAccountInfo& getAccountInfo() { return _accountInfo; }
+ void setAccountInfo(const DataServerAccountInfo &newAccountInfo);
static QJsonObject dataObjectFromResponse(QNetworkReply& requestReply);
diff --git a/libraries/procedural/src/procedural/Procedural.cpp b/libraries/procedural/src/procedural/Procedural.cpp
index 19c4a62443..f93605b730 100644
--- a/libraries/procedural/src/procedural/Procedural.cpp
+++ b/libraries/procedural/src/procedural/Procedural.cpp
@@ -272,18 +272,24 @@ void Procedural::prepare(gpu::Batch& batch, const glm::vec3& position, const glm
// Leave this here for debugging
// qCDebug(procedural) << "FragmentShader:\n" << fragmentShaderSource.c_str();
+ gpu::Shader::BindingSet slotBindings;
+ slotBindings.insert(gpu::Shader::Binding(std::string("iChannel0"), 0));
+ slotBindings.insert(gpu::Shader::Binding(std::string("iChannel1"), 1));
+ slotBindings.insert(gpu::Shader::Binding(std::string("iChannel2"), 2));
+ slotBindings.insert(gpu::Shader::Binding(std::string("iChannel3"), 3));
+
_opaqueFragmentShader = gpu::Shader::createPixel(opaqueShaderSource);
_opaqueShader = gpu::Shader::createProgram(_vertexShader, _opaqueFragmentShader);
- _transparentFragmentShader = gpu::Shader::createPixel(transparentShaderSource);
- _transparentShader = gpu::Shader::createProgram(_vertexShader, _transparentFragmentShader);
+ gpu::Shader::makeProgram(*_opaqueShader, slotBindings);
- gpu::Shader::BindingSet slotBindings;
- slotBindings.insert(gpu::Shader::Binding(std::string("iChannel0"), 0));
- slotBindings.insert(gpu::Shader::Binding(std::string("iChannel1"), 1));
- slotBindings.insert(gpu::Shader::Binding(std::string("iChannel2"), 2));
- slotBindings.insert(gpu::Shader::Binding(std::string("iChannel3"), 3));
- gpu::Shader::makeProgram(*_opaqueShader, slotBindings);
- gpu::Shader::makeProgram(*_transparentShader, slotBindings);
+ if (!transparentShaderSource.empty() && transparentShaderSource != opaqueShaderSource) {
+ _transparentFragmentShader = gpu::Shader::createPixel(transparentShaderSource);
+ _transparentShader = gpu::Shader::createProgram(_vertexShader, _transparentFragmentShader);
+ gpu::Shader::makeProgram(*_transparentShader, slotBindings);
+ } else {
+ _transparentFragmentShader = _opaqueFragmentShader;
+ _transparentShader = _opaqueShader;
+ }
_opaquePipeline = gpu::Pipeline::create(_opaqueShader, _opaqueState);
_transparentPipeline = gpu::Pipeline::create(_transparentShader, _transparentState);
diff --git a/libraries/render-utils/src/RenderForwardTask.cpp b/libraries/render-utils/src/RenderForwardTask.cpp
index 63370109e0..b49735a53f 100755
--- a/libraries/render-utils/src/RenderForwardTask.cpp
+++ b/libraries/render-utils/src/RenderForwardTask.cpp
@@ -21,6 +21,8 @@
#include
+#include
+
#include "StencilMaskPass.h"
#include "ZoneRenderer.h"
#include "FadeEffect.h"
@@ -53,8 +55,9 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend
const auto& transparents = items.get0()[RenderFetchCullSortTask::TRANSPARENT_SHAPE];
// const auto& lights = items.get0()[RenderFetchCullSortTask::LIGHT];
const auto& metas = items.get0()[RenderFetchCullSortTask::META];
- // const auto& overlayOpaques = items.get0()[RenderFetchCullSortTask::OVERLAY_OPAQUE_SHAPE];
- // const auto& overlayTransparents = items.get0()[RenderFetchCullSortTask::OVERLAY_TRANSPARENT_SHAPE];
+ const auto& overlayOpaques = items.get0()[RenderFetchCullSortTask::OVERLAY_OPAQUE_SHAPE];
+ const auto& overlayTransparents = items.get0()[RenderFetchCullSortTask::OVERLAY_TRANSPARENT_SHAPE];
+
//const auto& background = items.get0()[RenderFetchCullSortTask::BACKGROUND];
// const auto& spatialSelection = items[1];
@@ -75,6 +78,17 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend
// draw a stencil mask in hidden regions of the framebuffer.
task.addJob("PrepareStencil", framebuffer);
+ // Layered Overlays
+ const auto filteredOverlaysOpaque = task.addJob("FilterOverlaysLayeredOpaque", overlayOpaques, Item::LAYER_3D_FRONT);
+ const auto filteredOverlaysTransparent = task.addJob("FilterOverlaysLayeredTransparent", overlayTransparents, Item::LAYER_3D_FRONT);
+ const auto overlaysInFrontOpaque = filteredOverlaysOpaque.getN(0);
+ const auto overlaysInFrontTransparent = filteredOverlaysTransparent.getN(0);
+
+ const auto overlayInFrontOpaquesInputs = DrawOverlay3D::Inputs(overlaysInFrontOpaque, lightingModel, nullptr).asVarying();
+ const auto overlayInFrontTransparentsInputs = DrawOverlay3D::Inputs(overlaysInFrontTransparent, lightingModel, nullptr).asVarying();
+ task.addJob("DrawOverlayInFrontOpaque", overlayInFrontOpaquesInputs, true);
+ task.addJob("DrawOverlayInFrontTransparent", overlayInFrontTransparentsInputs, false);
+
// Draw opaques forward
const auto opaqueInputs = DrawForward::Inputs(opaques, lightingModel).asVarying();
task.addJob("DrawOpaques", opaqueInputs, shapePlumber);
diff --git a/libraries/ui/src/VirtualPadManager.h b/libraries/ui/src/VirtualPadManager.h
index 6f7fbcc921..cfd40a6447 100644
--- a/libraries/ui/src/VirtualPadManager.h
+++ b/libraries/ui/src/VirtualPadManager.h
@@ -58,7 +58,7 @@ namespace VirtualPad {
private:
Instance _leftVPadInstance;
- bool _enabled;
+ bool _enabled {true};
bool _hidden;
glm::vec2 _jumpButtonPosition;
int _extraBottomMargin {0};
diff --git a/plugins/openvr/src/OpenVrDisplayPlugin.cpp b/plugins/openvr/src/OpenVrDisplayPlugin.cpp
index 714cb91b3f..5a7417cb49 100644
--- a/plugins/openvr/src/OpenVrDisplayPlugin.cpp
+++ b/plugins/openvr/src/OpenVrDisplayPlugin.cpp
@@ -36,7 +36,6 @@
Q_DECLARE_LOGGING_CATEGORY(displayplugins)
-const char* StandingHMDSensorMode { "Standing HMD Sensor Mode" }; // this probably shouldn't be hardcoded here
const char* OpenVrThreadedSubmit { "OpenVR Threaded Submit" }; // this probably shouldn't be hardcoded here
PoseData _nextRenderPoseData;
@@ -451,7 +450,6 @@ bool OpenVrDisplayPlugin::internalActivate() {
qDebug() << "OpenVR Threaded submit enabled: " << _threadedSubmit;
_openVrDisplayActive = true;
- _container->setIsOptionChecked(StandingHMDSensorMode, true);
_system->GetRecommendedRenderTargetSize(&_renderTargetSize.x, &_renderTargetSize.y);
// Recommended render target size is per-eye, so double the X size for
// left + right eyes
@@ -507,7 +505,6 @@ void OpenVrDisplayPlugin::internalDeactivate() {
Parent::internalDeactivate();
_openVrDisplayActive = false;
- _container->setIsOptionChecked(StandingHMDSensorMode, false);
if (_system) {
// TODO: Invalidate poses. It's fine if someone else sets these shared values, but we're about to stop updating them, and
// we don't want ViveControllerManager to consider old values to be valid.
diff --git a/scripts/system/+android/displayNames.js b/scripts/system/+android/displayNames.js
new file mode 100644
index 0000000000..509d85cd2b
--- /dev/null
+++ b/scripts/system/+android/displayNames.js
@@ -0,0 +1,167 @@
+"use strict";
+//
+// displayNames.js
+// scripts/system/
+//
+// Created by Cristian Duarte & Gabriel Calero on May 3, 2018
+// Copyright 2018 High Fidelity, Inc.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+(function() { // BEGIN LOCAL_SCOPE
+
+var MAX_DISTANCE_PX = 20; // Should we use dp instead?
+var UNKNOWN_NAME = "Unknown";
+var METERS_ABOVE_HEAD = 0.4;
+
+var TEXT_LINE_HEIGHT = .1;
+var TEXT_MARGIN = 0.025;
+
+var HIDE_MS = 10000;
+
+var currentTouchToAnalyze = null;
+
+var currentlyShownAvatar = {
+ avatarID: null,
+ avatar: null,
+ overlay: null
+};
+
+var logEnabled = false;
+
+var hideTimer = null;
+
+function printd(str) {
+ if (logEnabled) {
+ print("[displayNames.js] " + str);
+ }
+}
+
+function clearOverlay() {
+ currentlyShownAvatar.avatar = null;
+ if (currentlyShownAvatar.overlay) {
+ Overlays.editOverlay(currentlyShownAvatar.overlay, {visible: false});
+ }
+}
+
+function touchedAvatar(avatarID, avatarData) {
+ printd("[AVATARNAME] touchEnd FOUND " + JSON.stringify(avatarData));
+
+ if (hideTimer) {
+ Script.clearTimeout(hideTimer);
+ }
+
+ // Case: touching an already selected avatar
+ if (currentlyShownAvatar.avatar && currentlyShownAvatar.avatarID == avatarID) {
+ clearOverlay();
+ return;
+ }
+
+ // Save currently selected avatar
+ currentlyShownAvatar.avatarID = avatarID;
+ currentlyShownAvatar.avatar = avatarData;
+
+ if (currentlyShownAvatar.overlay == null) {
+ var over = Overlays.addOverlay("text3d", {
+ lineHeight: TEXT_LINE_HEIGHT,
+ color: { red: 255, green: 255, blue: 255},
+ backgroundColor: {red: 0, green: 0, blue: 0},
+ leftMargin: TEXT_MARGIN,
+ topMargin: TEXT_MARGIN,
+ rightMargin: TEXT_MARGIN,
+ bottomMargin: TEXT_MARGIN,
+ alpha: 0.6,
+ solid: true,
+ isFacingAvatar: true,
+ visible: false
+ });
+ currentlyShownAvatar.overlay = over;
+ }
+
+ var nameToShow = avatarData.displayName ? avatarData.displayName :
+ (avatarData.sessionDisplayName ? avatarData.sessionDisplayName : UNKNOWN_NAME);
+ var textSize = Overlays.textSize(currentlyShownAvatar.overlay, nameToShow);
+
+ Overlays.editOverlay(currentlyShownAvatar.overlay, {
+ dimensions: {
+ x: textSize.width + 2 * TEXT_MARGIN,
+ y: TEXT_LINE_HEIGHT + 2 * TEXT_MARGIN
+ },
+ localPosition: { x: 0, y: METERS_ABOVE_HEAD, z: 0 },
+ text: nameToShow,
+ parentID: avatarData.sessionUUID,
+ parentJointIndex: avatarData.getJointIndex("Head"),
+ visible: true
+ });
+
+ hideTimer = Script.setTimeout(function() {
+ clearOverlay();
+ }, HIDE_MS);
+}
+
+function touchBegin(event) {
+ currentTouchToAnalyze = event;
+}
+
+function touchEnd(event) {
+ if (Vec3.distance({x: event.x, y: event.y }, {x: currentTouchToAnalyze.x, y: currentTouchToAnalyze.y}) > MAX_DISTANCE_PX) {
+ printd("[AVATARNAME] touchEnd moved too much");
+ currentTouchToAnalyze = null;
+ return;
+ }
+
+ var pickRay = Camera.computePickRay(event.x, event.y);
+ var avatarRay = AvatarManager.findRayIntersection(pickRay, [], [MyAvatar.sessionUUID])
+
+ if (avatarRay.intersects) {
+ touchedAvatar(avatarRay.avatarID, AvatarManager.getAvatar(avatarRay.avatarID));
+ } else {
+ printd("[AVATARNAME] touchEnd released outside the avatar");
+ }
+
+ currentTouchToAnalyze = null;
+}
+
+var runAtLeastOnce = false;
+
+function ending() {
+ if (!runAtLeastOnce) {
+ return;
+ }
+
+ Controller.touchBeginEvent.disconnect(touchBegin);
+ Controller.touchEndEvent.disconnect(touchEnd);
+ Controller.mousePressEvent.disconnect(touchBegin);
+ Controller.mouseReleaseEvent.disconnect(touchEnd);
+
+ if (currentlyShownAvatar.overlay) {
+ Overlays.deleteOverlay(currentlyShownAvatar.overlay);
+ currentlyShownAvatar.overlay = null;
+ }
+ if (currentlyShownAvatar.avatar) {
+ currentlyShownAvatar.avatar = null;
+ }
+}
+
+function init() {
+ Controller.touchBeginEvent.connect(touchBegin);
+ Controller.touchEndEvent.connect(touchEnd);
+ Controller.mousePressEvent.connect(touchBegin);
+ Controller.mouseReleaseEvent.connect(touchEnd);
+
+ Script.scriptEnding.connect(function () {
+ ending();
+ });
+
+ runAtLeastOnce = true;
+}
+
+module.exports = {
+ init: init,
+ ending: ending
+}
+
+//init(); // Enable to use in desktop as a standalone
+
+}()); // END LOCAL_SCOPE
\ No newline at end of file
diff --git a/scripts/system/+android/modes.js b/scripts/system/+android/modes.js
index f5b3609c26..2c155ae386 100644
--- a/scripts/system/+android/modes.js
+++ b/scripts/system/+android/modes.js
@@ -28,6 +28,7 @@ modeLabel[MODE_MY_VIEW]="MY VIEW";
var logEnabled = false;
var radar = Script.require('./radar.js');
var uniqueColor = Script.require('./uniqueColor.js');
+var displayNames = Script.require('./displayNames.js');
function printd(str) {
if (logEnabled) {
@@ -87,8 +88,10 @@ function switchToMode(newMode) {
if (currentMode == MODE_RADAR) {
radar.startRadarMode();
+ displayNames.ending();
} else if (currentMode == MODE_MY_VIEW) {
// nothing to do yet
+ displayNames.init();
} else {
printd("Unknown view mode " + currentMode);
}
diff --git a/scripts/system/controllers/controllerModules/equipEntity.js b/scripts/system/controllers/controllerModules/equipEntity.js
index b6cad6841d..08b88fe74d 100644
--- a/scripts/system/controllers/controllerModules/equipEntity.js
+++ b/scripts/system/controllers/controllerModules/equipEntity.js
@@ -6,11 +6,11 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-/* global Script, Entities, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND,
- getControllerJointIndex, enableDispatcherModule, disableDispatcherModule,
+/* global Script, Entities, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND, Camera,
+ getControllerJointIndex, enableDispatcherModule, disableDispatcherModule, entityIsFarGrabbedByOther,
Messages, makeDispatcherModuleParameters, makeRunningValues, Settings, entityHasActions,
Vec3, Overlays, flatten, Xform, getControllerWorldLocation, ensureDynamic, entityIsCloneable,
- cloneEntity, DISPATCHER_PROPERTIES, TEAR_AWAY_DISTANCE, Uuid, unhighlightTargetEntity
+ cloneEntity, DISPATCHER_PROPERTIES, Uuid, unhighlightTargetEntity, isInEditMode
*/
Script.include("/~/system/libraries/Xform.js");
@@ -780,7 +780,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
}
}
};
-
+
var clearGrabActions = function(entityID) {
var actionIDs = Entities.getActionIDs(entityID);
var myGrabTag = "grab-" + MyAvatar.sessionUUID;
@@ -793,7 +793,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
}
}
};
-
+
var onMousePress = function(event) {
if (isInEditMode() || !event.isLeftButton) { // don't consider any left clicks on the entity while in edit
return;
@@ -807,7 +807,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
if (hasEquipData && entityProperties.parentID === EMPTY_PARENT_ID && !entityIsFarGrabbedByOther(entityID)) {
entityProperties.id = entityID;
var rightHandPosition = MyAvatar.getJointPosition("RightHand");
- var leftHandPosition = MyAvatar.getJointPosition("LeftHand");
+ var leftHandPosition = MyAvatar.getJointPosition("LeftHand");
var distanceToRightHand = Vec3.distance(entityProperties.position, rightHandPosition);
var distanceToLeftHand = Vec3.distance(entityProperties.position, leftHandPosition);
var leftHandAvailable = leftEquipEntity.targetEntityID === null;
@@ -827,7 +827,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
};
var onKeyPress = function(event) {
- if (event.text === UNEQUIP_KEY) {
+ if (event.text.toLowerCase() === UNEQUIP_KEY) {
if (rightEquipEntity.targetEntityID) {
rightEquipEntity.endEquipEntity();
}
diff --git a/scripts/system/controllers/controllerModules/nearActionGrabEntity.js b/scripts/system/controllers/controllerModules/nearActionGrabEntity.js
index 5e06ed762d..f528c6f80f 100644
--- a/scripts/system/controllers/controllerModules/nearActionGrabEntity.js
+++ b/scripts/system/controllers/controllerModules/nearActionGrabEntity.js
@@ -10,7 +10,7 @@
propsArePhysical, Messages, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, entityIsGrabbable,
Quat, Vec3, MSECS_PER_SEC, getControllerWorldLocation, makeDispatcherModuleParameters, makeRunningValues,
TRIGGER_OFF_VALUE, NEAR_GRAB_RADIUS, findGroupParent, entityIsCloneable, propsAreCloneDynamic, cloneEntity,
- HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, BUMPER_ON_VALUE, unhighlightTargetEntity
+ HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, BUMPER_ON_VALUE, unhighlightTargetEntity, Uuid
*/
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
diff --git a/scripts/system/controllers/controllerModules/nearGrabHyperLinkEntity.js b/scripts/system/controllers/controllerModules/nearGrabHyperLinkEntity.js
index 59ce79cfd1..962ae89bb9 100644
--- a/scripts/system/controllers/controllerModules/nearGrabHyperLinkEntity.js
+++ b/scripts/system/controllers/controllerModules/nearGrabHyperLinkEntity.js
@@ -7,12 +7,8 @@
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-/* global Script, Entities, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND,
- getControllerJointIndex, getGrabbableData, enableDispatcherModule, disableDispatcherModule,
- propsArePhysical, Messages, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, entityIsGrabbable,
- Quat, Vec3, MSECS_PER_SEC, getControllerWorldLocation, makeDispatcherModuleParameters, makeRunningValues,
- TRIGGER_OFF_VALUE, NEAR_GRAB_RADIUS, findGroupParent, entityIsCloneable, propsAreCloneDynamic, cloneEntity,
- HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, BUMPER_ON_VALUE, AddressManager
+/* global Script, MyAvatar, RIGHT_HAND, LEFT_HAND, enableDispatcherModule, disableDispatcherModule,
+ makeDispatcherModuleParameters, makeRunningValues, TRIGGER_OFF_VALUE, NEAR_GRAB_RADIUS, BUMPER_ON_VALUE, AddressManager
*/
(function() {
diff --git a/scripts/system/controllers/controllerModules/nearParentGrabEntity.js b/scripts/system/controllers/controllerModules/nearParentGrabEntity.js
index cda0a683c7..0ebd4efb2f 100644
--- a/scripts/system/controllers/controllerModules/nearParentGrabEntity.js
+++ b/scripts/system/controllers/controllerModules/nearParentGrabEntity.js
@@ -11,8 +11,7 @@
TRIGGER_OFF_VALUE, makeDispatcherModuleParameters, entityIsGrabbable, makeRunningValues, NEAR_GRAB_RADIUS,
findGroupParent, Vec3, cloneEntity, entityIsCloneable, propsAreCloneDynamic, HAPTIC_PULSE_STRENGTH,
HAPTIC_PULSE_DURATION, BUMPER_ON_VALUE, findHandChildEntities, TEAR_AWAY_DISTANCE, MSECS_PER_SEC, TEAR_AWAY_CHECK_TIME,
- TEAR_AWAY_COUNT, distanceBetweenPointAndEntityBoundingBox, print, Selection, DISPATCHER_HOVERING_LIST, Uuid,
- highlightTargetEntity, unhighlightTargetEntity
+ TEAR_AWAY_COUNT, distanceBetweenPointAndEntityBoundingBox, print, Uuid, highlightTargetEntity, unhighlightTargetEntity
*/
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
@@ -43,11 +42,6 @@ Script.include("/~/system/libraries/cloneEntityUtils.js");
[],
100);
-
- // XXX does handJointIndex change if the avatar changes?
- this.handJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ? "RightHand" : "LeftHand");
- this.controllerJointIndex = getControllerJointIndex(this.hand);
-
this.thisHandIsParent = function(props) {
if (!props) {
return false;
@@ -62,8 +56,7 @@ Script.include("/~/system/libraries/cloneEntityUtils.js");
return true;
}
- var controllerJointIndex = this.controllerJointIndex;
- if (props.parentJointIndex === controllerJointIndex) {
+ if (props.parentJointIndex === getControllerJointIndex(this.hand)) {
return true;
}
@@ -102,7 +95,7 @@ Script.include("/~/system/libraries/cloneEntityUtils.js");
// } else {
// handJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ? "RightHand" : "LeftHand");
// }
- handJointIndex = this.controllerJointIndex;
+ handJointIndex = getControllerJointIndex(this.hand);
var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID];
Entities.callEntityMethod(targetProps.id, "startNearGrab", args);
diff --git a/scripts/system/controllers/controllerModules/nearParentGrabOverlay.js b/scripts/system/controllers/controllerModules/nearParentGrabOverlay.js
index 0f876816b3..368d5c483b 100644
--- a/scripts/system/controllers/controllerModules/nearParentGrabOverlay.js
+++ b/scripts/system/controllers/controllerModules/nearParentGrabOverlay.js
@@ -9,7 +9,7 @@
/* global Script, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND, getControllerJointIndex,
enableDispatcherModule, disableDispatcherModule, Messages, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION,
makeDispatcherModuleParameters, Overlays, makeRunningValues, Vec3, resizeTablet, getTabletWidthFromSettings,
- NEAR_GRAB_RADIUS
+ NEAR_GRAB_RADIUS, HMD, Uuid
*/
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
@@ -37,7 +37,6 @@ Script.include("/~/system/libraries/utils.js");
// XXX does handJointIndex change if the avatar changes?
this.handJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ? "RightHand" : "LeftHand");
- this.controllerJointIndex = getControllerJointIndex(this.hand);
this.getOtherModule = function() {
return (this.hand === RIGHT_HAND) ? leftNearParentingGrabOverlay : rightNearParentingGrabOverlay;
diff --git a/scripts/system/controllers/controllerModules/teleport.js b/scripts/system/controllers/controllerModules/teleport.js
index 560da57b20..3bf99ca26a 100644
--- a/scripts/system/controllers/controllerModules/teleport.js
+++ b/scripts/system/controllers/controllerModules/teleport.js
@@ -10,7 +10,7 @@
/* jslint bitwise: true */
-/* global Script, Entities, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND, getControllerJointIndex,
+/* global Script, Entities, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND,
enableDispatcherModule, disableDispatcherModule, Messages, makeDispatcherModuleParameters, makeRunningValues, Vec3,
HMD, Uuid, AvatarList, Picks, Pointers, PickType
*/
diff --git a/scripts/system/html/entityList.html b/scripts/system/html/entityList.html
index d608ab63e5..7906a3c97f 100644
--- a/scripts/system/html/entityList.html
+++ b/scripts/system/html/entityList.html
@@ -14,7 +14,6 @@
-
diff --git a/scripts/system/html/entityProperties.html b/scripts/system/html/entityProperties.html
index 8647dca035..8d63261f4c 100644
--- a/scripts/system/html/entityProperties.html
+++ b/scripts/system/html/entityProperties.html
@@ -20,7 +20,6 @@
-
diff --git a/scripts/system/html/gridControls.html b/scripts/system/html/gridControls.html
index c0bd87988d..cd646fed51 100644
--- a/scripts/system/html/gridControls.html
+++ b/scripts/system/html/gridControls.html
@@ -16,7 +16,6 @@
-
diff --git a/scripts/system/html/js/entityList.js b/scripts/system/html/js/entityList.js
index 625aa26b00..88b3ccbf7c 100644
--- a/scripts/system/html/js/entityList.js
+++ b/scripts/system/html/js/entityList.js
@@ -444,8 +444,6 @@ function loaded() {
augmentSpinButtons();
- setUpKeyboardControl();
-
// Disable right-click context menu which is not visible in the HMD and makes it seem like the app has locked
document.addEventListener("contextmenu", function (event) {
event.preventDefault();
diff --git a/scripts/system/html/js/entityProperties.js b/scripts/system/html/js/entityProperties.js
index 10e7b4b60e..e016a21731 100644
--- a/scripts/system/html/js/entityProperties.js
+++ b/scripts/system/html/js/entityProperties.js
@@ -7,7 +7,7 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
/* global alert, augmentSpinButtons, clearTimeout, console, document, Element, EventBridge,
- HifiEntityUI, JSONEditor, openEventBridge, setUpKeyboardControl, setTimeout, window, _ $ */
+ HifiEntityUI, JSONEditor, openEventBridge, setTimeout, window, _ $ */
var PI = 3.14159265358979;
var DEGREES_TO_RADIANS = PI / 180.0;
@@ -2104,8 +2104,6 @@ function loaded() {
augmentSpinButtons();
- setUpKeyboardControl();
-
// Disable right-click context menu which is not visible in the HMD and makes it seem like the app has locked
document.addEventListener("contextmenu", function(event) {
event.preventDefault();
diff --git a/scripts/system/html/js/gridControls.js b/scripts/system/html/js/gridControls.js
index be4271788e..79a169400a 100644
--- a/scripts/system/html/js/gridControls.js
+++ b/scripts/system/html/js/gridControls.js
@@ -129,8 +129,6 @@ function loaded() {
augmentSpinButtons();
- setUpKeyboardControl();
-
EventBridge.emitWebEvent(JSON.stringify({ type: 'init' }));
});
document.addEventListener("keydown", function (keyDown) {
diff --git a/scripts/system/html/js/keyboardControl.js b/scripts/system/html/js/keyboardControl.js
deleted file mode 100644
index 7a8a314c62..0000000000
--- a/scripts/system/html/js/keyboardControl.js
+++ /dev/null
@@ -1,73 +0,0 @@
-//
-// keyboardControl.js
-//
-// Created by David Rowe on 28 Sep 2016.
-// Copyright 2016 High Fidelity, Inc.
-//
-// Distributed under the Apache License, Version 2.0.
-// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-//
-
-function setUpKeyboardControl() {
-
- var lowerTimer = null;
- var isRaised = false;
- var KEYBOARD_HEIGHT = 200;
-
- function raiseKeyboard() {
- window.isKeyboardRaised = true;
- window.isNumericKeyboard = this.type === "number";
-
- if (lowerTimer !== null) {
- clearTimeout(lowerTimer);
- lowerTimer = null;
- }
-
- EventBridge.emitWebEvent("_RAISE_KEYBOARD" + (this.type === "number" ? "_NUMERIC" : ""));
-
- if (!isRaised) {
- var delta = this.getBoundingClientRect().bottom + 10 - (document.body.clientHeight - KEYBOARD_HEIGHT);
- if (delta > 0) {
- setTimeout(function () {
- document.body.scrollTop += delta;
- }, 500); // Allow time for keyboard to be raised in QML.
- }
- }
-
- isRaised = true;
- }
-
- function doLowerKeyboard() {
- window.isKeyboardRaised = false;
- window.isNumericKeyboard = false;
-
- EventBridge.emitWebEvent("_LOWER_KEYBOARD");
- lowerTimer = null;
- isRaised = false;
- }
-
- function lowerKeyboard() {
- // Delay lowering keyboard a little in case immediately raise it again.
- if (lowerTimer === null) {
- lowerTimer = setTimeout(doLowerKeyboard, 20);
- }
- }
-
- function documentBlur() {
- // Action any pending Lower keyboard event immediately upon leaving document window so that they don't interfere with
- // other Entities Editor tab.
- if (lowerTimer !== null) {
- clearTimeout(lowerTimer);
- doLowerKeyboard();
- }
- }
-
- var inputs = document.querySelectorAll("input[type=text], input[type=password], input[type=number], textarea");
- for (var i = 0, length = inputs.length; i < length; i++) {
- inputs[i].addEventListener("focus", raiseKeyboard);
- inputs[i].addEventListener("blur", lowerKeyboard);
- }
-
- window.addEventListener("blur", documentBlur);
-}
-
diff --git a/scripts/system/libraries/controllerDispatcherUtils.js b/scripts/system/libraries/controllerDispatcherUtils.js
index 43945c6145..1506ce17b2 100644
--- a/scripts/system/libraries/controllerDispatcherUtils.js
+++ b/scripts/system/libraries/controllerDispatcherUtils.js
@@ -7,7 +7,7 @@
/* global module, Camera, HMD, MyAvatar, controllerDispatcherPlugins:true, Quat, Vec3, Overlays, Xform,
- Selection,
+ Selection, Uuid,
MSECS_PER_SEC:true , LEFT_HAND:true, RIGHT_HAND:true, FORBIDDEN_GRAB_TYPES:true,
HAPTIC_PULSE_STRENGTH:true, HAPTIC_PULSE_DURATION:true, ZERO_VEC:true, ONE_VEC:true,
DEFAULT_REGISTRATION_POINT:true, INCHES_TO_METERS:true,
@@ -34,11 +34,12 @@
getGrabbableData:true,
entityIsGrabbable:true,
entityIsDistanceGrabbable:true,
+ getControllerJointIndexCacheTime:true,
+ getControllerJointIndexCache:true,
getControllerJointIndex:true,
propsArePhysical:true,
controllerDispatcherPluginsNeedSort:true,
projectOntoXYPlane:true,
- getChildrenProps:true,
projectOntoEntityXYPlane:true,
projectOntoOverlayXYPlane:true,
makeLaserLockInfo:true,
@@ -53,6 +54,8 @@
TEAR_AWAY_COUNT:true,
TEAR_AWAY_CHECK_TIME:true,
distanceBetweenPointAndEntityBoundingBox:true,
+ entityIsEquipped:true,
+ entityIsFarGrabbedByOther:true,
highlightTargetEntity:true,
clearHighlightedEntities:true,
unhighlightTargetEntity:true
@@ -266,20 +269,32 @@ entityIsDistanceGrabbable = function(props) {
return true;
};
-getControllerJointIndex = function (hand) {
- if (HMD.isHandControllerAvailable()) {
- var controllerJointIndex = -1;
- if (Camera.mode === "first person") {
- controllerJointIndex = MyAvatar.getJointIndex(hand === RIGHT_HAND ?
- "_CONTROLLER_RIGHTHAND" :
- "_CONTROLLER_LEFTHAND");
- } else if (Camera.mode === "third person") {
- controllerJointIndex = MyAvatar.getJointIndex(hand === RIGHT_HAND ?
- "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" :
- "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND");
- }
+getControllerJointIndexCacheTime = [0, 0];
+getControllerJointIndexCache = [-1, -1];
- return controllerJointIndex;
+getControllerJointIndex = function (hand) {
+ var GET_CONTROLLERJOINTINDEX_CACHE_REFRESH_TIME = 3000; // msecs
+
+ var now = Date.now();
+ if (now - getControllerJointIndexCacheTime[hand] > GET_CONTROLLERJOINTINDEX_CACHE_REFRESH_TIME) {
+ if (HMD.isHandControllerAvailable()) {
+ var controllerJointIndex = -1;
+ if (Camera.mode === "first person") {
+ controllerJointIndex = MyAvatar.getJointIndex(hand === RIGHT_HAND ?
+ "_CONTROLLER_RIGHTHAND" :
+ "_CONTROLLER_LEFTHAND");
+ } else if (Camera.mode === "third person") {
+ controllerJointIndex = MyAvatar.getJointIndex(hand === RIGHT_HAND ?
+ "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" :
+ "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND");
+ }
+
+ getControllerJointIndexCacheTime[hand] = now;
+ getControllerJointIndexCache[hand] = controllerJointIndex;
+ return controllerJointIndex;
+ }
+ } else {
+ return getControllerJointIndexCache[hand];
}
return -1;
diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js
index c3edee264f..dc4d5aa844 100644
--- a/scripts/system/marketplaces/marketplaces.js
+++ b/scripts/system/marketplaces/marketplaces.js
@@ -19,6 +19,7 @@ var selectionDisplay = null; // for gridTool.js to ignore
Script.include("/~/system/libraries/WebTablet.js");
Script.include("/~/system/libraries/gridTool.js");
+ Script.include("/~/system/libraries/connectionUtils.js");
var METAVERSE_SERVER_URL = Account.metaverseServerURL;
var MARKETPLACE_URL = METAVERSE_SERVER_URL + "/marketplace";
diff --git a/tests-manual/render-texture-load/src/GLIHelpers.h b/tests-manual/render-texture-load/src/GLIHelpers.h
index 886176e874..a5d4f71bb3 100644
--- a/tests-manual/render-texture-load/src/GLIHelpers.h
+++ b/tests-manual/render-texture-load/src/GLIHelpers.h
@@ -15,7 +15,7 @@
// Work around for a bug in the MSVC compiler that chokes when you use GLI and Qt headers together.
#define gli glm
-#ifdef Q_OS_MAC
+#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-variable"
#pragma clang diagnostic ignored "-Wignored-qualifiers"
@@ -33,7 +33,7 @@
#include
-#ifdef Q_OS_MAC
+#if defined(__clang__)
#pragma clang diagnostic pop
#endif