setting { QStringList() << group << key , defaultValue};
- return setting.get();
-}
-
JNIEXPORT void JNICALL
Java_io_highfidelity_hifiinterface_receiver_HeadsetStateReceiver_notifyHeadsetOn(JNIEnv *env,
jobject instance,
diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/HifiUtils.java b/android/app/src/main/java/io/highfidelity/hifiinterface/HifiUtils.java
index f92cd0a385..a85e18d9a9 100644
--- a/android/app/src/main/java/io/highfidelity/hifiinterface/HifiUtils.java
+++ b/android/app/src/main/java/io/highfidelity/hifiinterface/HifiUtils.java
@@ -64,4 +64,10 @@ public class HifiUtils {
public native String protocolVersionSignature();
+ public native boolean isUserLoggedIn();
+
+ public native void updateHifiSetting(String group, String key, boolean value);
+ public native boolean getHifiSettingBoolean(String group, String key, boolean defaultValue);
+
+ public native boolean isKeepingLoggedIn();
}
diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/InterfaceActivity.java b/android/app/src/main/java/io/highfidelity/hifiinterface/InterfaceActivity.java
index 90e411173b..50aea59663 100644
--- a/android/app/src/main/java/io/highfidelity/hifiinterface/InterfaceActivity.java
+++ b/android/app/src/main/java/io/highfidelity/hifiinterface/InterfaceActivity.java
@@ -76,7 +76,7 @@ public class InterfaceActivity extends QtActivity implements WebViewFragment.OnW
private static boolean inVrMode;
private boolean nativeEnterBackgroundCallEnqueued = false;
- private SlidingDrawer webSlidingDrawer;
+ private SlidingDrawer mWebSlidingDrawer;
// private GvrApi gvrApi;
// Opaque native pointer to the Application C++ object.
// This object is owned by the InterfaceActivity instance and passed to the native methods.
@@ -116,17 +116,6 @@ public class InterfaceActivity extends QtActivity implements WebViewFragment.OnW
//nativeGvrApi =
nativeOnCreate(this, assetManager /*, gvrApi.getNativeGvrContext()*/);
- Point size = new Point();
- getWindowManager().getDefaultDisplay().getRealSize(size);
-
- try {
- PackageInfo pInfo = this.getPackageManager().getPackageInfo(getPackageName(), 0);
- String version = pInfo.versionName;
-// setAppVersion(version);
- } catch (PackageManager.NameNotFoundException e) {
- Log.e("GVR", "Error getting application version", e);
- }
-
final View rootView = getWindow().getDecorView().findViewById(android.R.id.content);
// This is a workaround to hide the menu bar when the virtual keyboard is shown from Qt
@@ -137,26 +126,6 @@ public class InterfaceActivity extends QtActivity implements WebViewFragment.OnW
});
startActivity(new Intent(this, SplashActivity.class));
mVibrator = (Vibrator) this.getSystemService(VIBRATOR_SERVICE);
-
- FrameLayout mainLayout = findViewById(android.R.id.content);
- LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- webSlidingDrawer = (SlidingDrawer) inflater.inflate(R.layout.web_drawer, mainLayout, false);
- QtLayout qtLayout = (QtLayout) mainLayout.getChildAt(0);
- QtLayout.LayoutParams layoutParams = new QtLayout.LayoutParams(webSlidingDrawer.getLayoutParams());
- webSlidingDrawer.setOnDrawerCloseListener(() -> {
- WebViewFragment webViewFragment = (WebViewFragment) getFragmentManager().findFragmentByTag("webViewFragment");
- webViewFragment.close();
- });
- int widthPx = Math.max(size.x, size.y);
- int heightPx = Math.min(size.x, size.y);
-
- layoutParams.x = (int) (widthPx - WEB_DRAWER_RIGHT_MARGIN * getResources().getDisplayMetrics().xdpi / NORMAL_DPI);
- layoutParams.y = (int) (heightPx - WEB_DRAWER_BOTTOM_MARGIN * getResources().getDisplayMetrics().ydpi / NORMAL_DPI);
-
- layoutParams.resolveLayoutDirection(View.LAYOUT_DIRECTION_RTL);
- qtLayout.addView(webSlidingDrawer, layoutParams);
- webSlidingDrawer.setVisibility(View.GONE);
-
headsetStateReceiver = new HeadsetStateReceiver();
}
@@ -289,14 +258,47 @@ public class InterfaceActivity extends QtActivity implements WebViewFragment.OnW
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
if (intent.hasExtra(DOMAIN_URL)) {
- webSlidingDrawer.setVisibility(View.GONE);
+ hideWebDrawer();
nativeGotoUrl(intent.getStringExtra(DOMAIN_URL));
} else if (intent.hasExtra(EXTRA_GOTO_USERNAME)) {
- webSlidingDrawer.setVisibility(View.GONE);
+ hideWebDrawer();
nativeGoToUser(intent.getStringExtra(EXTRA_GOTO_USERNAME));
}
}
+ private void hideWebDrawer() {
+ if (mWebSlidingDrawer != null) {
+ mWebSlidingDrawer.setVisibility(View.GONE);
+ }
+ }
+
+ public void showWebDrawer() {
+ if (mWebSlidingDrawer == null) {
+ FrameLayout mainLayout = findViewById(android.R.id.content);
+ LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ QtLayout qtLayout = (QtLayout) mainLayout.getChildAt(0);
+ mWebSlidingDrawer = (SlidingDrawer) inflater.inflate(R.layout.web_drawer, mainLayout, false);
+
+ QtLayout.LayoutParams layoutParams = new QtLayout.LayoutParams(mWebSlidingDrawer.getLayoutParams());
+ mWebSlidingDrawer.setOnDrawerCloseListener(() -> {
+ WebViewFragment webViewFragment = (WebViewFragment) getFragmentManager().findFragmentByTag("webViewFragment");
+ webViewFragment.close();
+ });
+
+ Point size = new Point();
+ getWindowManager().getDefaultDisplay().getRealSize(size);
+ int widthPx = Math.max(size.x, size.y);
+ int heightPx = Math.min(size.x, size.y);
+
+ layoutParams.x = (int) (widthPx - WEB_DRAWER_RIGHT_MARGIN * getResources().getDisplayMetrics().xdpi / NORMAL_DPI);
+ layoutParams.y = (int) (heightPx - WEB_DRAWER_BOTTOM_MARGIN * getResources().getDisplayMetrics().ydpi / NORMAL_DPI);
+
+ layoutParams.resolveLayoutDirection(View.LAYOUT_DIRECTION_RTL);
+ qtLayout.addView(mWebSlidingDrawer, layoutParams);
+ }
+ mWebSlidingDrawer.setVisibility(View.VISIBLE);
+ }
+
public void openAndroidActivity(String activityName, boolean backToScene) {
openAndroidActivity(activityName, backToScene, null);
}
@@ -313,29 +315,29 @@ public class InterfaceActivity extends QtActivity implements WebViewFragment.OnW
break;
case "Login":
nativeBeforeEnterBackground();
- Intent loginIntent = new Intent(this, MainActivity.class);
- loginIntent.putExtra(MainActivity.EXTRA_FRAGMENT, activityName);
- loginIntent.putExtra(MainActivity.EXTRA_BACK_TO_SCENE, backToScene);
+ Intent loginIntent = new Intent(this, LoginMenuActivity.class);
+ loginIntent.putExtra(LoginMenuActivity.EXTRA_BACK_TO_SCENE, backToScene);
+ loginIntent.putExtra(LoginMenuActivity.EXTRA_BACK_ON_SKIP, true);
if (args != null && args.containsKey(DOMAIN_URL)) {
- loginIntent.putExtra(DOMAIN_URL, (String) args.get(DOMAIN_URL));
+ loginIntent.putExtra(LoginMenuActivity.EXTRA_DOMAIN_URL, (String) args.get(DOMAIN_URL));
}
startActivity(loginIntent);
break;
case "WebView":
runOnUiThread(() -> {
- webSlidingDrawer.setVisibility(View.VISIBLE);
- if (!webSlidingDrawer.isOpened()) {
- webSlidingDrawer.animateOpen();
+ showWebDrawer();
+ if (!mWebSlidingDrawer.isOpened()) {
+ mWebSlidingDrawer.animateOpen();
}
if (args != null && args.containsKey(WebViewActivity.WEB_VIEW_ACTIVITY_EXTRA_URL)) {
WebViewFragment webViewFragment = (WebViewFragment) getFragmentManager().findFragmentByTag("webViewFragment");
webViewFragment.loadUrl((String) args.get(WebViewActivity.WEB_VIEW_ACTIVITY_EXTRA_URL), true);
webViewFragment.setToolbarVisible(true);
webViewFragment.setCloseAction(() -> {
- if (webSlidingDrawer.isOpened()) {
- webSlidingDrawer.animateClose();
+ if (mWebSlidingDrawer.isOpened()) {
+ mWebSlidingDrawer.animateClose();
}
- webSlidingDrawer.setVisibility(View.GONE);
+ hideWebDrawer();
});
}
});
@@ -381,4 +383,7 @@ public class InterfaceActivity extends QtActivity implements WebViewFragment.OnW
public void onExpand() {
keepInterfaceRunning = true;
}
+
+ @Override
+ public void onOAuthAuthorizeCallback(Uri uri) { }
}
diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/LoginMenuActivity.java b/android/app/src/main/java/io/highfidelity/hifiinterface/LoginMenuActivity.java
new file mode 100644
index 0000000000..5cb196249d
--- /dev/null
+++ b/android/app/src/main/java/io/highfidelity/hifiinterface/LoginMenuActivity.java
@@ -0,0 +1,210 @@
+package io.highfidelity.hifiinterface;
+
+
+import android.app.Fragment;
+import android.app.FragmentManager;
+import android.app.FragmentTransaction;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.view.View;
+import io.highfidelity.hifiinterface.fragment.LoginFragment;
+import io.highfidelity.hifiinterface.fragment.OnBackPressedListener;
+import io.highfidelity.hifiinterface.fragment.SignupFragment;
+import io.highfidelity.hifiinterface.fragment.StartMenuFragment;
+
+public class LoginMenuActivity extends AppCompatActivity
+ implements StartMenuFragment.StartMenuInteractionListener,
+ LoginFragment.OnLoginInteractionListener,
+ SignupFragment.OnSignupInteractionListener {
+
+ /**
+ * Set EXTRA_FINISH_ON_BACK to finish the app when back button is pressed
+ */
+ public static final String EXTRA_FINISH_ON_BACK = "finishOnBack";
+
+ /**
+ * Set EXTRA_BACK_TO_SCENE to back to the scene
+ */
+ public static final String EXTRA_BACK_TO_SCENE = "backToScene";
+
+ /**
+ * Set EXTRA_BACK_ON_SKIP to finish this activity when skip button is pressed
+ */
+ public static final String EXTRA_BACK_ON_SKIP = "backOnSkip";
+
+ public static final String EXTRA_DOMAIN_URL = "url";
+
+ private boolean finishOnBack;
+ private boolean backToScene;
+ private boolean backOnSkip;
+ private String domainUrlToBack;
+
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_encourage_login);
+
+ finishOnBack = getIntent().getBooleanExtra(EXTRA_FINISH_ON_BACK, false);
+ backToScene = getIntent().getBooleanExtra(EXTRA_BACK_TO_SCENE, false);
+ domainUrlToBack = getIntent().getStringExtra(EXTRA_DOMAIN_URL);
+ backOnSkip = getIntent().getBooleanExtra(EXTRA_BACK_ON_SKIP, false);
+
+ if (savedInstanceState != null) {
+ finishOnBack = savedInstanceState.getBoolean(EXTRA_FINISH_ON_BACK, false);
+ backToScene = savedInstanceState.getBoolean(EXTRA_BACK_TO_SCENE, false);
+ backOnSkip = savedInstanceState.getBoolean(EXTRA_BACK_ON_SKIP, false);
+ domainUrlToBack = savedInstanceState.getString(EXTRA_DOMAIN_URL);
+ }
+
+ loadMenuFragment();
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putBoolean(EXTRA_FINISH_ON_BACK, finishOnBack);
+ outState.putBoolean(EXTRA_BACK_TO_SCENE, backToScene);
+ outState.putString(EXTRA_DOMAIN_URL, domainUrlToBack);
+ }
+
+ @Override
+ protected void onRestoreInstanceState(Bundle savedInstanceState) {
+ super.onRestoreInstanceState(savedInstanceState);
+ finishOnBack = savedInstanceState.getBoolean(EXTRA_FINISH_ON_BACK, false);
+ backToScene = savedInstanceState.getBoolean(EXTRA_BACK_TO_SCENE, false);
+ backOnSkip = savedInstanceState.getBoolean(EXTRA_BACK_ON_SKIP, false);
+ domainUrlToBack = savedInstanceState.getString(EXTRA_DOMAIN_URL);
+ }
+
+ private void loadMenuFragment() {
+ FragmentManager fragmentManager = getFragmentManager();
+ FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
+ Fragment fragment = StartMenuFragment.newInstance();
+ fragmentTransaction.replace(R.id.content_frame, fragment);
+ fragmentTransaction.addToBackStack(fragment.toString());
+ fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
+ fragmentTransaction.commit();
+ hideStatusBar();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ hideStatusBar();
+ }
+
+ private void hideStatusBar() {
+ View decorView = getWindow().getDecorView();
+ // Hide the status bar.
+ int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
+ decorView.setSystemUiVisibility(uiOptions);
+ }
+
+ @Override
+ public void onSignupButtonClicked() {
+ loadSignupFragment();
+ }
+
+ @Override
+ public void onLoginButtonClicked() {
+ loadLoginFragment(false);
+ }
+
+ @Override
+ public void onSkipLoginClicked() {
+ if (backOnSkip) {
+ onBackPressed();
+ } else {
+ loadMainActivity();
+ }
+ }
+
+ @Override
+ public void onSteamLoginButtonClicked() {
+ loadLoginFragment(true);
+ }
+
+ private void loadSignupFragment() {
+ FragmentManager fragmentManager = getFragmentManager();
+ FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
+ Fragment fragment = SignupFragment.newInstance();
+ String tag = getString(R.string.tagFragmentSignup);
+ fragmentTransaction.replace(R.id.content_frame, fragment, tag);
+ fragmentTransaction.addToBackStack(tag);
+ fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
+ fragmentTransaction.commit();
+ hideStatusBar();
+ }
+
+ private void loadLoginFragment(boolean useOauth) {
+ FragmentManager fragmentManager = getFragmentManager();
+ FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
+ Fragment fragment = LoginFragment.newInstance(useOauth);
+ String tag = getString(R.string.tagFragmentLogin);
+ fragmentTransaction.replace(R.id.content_frame, fragment, tag);
+ fragmentTransaction.addToBackStack(tag);
+ fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
+ fragmentTransaction.commit();
+ hideStatusBar();
+ }
+
+ @Override
+ public void onLoginCompleted() {
+ loadMainActivity();
+ }
+
+ @Override
+ public void onCancelLogin() {
+ getFragmentManager().popBackStack();
+ }
+
+ @Override
+ public void onCancelSignup() {
+ getFragmentManager().popBackStack();
+ }
+
+ private void loadMainActivity() {
+ finish();
+ if (backToScene) {
+ backToScene = false;
+ goToDomain(domainUrlToBack != null? domainUrlToBack : "");
+ } else {
+ startActivity(new Intent(this, MainActivity.class));
+ }
+ }
+
+ private void goToDomain(String domainUrl) {
+ Intent intent = new Intent(this, InterfaceActivity.class);
+ intent.putExtra(InterfaceActivity.DOMAIN_URL, domainUrl);
+ finish();
+ intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
+ startActivity(intent);
+ }
+
+
+ @Override
+ public void onSignupCompleted() {
+ loadMainActivity();
+ }
+
+ @Override
+ public void onBackPressed() {
+ FragmentManager fm = getFragmentManager();
+ int index = fm.getBackStackEntryCount() - 1;
+ if (index > 0) {
+ FragmentManager.BackStackEntry backEntry = fm.getBackStackEntryAt(index);
+ String tag = backEntry.getName();
+ Fragment topFragment = getFragmentManager().findFragmentByTag(tag);
+ if (!(topFragment instanceof OnBackPressedListener) ||
+ !((OnBackPressedListener) topFragment).doBack()) {
+ super.onBackPressed();
+ }
+ } else if (finishOnBack){
+ finishAffinity();
+ } else {
+ finish();
+ }
+ }
+}
diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/MainActivity.java b/android/app/src/main/java/io/highfidelity/hifiinterface/MainActivity.java
index 7df04100b0..e17b530f1c 100644
--- a/android/app/src/main/java/io/highfidelity/hifiinterface/MainActivity.java
+++ b/android/app/src/main/java/io/highfidelity/hifiinterface/MainActivity.java
@@ -1,5 +1,6 @@
package io.highfidelity.hifiinterface;
+import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
@@ -29,23 +30,16 @@ import android.widget.TextView;
import com.squareup.picasso.Callback;
import com.squareup.picasso.Picasso;
-import java.util.HashMap;
-import java.util.Map;
-
import io.highfidelity.hifiinterface.fragment.FriendsFragment;
import io.highfidelity.hifiinterface.fragment.HomeFragment;
-import io.highfidelity.hifiinterface.fragment.LoginFragment;
import io.highfidelity.hifiinterface.fragment.PolicyFragment;
import io.highfidelity.hifiinterface.fragment.SettingsFragment;
-import io.highfidelity.hifiinterface.fragment.SignedInFragment;
-import io.highfidelity.hifiinterface.fragment.SignupFragment;import io.highfidelity.hifiinterface.task.DownloadProfileImageTask;
+import io.highfidelity.hifiinterface.fragment.SignupFragment;
+import io.highfidelity.hifiinterface.task.DownloadProfileImageTask;
public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener,
- LoginFragment.OnLoginInteractionListener,
HomeFragment.OnHomeInteractionListener,
- FriendsFragment.OnHomeInteractionListener,
- SignupFragment.OnSignupInteractionListener,
- SignedInFragment.OnSignedInInteractionListener {
+ FriendsFragment.OnHomeInteractionListener {
private static final int PROFILE_PICTURE_PLACEHOLDER = R.drawable.default_profile_avatar;
public static final String DEFAULT_FRAGMENT = "Home";
@@ -55,9 +49,9 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
private String TAG = "HighFidelity";
- public native boolean nativeIsLoggedIn();
- public native void nativeLogout();
- public native String nativeGetDisplayName();
+ public native void logout();
+ public native void setUsernameChangedListener(Activity usernameChangedListener);
+ public native String getUsername();
private DrawerLayout mDrawerLayout;
private NavigationView mNavigationView;
@@ -130,9 +124,6 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
private void loadFragment(String fragment) {
switch (fragment) {
- case "Login":
- loadLoginFragment();
- break;
case "Home":
loadHomeFragment(true);
break;
@@ -153,19 +144,10 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
loadFragment(fragment, getString(R.string.home), getString(R.string.tagFragmentHome), addToBackStack, true);
}
- private void loadLoginFragment() {
- Fragment fragment = LoginFragment.newInstance();
- loadFragment(fragment, getString(R.string.login), getString(R.string.tagFragmentLogin), true, true);
- }
-
- private void loadSignedInFragment() {
- Fragment fragment = SignedInFragment.newInstance();
- loadFragment(fragment, getString(R.string.welcome), getString(R.string.tagFragmentSignedIn), true, true);
- }
-
- private void loadSignupFragment() {
- Fragment fragment = SignupFragment.newInstance();
- loadFragment(fragment, getString(R.string.signup), getString(R.string.tagFragmentSignup), true, false);
+ private void startLoginMenuActivity() {
+ Intent intent = new Intent(this, LoginMenuActivity.class);
+ intent.putExtra(LoginMenuActivity.EXTRA_BACK_ON_SKIP, true);
+ startActivity(intent);
}
private void loadPrivacyPolicyFragment() {
@@ -223,7 +205,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
private void updateLoginMenu() {
- if (nativeIsLoggedIn()) {
+ if (HifiUtils.getInstance().isUserLoggedIn()) {
mLoginPanel.setVisibility(View.GONE);
mProfilePanel.setVisibility(View.VISIBLE);
mLogoutOption.setVisibility(View.VISIBLE);
@@ -239,7 +221,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
}
private void updateProfileHeader() {
- updateProfileHeader(nativeGetDisplayName());
+ updateProfileHeader(getUsername());
}
private void updateProfileHeader(String username) {
if (!username.isEmpty()) {
@@ -289,15 +271,22 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
@Override
protected void onStart() {
super.onStart();
+ setUsernameChangedListener(this);
updateLoginMenu();
}
+ @Override
+ protected void onStop() {
+ super.onStop();
+ setUsernameChangedListener(null);
+ }
+
public void onLoginClicked(View view) {
- loadLoginFragment();
+ startLoginMenuActivity();
}
public void onLogoutClicked(View view) {
- nativeLogout();
+ logout();
updateLoginMenu();
exitLoggedInFragment();
@@ -338,42 +327,6 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
startActivity(intent);
}
- @Override
- public void onLoginCompleted() {
- loadHomeFragment(false);
- updateLoginMenu();
- if (backToScene) {
- backToScene = false;
- goToLastLocation();
- }
- }
-
- @Override
- public void onGettingStarted() {
- loadHomeFragment(false);
- if (backToScene) {
- backToScene = false;
- goToLastLocation();
- }
- }
-
- @Override
- public void onLoginRequested() {
- // go back from signup to login
- onBackPressed();
- }
-
- @Override
- public void onSignupRequested() {
- loadSignupFragment();
- }
-
- @Override
- public void onSignupCompleted() {
- loadSignedInFragment();
- updateLoginMenu();
- }
-
public void handleUsernameChanged(String username) {
runOnUiThread(() -> updateProfileHeader(username));
}
@@ -418,7 +371,6 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
public void onBackPressed() {
// if a fragment needs to internally manage back presses..
FragmentManager fm = getFragmentManager();
- Log.d("[BACK]", "getBackStackEntryCount " + fm.getBackStackEntryCount());
Fragment friendsFragment = fm.findFragmentByTag(getString(R.string.tagFragmentPeople));
if (friendsFragment != null && friendsFragment instanceof FriendsFragment) {
if (((FriendsFragment) friendsFragment).onBackPressed()) {
diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/SplashActivity.java b/android/app/src/main/java/io/highfidelity/hifiinterface/SplashActivity.java
index e0aa967aaa..bb42467ace 100644
--- a/android/app/src/main/java/io/highfidelity/hifiinterface/SplashActivity.java
+++ b/android/app/src/main/java/io/highfidelity/hifiinterface/SplashActivity.java
@@ -3,7 +3,6 @@ package io.highfidelity.hifiinterface;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
-import android.os.Handler;
import android.view.View;
public class SplashActivity extends Activity {
@@ -37,7 +36,13 @@ public class SplashActivity extends Activity {
}
public void onAppLoadedComplete() {
- startActivity(new Intent(this, MainActivity.class));
+ if (HifiUtils.getInstance().isUserLoggedIn()) {
+ startActivity(new Intent(this, MainActivity.class));
+ } else {
+ Intent menuIntent = new Intent(this, LoginMenuActivity.class);
+ menuIntent.putExtra(LoginMenuActivity.EXTRA_FINISH_ON_BACK, true);
+ startActivity(menuIntent);
+ }
SplashActivity.this.finish();
}
}
diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/WebViewActivity.java b/android/app/src/main/java/io/highfidelity/hifiinterface/WebViewActivity.java
index 5d65bcad51..e906c4b734 100644
--- a/android/app/src/main/java/io/highfidelity/hifiinterface/WebViewActivity.java
+++ b/android/app/src/main/java/io/highfidelity/hifiinterface/WebViewActivity.java
@@ -28,11 +28,18 @@ import java.net.MalformedURLException;
import java.net.URL;
import io.highfidelity.hifiinterface.fragment.WebViewFragment;
+import io.highfidelity.hifiinterface.fragment.WebViewFragment.OnWebViewInteractionListener;
-public class WebViewActivity extends Activity implements WebViewFragment.OnWebViewInteractionListener {
+public class WebViewActivity extends Activity implements OnWebViewInteractionListener {
public static final String WEB_VIEW_ACTIVITY_EXTRA_URL = "url";
+ public static final String WEB_VIEW_ACTIVITY_EXTRA_CLEAR_COOKIES = "clear_cookies";
+ public static final String RESULT_OAUTH_CODE = "code";
+ public static final String RESULT_OAUTH_STATE = "state";
+
private static final String FRAGMENT_TAG = "WebViewActivity_WebFragment";
+ private static final String OAUTH_CODE = "code";
+ private static final String OAUTH_STATE = "state";
private native void nativeProcessURL(String url);
@@ -47,14 +54,15 @@ public class WebViewActivity extends Activity implements WebViewFragment.OnWebVi
mActionBar = getActionBar();
mActionBar.setDisplayHomeAsUpEnabled(true);
- loadWebViewFragment(getIntent().getStringExtra(WEB_VIEW_ACTIVITY_EXTRA_URL));
+ loadWebViewFragment(getIntent().getStringExtra(WEB_VIEW_ACTIVITY_EXTRA_URL), getIntent().getBooleanExtra(WEB_VIEW_ACTIVITY_EXTRA_CLEAR_COOKIES, false));
}
- private void loadWebViewFragment(String url) {
+ private void loadWebViewFragment(String url, boolean clearCookies) {
WebViewFragment fragment = WebViewFragment.newInstance();
Bundle bundle = new Bundle();
bundle.putString(WebViewFragment.URL, url);
bundle.putBoolean(WebViewFragment.TOOLBAR_VISIBLE, false);
+ bundle.putBoolean(WebViewFragment.CLEAR_COOKIES, clearCookies);
fragment.setArguments(bundle);
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction ft = fragmentManager.beginTransaction();
@@ -131,4 +139,13 @@ public class WebViewActivity extends Activity implements WebViewFragment.OnWebVi
@Override
public void onExpand() { }
+ @Override
+ public void onOAuthAuthorizeCallback(Uri uri) {
+ Intent result = new Intent();
+ result.putExtra(RESULT_OAUTH_CODE, uri.getQueryParameter(OAUTH_CODE));
+ result.putExtra(RESULT_OAUTH_STATE, uri.getQueryParameter(OAUTH_STATE));
+ setResult(Activity.RESULT_OK, result);
+ finish();
+ }
+
}
diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/FriendsFragment.java b/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/FriendsFragment.java
index 2475c4d887..e19a9c5a7a 100644
--- a/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/FriendsFragment.java
+++ b/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/FriendsFragment.java
@@ -23,8 +23,6 @@ import io.highfidelity.hifiinterface.view.UserListAdapter;
public class FriendsFragment extends Fragment {
- public native boolean nativeIsLoggedIn();
-
public native String nativeGetAccessToken();
private RecyclerView mUsersView;
diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/LoginFragment.java b/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/LoginFragment.java
index f22e5cd6bb..28406d5986 100644
--- a/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/LoginFragment.java
+++ b/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/LoginFragment.java
@@ -2,41 +2,65 @@ package io.highfidelity.hifiinterface.fragment;
import android.app.Activity;
import android.app.Fragment;
-import android.app.ProgressDialog;
import android.content.Context;
-import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.util.Log;
+import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
+import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.TextView;
import org.qtproject.qt5.android.QtNative;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.util.Random;
+
+import io.highfidelity.hifiinterface.BuildConfig;
+import io.highfidelity.hifiinterface.HifiUtils;
import io.highfidelity.hifiinterface.R;
+import io.highfidelity.hifiinterface.WebViewActivity;
import static org.qtproject.qt5.android.QtActivityDelegate.ApplicationActive;
import static org.qtproject.qt5.android.QtActivityDelegate.ApplicationInactive;
-public class LoginFragment extends Fragment {
+public class LoginFragment extends Fragment
+ implements OnBackPressedListener {
+
+ private static final String ARG_USE_OAUTH = "use_oauth";
+ private static final String TAG = "Interface";
+
+ private final String OAUTH_CLIENT_ID = BuildConfig.OAUTH_CLIENT_ID;
+ private final String OAUTH_REDIRECT_URI = BuildConfig.OAUTH_REDIRECT_URI;
+ private final String OAUTH_AUTHORIZE_BASE_URL = "https://highfidelity.com/oauth/authorize";
+ private static final int OAUTH_AUTHORIZE_REQUEST = 1;
private EditText mUsername;
private EditText mPassword;
private TextView mError;
- private TextView mForgotPassword;
- private TextView mSignup;
private Button mLoginButton;
+ private CheckBox mKeepMeLoggedInCheckbox;
+ private ViewGroup mLoginForm;
+ private ViewGroup mLoggingInFrame;
+ private ViewGroup mLoggedInFrame;
+ private boolean mLoginInProgress;
+ private boolean mLoginSuccess;
+ private boolean mUseOauth;
+ private String mOauthState;
- private ProgressDialog mDialog;
+ public native void login(String username, String password, boolean keepLoggedIn);
+ private native void retrieveAccessToken(String authCode, String clientId, String clientSecret, String redirectUri);
- public native void nativeLogin(String username, String password, Activity usernameChangedListener);
- public native void nativeCancelLogin();
+ public native void cancelLogin();
private LoginFragment.OnLoginInteractionListener mListener;
@@ -44,11 +68,22 @@ public class LoginFragment extends Fragment {
// Required empty public constructor
}
- public static LoginFragment newInstance() {
+ public static LoginFragment newInstance(boolean useOauth) {
LoginFragment fragment = new LoginFragment();
+ Bundle args = new Bundle();
+ args.putBoolean(ARG_USE_OAUTH, useOauth);
+ fragment.setArguments(args);
return fragment;
}
+ @Override
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ if (getArguments() != null) {
+ mUseOauth = getArguments().getBoolean(ARG_USE_OAUTH, false);
+ }
+ }
+
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
@@ -58,22 +93,29 @@ public class LoginFragment extends Fragment {
mPassword = rootView.findViewById(R.id.password);
mError = rootView.findViewById(R.id.error);
mLoginButton = rootView.findViewById(R.id.loginButton);
- mForgotPassword = rootView.findViewById(R.id.forgotPassword);
- mSignup = rootView.findViewById(R.id.signupButton);
+ mLoginForm = rootView.findViewById(R.id.loginForm);
+ mLoggingInFrame = rootView.findViewById(R.id.loggingInFrame);
+ mLoggedInFrame = rootView.findViewById(R.id.loggedInFrame);
+ mKeepMeLoggedInCheckbox = rootView.findViewById(R.id.keepMeLoggedIn);
- mLoginButton.setOnClickListener(view -> login());
+ rootView.findViewById(R.id.forgotPassword).setOnClickListener(view -> onForgotPasswordClicked());
- mForgotPassword.setOnClickListener(view -> forgotPassword());
- mSignup.setOnClickListener(view -> signup());
+ rootView.findViewById(R.id.cancel).setOnClickListener(view -> onCancelLogin());
- mPassword.setOnEditorActionListener(
- (textView, actionId, keyEvent) -> {
- if (actionId == EditorInfo.IME_ACTION_DONE) {
- mLoginButton.performClick();
- return true;
- }
- return false;
- });
+ rootView.findViewById(R.id.getStarted).setOnClickListener(view -> onGetStartedClicked());
+
+ mLoginButton.setOnClickListener(view -> onLoginButtonClicked());
+
+ rootView.findViewById(R.id.takeMeInWorld).setOnClickListener(view -> skipLogin());
+ mPassword.setOnEditorActionListener((textView, actionId, keyEvent) -> onPasswordEditorAction(textView, actionId, keyEvent));
+
+ mKeepMeLoggedInCheckbox.setChecked(HifiUtils.getInstance().isKeepingLoggedIn());
+
+ if (mUseOauth) {
+ openWebForAuthorization();
+ } else {
+ showLoginForm();
+ }
return rootView;
}
@@ -104,13 +146,57 @@ public class LoginFragment extends Fragment {
@Override
public void onStop() {
super.onStop();
- cancelActivityIndicator();
// Leave the Qt app paused
QtNative.setApplicationState(ApplicationInactive);
hideKeyboard();
}
- public void login() {
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode == OAUTH_AUTHORIZE_REQUEST) {
+ if (resultCode == Activity.RESULT_OK) {
+ String authCode = data.getStringExtra(WebViewActivity.RESULT_OAUTH_CODE);
+ String state = data.getStringExtra(WebViewActivity.RESULT_OAUTH_STATE);
+ if (state != null && state.equals(mOauthState) && mListener != null) {
+ mOauthState = null;
+ showActivityIndicator();
+ mLoginInProgress = true;
+ retrieveAccessToken(authCode, BuildConfig.OAUTH_CLIENT_ID, BuildConfig.OAUTH_CLIENT_SECRET, BuildConfig.OAUTH_REDIRECT_URI);
+ }
+ } else {
+ onCancelLogin();
+ }
+ }
+
+ }
+
+ private void onCancelLogin() {
+ if (mListener != null) {
+ mListener.onCancelLogin();
+ }
+ }
+
+ private boolean onPasswordEditorAction(TextView textView, int actionId, KeyEvent keyEvent) {
+ if (actionId == EditorInfo.IME_ACTION_DONE) {
+ mLoginButton.performClick();
+ return true;
+ }
+ return false;
+ }
+
+ private void skipLogin() {
+ if (mListener != null) {
+ mListener.onSkipLoginClicked();
+ }
+ }
+
+ private void onGetStartedClicked() {
+ if (mListener != null) {
+ mListener.onLoginCompleted();
+ }
+ }
+
+ public void onLoginButtonClicked() {
String username = mUsername.getText().toString().trim();
String password = mPassword.getText().toString();
hideKeyboard();
@@ -120,13 +206,10 @@ public class LoginFragment extends Fragment {
mLoginButton.setEnabled(false);
hideError();
showActivityIndicator();
- nativeLogin(username, password, getActivity());
- }
- }
-
- public void signup() {
- if (mListener != null) {
- mListener.onSignupRequested();
+ mLoginInProgress = true;
+ mLoginSuccess = false;
+ boolean keepUserLoggedIn = mKeepMeLoggedInCheckbox.isChecked();
+ login(username, password, keepUserLoggedIn);
}
}
@@ -138,33 +221,32 @@ public class LoginFragment extends Fragment {
}
}
- private void forgotPassword() {
+ private void onForgotPasswordClicked() {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://highfidelity.com/users/password/new"));
startActivity(intent);
}
private void showActivityIndicator() {
- if (mDialog == null) {
- mDialog = new ProgressDialog(getContext());
- }
- mDialog.setMessage(getString(R.string.logging_in));
- mDialog.setCancelable(true);
- mDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
- @Override
- public void onCancel(DialogInterface dialogInterface) {
- nativeCancelLogin();
- cancelActivityIndicator();
- mLoginButton.setEnabled(true);
- }
- });
- mDialog.show();
+ mLoginForm.setVisibility(View.GONE);
+ mLoggedInFrame.setVisibility(View.GONE);
+ mLoggingInFrame.setVisibility(View.VISIBLE);
+ mLoggingInFrame.bringToFront();
}
- private void cancelActivityIndicator() {
- if (mDialog != null) {
- mDialog.cancel();
- }
+ private void showLoginForm() {
+ mLoggingInFrame.setVisibility(View.GONE);
+ mLoggedInFrame.setVisibility(View.GONE);
+ mLoginForm.setVisibility(View.VISIBLE);
+ mLoginForm.bringToFront();
}
+
+ private void showLoggedInMessage() {
+ mLoginForm.setVisibility(View.GONE);
+ mLoggingInFrame.setVisibility(View.GONE);
+ mLoggedInFrame.setVisibility(View.VISIBLE);
+ mLoggedInFrame.bringToFront();
+ }
+
private void showError(String error) {
mError.setText(error);
mError.setVisibility(View.VISIBLE);
@@ -176,22 +258,71 @@ public class LoginFragment extends Fragment {
}
public void handleLoginCompleted(boolean success) {
+ mLoginInProgress = false;
getActivity().runOnUiThread(() -> {
mLoginButton.setEnabled(true);
- cancelActivityIndicator();
if (success) {
- if (mListener != null) {
- mListener.onLoginCompleted();
- }
+ mLoginSuccess = true;
+ showLoggedInMessage();
} else {
- showError(getString(R.string.login_username_or_password_incorrect));
+ if (!mUseOauth) {
+ showLoginForm();
+ showError(getString(R.string.login_username_or_password_incorrect));
+ } else {
+ openWebForAuthorization();
+ }
}
});
}
+ @Override
+ public boolean doBack() {
+ if (mLoginInProgress) {
+ cancelLogin();
+ showLoginForm();
+ mLoginInProgress = false;
+ mLoginButton.setEnabled(true);
+ return true;
+ } else if (mLoginSuccess) {
+ onGetStartedClicked();
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ private void updateOauthState() {
+ // as we only use oauth for steam that's ok for now
+ mOauthState = "steam-" + Long.toString(new Random().nextLong());
+ }
+
+ private String buildAuthorizeUrl() {
+ StringBuilder sb = new StringBuilder(OAUTH_AUTHORIZE_BASE_URL);
+ sb.append("?client_id=").append(OAUTH_CLIENT_ID);
+ try {
+ String redirectUri = URLEncoder.encode(OAUTH_REDIRECT_URI, "utf-8");
+ sb.append("&redirect_uri=").append(redirectUri);
+ } catch (UnsupportedEncodingException e) {
+ Log.e(TAG, "Cannot build oauth autorization url", e);
+ }
+ sb.append("&response_type=code&scope=owner");
+ sb.append("&state=").append(mOauthState);
+ return sb.toString();
+ }
+
+ private void openWebForAuthorization() {
+ Intent openUrlIntent = new Intent(getActivity(), WebViewActivity.class);
+ updateOauthState();
+ openUrlIntent.putExtra(WebViewActivity.WEB_VIEW_ACTIVITY_EXTRA_URL, buildAuthorizeUrl());
+ openUrlIntent.putExtra(WebViewActivity.WEB_VIEW_ACTIVITY_EXTRA_CLEAR_COOKIES, true);
+ startActivityForResult(openUrlIntent, OAUTH_AUTHORIZE_REQUEST);
+ }
+
+
public interface OnLoginInteractionListener {
void onLoginCompleted();
- void onSignupRequested();
+ void onCancelLogin();
+ void onSkipLoginClicked();
}
}
diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/OnBackPressedListener.java b/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/OnBackPressedListener.java
new file mode 100644
index 0000000000..c160138cea
--- /dev/null
+++ b/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/OnBackPressedListener.java
@@ -0,0 +1,11 @@
+package io.highfidelity.hifiinterface.fragment;
+
+public interface OnBackPressedListener {
+
+ /**
+ * Processes the back pressed event and returns true if it was managed by this Fragment
+ * @return
+ */
+ boolean doBack();
+
+}
diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/SettingsFragment.java b/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/SettingsFragment.java
index cc23665e72..e32dc3b996 100644
--- a/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/SettingsFragment.java
+++ b/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/SettingsFragment.java
@@ -3,32 +3,35 @@ package io.highfidelity.hifiinterface.fragment;
import android.content.SharedPreferences;
import android.media.audiofx.AcousticEchoCanceler;
import android.os.Bundle;
-import android.preference.Preference;
import android.preference.PreferenceFragment;
+import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
+import io.highfidelity.hifiinterface.HifiUtils;
import io.highfidelity.hifiinterface.R;
public class SettingsFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener {
- public native void updateHifiSetting(String group, String key, boolean value);
- public native boolean getHifiSettingBoolean(String group, String key, boolean defaultValue);
-
private final String HIFI_SETTINGS_ANDROID_GROUP = "Android";
private final String HIFI_SETTINGS_AEC_KEY = "aec";
private final String PREFERENCE_KEY_AEC = "aec";
+ private final boolean DEFAULT_AEC_ENABLED = true;
+
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.settings);
+ boolean aecAvailable = AcousticEchoCanceler.isAvailable();
+ PreferenceManager.setDefaultValues(getContext(), R.xml.settings, false);
- if (!AcousticEchoCanceler.isAvailable()) {
- getPreferenceScreen().getPreferenceManager().findPreference("aec").setEnabled(false);
+ if (!aecAvailable) {
+ findPreference(PREFERENCE_KEY_AEC).setEnabled(false);
+ HifiUtils.getInstance().updateHifiSetting(HIFI_SETTINGS_ANDROID_GROUP, HIFI_SETTINGS_AEC_KEY, false);
}
getPreferenceScreen().getSharedPreferences().edit().putBoolean(PREFERENCE_KEY_AEC,
- getHifiSettingBoolean(HIFI_SETTINGS_ANDROID_GROUP, HIFI_SETTINGS_AEC_KEY, false));
+ aecAvailable && HifiUtils.getInstance().getHifiSettingBoolean(HIFI_SETTINGS_ANDROID_GROUP, HIFI_SETTINGS_AEC_KEY, DEFAULT_AEC_ENABLED)).commit();
}
public static SettingsFragment newInstance() {
@@ -46,15 +49,13 @@ public class SettingsFragment extends PreferenceFragment implements SharedPrefer
public void onPause() {
super.onPause();
getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
-
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
- Preference pref = findPreference(key);
switch (key) {
case "aec":
- updateHifiSetting(HIFI_SETTINGS_ANDROID_GROUP, HIFI_SETTINGS_AEC_KEY, sharedPreferences.getBoolean(key, false));
+ HifiUtils.getInstance().updateHifiSetting(HIFI_SETTINGS_ANDROID_GROUP, HIFI_SETTINGS_AEC_KEY, sharedPreferences.getBoolean(key, false));
break;
default:
break;
diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/SignedInFragment.java b/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/SignedInFragment.java
deleted file mode 100644
index 9ed2f1c7f5..0000000000
--- a/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/SignedInFragment.java
+++ /dev/null
@@ -1,73 +0,0 @@
-package io.highfidelity.hifiinterface.fragment;
-
-import android.app.Fragment;
-import android.content.Context;
-import android.os.Bundle;
-import android.text.Html;
-import android.text.Spanned;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.Button;
-import android.widget.TextView;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-import io.highfidelity.hifiinterface.R;
-
-public class SignedInFragment extends Fragment {
-
- private Button mGetStartedButton;
- private OnSignedInInteractionListener mListener;
-
- public SignedInFragment() {
- // Required empty public constructor
- }
-
- public static SignedInFragment newInstance() {
- SignedInFragment fragment = new SignedInFragment();
- return fragment;
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- View rootView = inflater.inflate(R.layout.fragment_signedin, container, false);
- mGetStartedButton = rootView.findViewById(R.id.getStarted);
-
- mGetStartedButton.setOnClickListener(view -> {
- getStarted();
- });
-
- return rootView;
- }
-
- @Override
- public void onAttach(Context context) {
- super.onAttach(context);
- if (context instanceof SignedInFragment.OnSignedInInteractionListener) {
- mListener = (SignedInFragment.OnSignedInInteractionListener) context;
- } else {
- throw new RuntimeException(context.toString()
- + " must implement OnSignedInInteractionListener");
- }
- }
-
- @Override
- public void onDetach() {
- super.onDetach();
- mListener = null;
- }
-
- public void getStarted() {
- if (mListener != null) {
- mListener.onGettingStarted();
- }
- }
-
- public interface OnSignedInInteractionListener {
- void onGettingStarted();
- }
-
-}
diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/SignupFragment.java b/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/SignupFragment.java
index 33644e5bda..a11ae31fa1 100644
--- a/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/SignupFragment.java
+++ b/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/SignupFragment.java
@@ -1,42 +1,50 @@
package io.highfidelity.hifiinterface.fragment;
-import android.app.Activity;
import android.app.Fragment;
-import android.app.ProgressDialog;
import android.content.Context;
import android.os.Bundle;
+import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
+import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.TextView;
import org.qtproject.qt5.android.QtNative;
+import io.highfidelity.hifiinterface.HifiUtils;
import io.highfidelity.hifiinterface.R;
import static org.qtproject.qt5.android.QtActivityDelegate.ApplicationActive;
import static org.qtproject.qt5.android.QtActivityDelegate.ApplicationInactive;
-public class SignupFragment extends Fragment {
+public class SignupFragment extends Fragment
+ implements OnBackPressedListener {
private EditText mEmail;
private EditText mUsername;
private EditText mPassword;
private TextView mError;
- private TextView mCancelButton;
-
+ private TextView mActivityText;
private Button mSignupButton;
+ private CheckBox mKeepMeLoggedInCheckbox;
- private ProgressDialog mDialog;
+ private ViewGroup mSignupForm;
+ private ViewGroup mLoggingInFrame;
+ private ViewGroup mLoggedInFrame;
- public native void nativeSignup(String email, String username, String password); // move to SignupFragment
- public native void nativeCancelSignup();
- public native void nativeLogin(String username, String password, Activity usernameChangedListener);
- public native void nativeCancelLogin();
+ private boolean mLoginInProgress;
+ private boolean mSignupInProgress;
+ private boolean mSignupSuccess;
+
+ public native void signup(String email, String username, String password); // move to SignupFragment
+ public native void cancelSignup();
+ public native void login(String username, String password, boolean keepLoggedIn);
+ public native void cancelLogin();
private SignupFragment.OnSignupInteractionListener mListener;
@@ -59,18 +67,23 @@ public class SignupFragment extends Fragment {
mPassword = rootView.findViewById(R.id.password);
mError = rootView.findViewById(R.id.error);
mSignupButton = rootView.findViewById(R.id.signupButton);
- mCancelButton = rootView.findViewById(R.id.cancelButton);
+ mActivityText = rootView.findViewById(R.id.activityText);
+ mKeepMeLoggedInCheckbox = rootView.findViewById(R.id.keepMeLoggedIn);
+
+ mSignupForm = rootView.findViewById(R.id.signupForm);
+ mLoggedInFrame = rootView.findViewById(R.id.loggedInFrame);
+ mLoggingInFrame = rootView.findViewById(R.id.loggingInFrame);
+
+ rootView.findViewById(R.id.cancel).setOnClickListener(view -> onCancelSignup());
mSignupButton.setOnClickListener(view -> signup());
- mCancelButton.setOnClickListener(view -> login());
- mPassword.setOnEditorActionListener(
- (textView, actionId, keyEvent) -> {
- if (actionId == EditorInfo.IME_ACTION_DONE) {
- mSignupButton.performClick();
- return true;
- }
- return false;
- });
+
+ rootView.findViewById(R.id.getStarted).setOnClickListener(view -> onGetStartedClicked());
+
+ mPassword.setOnEditorActionListener((textView, actionId, keyEvent) -> onPasswordEditorAction(textView, actionId, keyEvent));
+
+ mKeepMeLoggedInCheckbox.setChecked(HifiUtils.getInstance().isKeepingLoggedIn());
+
return rootView;
}
@@ -101,15 +114,22 @@ public class SignupFragment extends Fragment {
@Override
public void onStop() {
super.onStop();
- cancelActivityIndicator();
// Leave the Qt app paused
QtNative.setApplicationState(ApplicationInactive);
hideKeyboard();
}
- private void login() {
+ private boolean onPasswordEditorAction(TextView textView, int actionId, KeyEvent keyEvent) {
+ if (actionId == EditorInfo.IME_ACTION_DONE) {
+ mSignupButton.performClick();
+ return true;
+ }
+ return false;
+ }
+
+ private void onCancelSignup() {
if (mListener != null) {
- mListener.onLoginRequested();
+ mListener.onCancelSignup();
}
}
@@ -123,8 +143,11 @@ public class SignupFragment extends Fragment {
} else {
mSignupButton.setEnabled(false);
hideError();
+ mActivityText.setText(R.string.creating_account);
showActivityIndicator();
- nativeSignup(email, username, password);
+ mSignupInProgress = true;
+ mSignupSuccess = false;
+ signup(email, username, password);
}
}
@@ -137,23 +160,21 @@ public class SignupFragment extends Fragment {
}
private void showActivityIndicator() {
- if (mDialog == null) {
- mDialog = new ProgressDialog(getContext());
- }
- mDialog.setMessage(getString(R.string.creating_account));
- mDialog.setCancelable(true);
- mDialog.setOnCancelListener(dialogInterface -> {
- nativeCancelSignup();
- cancelActivityIndicator();
- mSignupButton.setEnabled(true);
- });
- mDialog.show();
+ mSignupForm.setVisibility(View.GONE);
+ mLoggedInFrame.setVisibility(View.GONE);
+ mLoggingInFrame.setVisibility(View.VISIBLE);
}
- private void cancelActivityIndicator() {
- if (mDialog != null) {
- mDialog.cancel();
- }
+ private void showLoggedInMessage() {
+ mSignupForm.setVisibility(View.GONE);
+ mLoggingInFrame.setVisibility(View.GONE);
+ mLoggedInFrame.setVisibility(View.VISIBLE);
+ }
+
+ private void showSignupForm() {
+ mLoggingInFrame.setVisibility(View.GONE);
+ mLoggedInFrame.setVisibility(View.GONE);
+ mSignupForm.setVisibility(View.VISIBLE);
}
private void showError(String error) {
mError.setText(error);
@@ -167,51 +188,73 @@ public class SignupFragment extends Fragment {
public interface OnSignupInteractionListener {
void onSignupCompleted();
- void onLoginRequested();
+ void onCancelSignup();
}
+ private void onGetStartedClicked() {
+ if (mListener != null) {
+ mListener.onSignupCompleted();
+ }
+ }
+
+
public void handleSignupCompleted() {
+ mSignupInProgress = false;
String username = mUsername.getText().toString().trim();
String password = mPassword.getText().toString();
- mDialog.setMessage(getString(R.string.logging_in));
- mDialog.setCancelable(true);
- mDialog.setOnCancelListener(dialogInterface -> {
- nativeCancelLogin();
- cancelActivityIndicator();
- if (mListener != null) {
- mListener.onLoginRequested();
- }
+ getActivity().runOnUiThread(() -> {
+ mActivityText.setText(R.string.logging_in);
});
- mDialog.show();
- nativeLogin(username, password, getActivity());
+ mLoginInProgress = true;
+ boolean keepUserLoggedIn = mKeepMeLoggedInCheckbox.isChecked();
+ login(username, password, keepUserLoggedIn);
}
public void handleSignupFailed(String error) {
+ mSignupInProgress = false;
getActivity().runOnUiThread(() -> {
mSignupButton.setEnabled(true);
- cancelActivityIndicator();
+ showSignupForm();
mError.setText(error);
mError.setVisibility(View.VISIBLE);
});
}
public void handleLoginCompleted(boolean success) {
+ mLoginInProgress = false;
getActivity().runOnUiThread(() -> {
mSignupButton.setEnabled(true);
- cancelActivityIndicator();
-
if (success) {
- if (mListener != null) {
- mListener.onSignupCompleted();
- }
+ mSignupSuccess = true;
+ showLoggedInMessage();
} else {
// Registration was successful but login failed.
// Let the user to login manually
- mListener.onLoginRequested();
+ mListener.onCancelSignup();
+ showSignupForm();
}
});
}
+ @Override
+ public boolean doBack() {
+ if (mSignupInProgress) {
+ cancelSignup();
+ } else if (mLoginInProgress) {
+ cancelLogin();
+ }
-
+ if (mSignupInProgress || mLoginInProgress) {
+ showSignupForm();
+ mLoginInProgress = false;
+ mSignupInProgress = false;
+ mSignupButton.setEnabled(true);
+ return true;
+ } else if (mSignupSuccess) {
+ onGetStartedClicked();
+ return true;
+ } else {
+ return false;
+ }
+ }
}
diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/StartMenuFragment.java b/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/StartMenuFragment.java
new file mode 100644
index 0000000000..fe77991962
--- /dev/null
+++ b/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/StartMenuFragment.java
@@ -0,0 +1,93 @@
+package io.highfidelity.hifiinterface.fragment;
+
+import android.app.Fragment;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import io.highfidelity.hifiinterface.R;
+
+public class StartMenuFragment extends Fragment {
+
+ private String TAG = "HighFidelity";
+ private StartMenuInteractionListener mListener;
+
+ public StartMenuFragment() {
+ // Required empty public constructor
+ }
+
+ public static StartMenuFragment newInstance() {
+ StartMenuFragment fragment = new StartMenuFragment();
+ return fragment;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ // Inflate the layout for this fragment
+ View rootView = inflater.inflate(R.layout.fragment_login_menu, container, false);
+ rootView.findViewById(R.id.signupButton).setOnClickListener(view -> {
+ if (mListener != null) {
+ mListener.onSignupButtonClicked();
+ }
+ });
+
+ rootView.findViewById(R.id.loginButton).setOnClickListener(view -> {
+ if (mListener != null) {
+ mListener.onLoginButtonClicked();
+ }
+ });
+
+ rootView.findViewById(R.id.steamLoginButton).setOnClickListener(view -> {
+ if (mListener != null) {
+ mListener.onSteamLoginButtonClicked();
+ }
+ });
+
+ rootView.findViewById(R.id.takeMeInWorld).setOnClickListener(view -> {
+ if (mListener != null) {
+ mListener.onSkipLoginClicked();
+ }
+ });
+
+
+
+ return rootView;
+ }
+
+ @Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ if (context instanceof StartMenuInteractionListener) {
+ mListener = (StartMenuInteractionListener) context;
+ } else {
+ throw new RuntimeException(context.toString()
+ + " must implement StartMenuInteractionListener");
+ }
+ }
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ mListener = null;
+ }
+
+ /**
+ * This interface must be implemented by activities that contain this
+ * fragment to allow an interaction in this fragment to be communicated
+ * to the activity and potentially other fragments contained in that
+ * activity.
+ *
+ * See the Android Training lesson Communicating with Other Fragments for more information.
+ */
+ public interface StartMenuInteractionListener {
+ void onSignupButtonClicked();
+ void onLoginButtonClicked();
+ void onSkipLoginClicked();
+ void onSteamLoginButtonClicked();
+ }
+}
diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/WebViewFragment.java b/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/WebViewFragment.java
index 2d887d5a19..3614fe47e4 100644
--- a/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/WebViewFragment.java
+++ b/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/WebViewFragment.java
@@ -4,9 +4,11 @@ import android.app.Fragment;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
+import android.net.Uri;
import android.net.http.SslError;
import android.os.Bundle;
import android.os.Handler;
+import android.text.TextUtils;
import android.view.GestureDetector;
import android.view.KeyEvent;
import android.view.LayoutInflater;
@@ -14,6 +16,7 @@ import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AlphaAnimation;
+import android.webkit.CookieManager;
import android.webkit.SslErrorHandler;
import android.webkit.WebChromeClient;
import android.webkit.WebResourceError;
@@ -25,6 +28,7 @@ import android.webkit.WebViewClient;
import android.widget.ProgressBar;
import android.widget.Toast;
+import io.highfidelity.hifiinterface.BuildConfig;
import io.highfidelity.hifiinterface.R;
import io.highfidelity.hifiinterface.WebViewActivity;
@@ -32,6 +36,7 @@ public class WebViewFragment extends Fragment implements GestureDetector.OnGestu
public static final String URL = "url";
public static final String TOOLBAR_VISIBLE = "toolbar_visible";
+ public static final String CLEAR_COOKIES = "clear_cookies";
private static final long DELAY_HIDE_TOOLBAR_MILLIS = 3000;
private static final long FADE_OUT_DURATION = 2000;
@@ -41,6 +46,7 @@ public class WebViewFragment extends Fragment implements GestureDetector.OnGestu
private ProgressBar mProgressBar;
private String mUrl;
private boolean mToolbarVisible;
+ private boolean mClearCookies;
private OnWebViewInteractionListener mListener;
private Runnable mCloseAction;
@@ -170,6 +176,7 @@ public class WebViewFragment extends Fragment implements GestureDetector.OnGestu
if (getArguments() != null) {
mUrl = getArguments().getString(URL);
mToolbarVisible = getArguments().getBoolean(TOOLBAR_VISIBLE);
+ mClearCookies = getArguments().getBoolean(CLEAR_COOKIES);
}
}
@@ -179,6 +186,10 @@ public class WebViewFragment extends Fragment implements GestureDetector.OnGestu
View rootView = inflater.inflate(R.layout.fragment_web_view, container, false);
mProgressBar = rootView.findViewById(R.id.toolbarProgressBar);
myWebView = rootView.findViewById(R.id.web_view);
+ if (mClearCookies) {
+ CookieManager.getInstance().removeAllCookies(null);
+ }
+
mHandler = new Handler();
gestureDetector = new GestureDetector(this);
gestureDetector.setOnDoubleTapListener(new GestureDetector.OnDoubleTapListener() {
@@ -251,6 +262,7 @@ public class WebViewFragment extends Fragment implements GestureDetector.OnGestu
void onWebLoaded(String url, SafenessLevel safenessLevel);
void onTitleReceived(String title);
void onExpand();
+ void onOAuthAuthorizeCallback(Uri uri);
}
@@ -320,6 +332,18 @@ public class WebViewFragment extends Fragment implements GestureDetector.OnGestu
super.onLoadResource(view, url);
}
}
+
+ @Override
+ public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
+ if (!TextUtils.isEmpty(BuildConfig.OAUTH_REDIRECT_URI) &&
+ request.getUrl().toString().startsWith(BuildConfig.OAUTH_REDIRECT_URI)) {
+ if (mListener != null) {
+ mListener.onOAuthAuthorizeCallback(request.getUrl());
+ }
+ return true;
+ }
+ return super.shouldOverrideUrlLoading(view, request);
+ }
}
class HiFiWebChromeClient extends WebChromeClient {
diff --git a/android/app/src/main/res/drawable/encourage_login_background.jpg b/android/app/src/main/res/drawable/encourage_login_background.jpg
new file mode 100644
index 0000000000..5382880c3e
Binary files /dev/null and b/android/app/src/main/res/drawable/encourage_login_background.jpg differ
diff --git a/android/app/src/main/res/drawable/hifi_header.xml b/android/app/src/main/res/drawable/hifi_header.xml
index 9f7c85297a..7762fea81e 100644
--- a/android/app/src/main/res/drawable/hifi_header.xml
+++ b/android/app/src/main/res/drawable/hifi_header.xml
@@ -1,6 +1,6 @@
diff --git a/android/app/src/main/res/drawable/ic_right_arrow.xml b/android/app/src/main/res/drawable/ic_right_arrow.xml
new file mode 100644
index 0000000000..e35d1a2733
--- /dev/null
+++ b/android/app/src/main/res/drawable/ic_right_arrow.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/drawable/ic_steam.xml b/android/app/src/main/res/drawable/ic_steam.xml
new file mode 100644
index 0000000000..9b739c1f73
--- /dev/null
+++ b/android/app/src/main/res/drawable/ic_steam.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/drawable/rounded_button.xml b/android/app/src/main/res/drawable/rounded_button_color1.xml
similarity index 100%
rename from android/app/src/main/res/drawable/rounded_button.xml
rename to android/app/src/main/res/drawable/rounded_button_color1.xml
diff --git a/android/app/src/main/res/drawable/rounded_button_color3.xml b/android/app/src/main/res/drawable/rounded_button_color3.xml
new file mode 100644
index 0000000000..6230885b30
--- /dev/null
+++ b/android/app/src/main/res/drawable/rounded_button_color3.xml
@@ -0,0 +1,24 @@
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/drawable/rounded_button_color4.xml b/android/app/src/main/res/drawable/rounded_button_color4.xml
new file mode 100644
index 0000000000..679bf24513
--- /dev/null
+++ b/android/app/src/main/res/drawable/rounded_button_color4.xml
@@ -0,0 +1,24 @@
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/drawable/rounded_edit.xml b/android/app/src/main/res/drawable/rounded_edit.xml
deleted file mode 100644
index 3c1cac4d1d..0000000000
--- a/android/app/src/main/res/drawable/rounded_edit.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/activity_encourage_login.xml b/android/app/src/main/res/layout/activity_encourage_login.xml
new file mode 100644
index 0000000000..d7c9ff6b4d
--- /dev/null
+++ b/android/app/src/main/res/layout/activity_encourage_login.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/fragment_login.xml b/android/app/src/main/res/layout/fragment_login.xml
index 6933ad1eb5..d12b84cc8d 100644
--- a/android/app/src/main/res/layout/fragment_login.xml
+++ b/android/app/src/main/res/layout/fragment_login.xml
@@ -6,6 +6,17 @@
android:layout_height="match_parent"
android:background="@color/backgroundLight">
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ android:layout_height="0dp"
+ android:layout_marginTop="@dimen/login_form_margin_top"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintRight_toRightOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/header"
+ app:layout_constraintBottom_toBottomOf="parent"
+ android:visibility="gone">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/app/src/main/res/layout/fragment_login_menu.xml b/android/app/src/main/res/layout/fragment_login_menu.xml
new file mode 100644
index 0000000000..edfa4dd9fd
--- /dev/null
+++ b/android/app/src/main/res/layout/fragment_login_menu.xml
@@ -0,0 +1,122 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/fragment_signedin.xml b/android/app/src/main/res/layout/fragment_signedin.xml
deleted file mode 100644
index 1c982b0e0d..0000000000
--- a/android/app/src/main/res/layout/fragment_signedin.xml
+++ /dev/null
@@ -1,63 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/android/app/src/main/res/layout/fragment_signup.xml b/android/app/src/main/res/layout/fragment_signup.xml
index 41c4a8cbbe..1540d26434 100644
--- a/android/app/src/main/res/layout/fragment_signup.xml
+++ b/android/app/src/main/res/layout/fragment_signup.xml
@@ -6,6 +6,18 @@
android:layout_height="match_parent"
android:background="@color/backgroundLight">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+ app:layout_constraintTop_toBottomOf="@id/keepMeLoggedIn" />
-
+ android:textColor="@color/white_opaque"
+ android:fontFamily="@font/raleway_bold"
+ android:textSize="@dimen/button_medium_text_size"
+ android:text="@string/cancel_uppercase" />
+
diff --git a/android/app/src/main/res/values-w385dp/dimens.xml b/android/app/src/main/res/values-w385dp/dimens.xml
new file mode 100644
index 0000000000..7463700d2a
--- /dev/null
+++ b/android/app/src/main/res/values-w385dp/dimens.xml
@@ -0,0 +1,22 @@
+
+
+ 35dp
+ 84dp
+ 340dp
+ 171dp
+ 42dp
+ 10dp
+ 14sp
+ 18sp
+ 18sp
+ 72dp
+ 76dp
+ 100dp
+ 27dp
+ 238dp
+ 42dp
+ 270dp
+ 86dp
+ 22sp
+ 16dp
+
\ 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 fad2c98fb8..fc5ce7ba16 100644
--- a/android/app/src/main/res/values/colors.xml
+++ b/android/app/src/main/res/values/colors.xml
@@ -10,6 +10,8 @@
#1EB5EC
#00B4EF
#828282
+ #8F8F8F
+ #434343
#333333
#4F4F4F
#33999999
diff --git a/android/app/src/main/res/values/dimens.xml b/android/app/src/main/res/values/dimens.xml
index d40132939b..85d79509ba 100644
--- a/android/app/src/main/res/values/dimens.xml
+++ b/android/app/src/main/res/values/dimens.xml
@@ -33,10 +33,26 @@
6dp
64dp
- 56dp
- 101dp
- 425dp
+ 32dp
+ 76dp
+ 306dp
8dp
+ 150dp
+ 38dp
+ 65dp
+ 68dp
+ 90dp
+ 9dp
+ 16sp
+ 16sp
+ 13sp
+ 24dp
+ 214dp
+ 38dp
+ 300dp
+ 77dp
+ 20sp
+ 14dp
diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml
index 4be4ccf867..671f171c3e 100644
--- a/android/app/src/main/res/values/strings.xml
+++ b/android/app/src/main/res/values/strings.xml
@@ -16,9 +16,9 @@
Password
Login
Logout
- Forgot password?\u00A0
+ Can\u0027t access your account?
Username or password incorrect.
- Logging into High Fidelity
+ Logging in
Search for a place by name\u00A0
Loading places…
No places exist with that name
@@ -26,16 +26,20 @@
Your Last Location
Online
Sign Up
+ SIGN UP
Creating your High Fidelity account
Email, username or password incorrect.
You are now signed into High Fidelity
+ You are now logged in!
Welcome
Cancel
- Get Started
+ CANCEL
+ GET STARTED
tagFragmentHome
tagFragmentLogin
+ tagFragmentLogginIn
tagFragmentSignup
tagFragmentPolicy
tagFragmentPeople
@@ -45,4 +49,9 @@
AEC
Acoustic Echo Cancellation
Developer
+ LOG IN
+ Keep Me Logged In
+ No thanks, take me in-world!
+ BE ANYWHERE, WITH ANYONE \nRIGHT NOW
+ STEAM LOG IN
diff --git a/android/app/src/main/res/xml/settings.xml b/android/app/src/main/res/xml/settings.xml
index 5ec47b1aff..934d34ba73 100644
--- a/android/app/src/main/res/xml/settings.xml
+++ b/android/app/src/main/res/xml/settings.xml
@@ -6,6 +6,7 @@
+ android:summary="@string/acoustic_echo_cancellation"
+ android:defaultValue="true" />
\ No newline at end of file
diff --git a/assignment-client/CMakeLists.txt b/assignment-client/CMakeLists.txt
index c73e8e1d34..1500d7b98e 100644
--- a/assignment-client/CMakeLists.txt
+++ b/assignment-client/CMakeLists.txt
@@ -11,7 +11,7 @@ setup_memory_debugger()
# link in the shared libraries
link_hifi_libraries(
- audio avatars octree gpu graphics fbx entities
+ audio avatars octree gpu graphics fbx hfm entities
networking animation recording shared script-engine embedded-webserver
controllers physics plugins midi image
)
diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt
index 50247b1145..e6d83e7890 100644
--- a/interface/CMakeLists.txt
+++ b/interface/CMakeLists.txt
@@ -206,7 +206,7 @@ endif()
link_hifi_libraries(
shared workload task octree ktx gpu gl procedural graphics graphics-scripting render
pointers
- recording fbx networking model-networking entities avatars trackers
+ recording hfm fbx networking model-networking entities avatars trackers
audio audio-client animation script-engine physics
render-utils entities-renderer avatars-renderer ui qml auto-updater midi
controllers plugins image trackers
diff --git a/interface/resources/html/raiseAndLowerKeyboard.js b/interface/resources/html/raiseAndLowerKeyboard.js
index f40c0d7376..8cdb3c2327 100644
--- a/interface/resources/html/raiseAndLowerKeyboard.js
+++ b/interface/resources/html/raiseAndLowerKeyboard.js
@@ -18,6 +18,11 @@
window.isKeyboardRaised = false;
window.isNumericKeyboard = false;
window.isPasswordField = false;
+ window.lastActiveElement = null;
+
+ function getActiveElement() {
+ return document.activeElement;
+ }
function shouldSetPasswordField() {
var nodeType = document.activeElement.type;
@@ -65,10 +70,11 @@
var keyboardRaised = shouldRaiseKeyboard();
var numericKeyboard = shouldSetNumeric();
var passwordField = shouldSetPasswordField();
+ var activeElement = getActiveElement();
if (isWindowFocused &&
(keyboardRaised !== window.isKeyboardRaised || numericKeyboard !== window.isNumericKeyboard
- || passwordField !== window.isPasswordField)) {
+ || passwordField !== window.isPasswordField || activeElement !== window.lastActiveElement)) {
if (typeof EventBridge !== "undefined" && EventBridge !== null) {
EventBridge.emitWebEvent(
@@ -90,6 +96,7 @@
window.isKeyboardRaised = keyboardRaised;
window.isNumericKeyboard = numericKeyboard;
window.isPasswordField = passwordField;
+ window.lastActiveElement = activeElement;
}
}, POLL_FREQUENCY);
diff --git a/interface/resources/icons/tablet-icons/inventory-a-msg.svg b/interface/resources/icons/tablet-icons/inventory-a-msg.svg
index 794bd1e414..b028c08b50 100644
--- a/interface/resources/icons/tablet-icons/inventory-a-msg.svg
+++ b/interface/resources/icons/tablet-icons/inventory-a-msg.svg
@@ -1,4 +1,20 @@
-
+
+
+
diff --git a/interface/resources/icons/tablet-icons/inventory-a.svg b/interface/resources/icons/tablet-icons/inventory-a.svg
index 8b6f34eaa3..584ebd3b9b 100644
--- a/interface/resources/icons/tablet-icons/inventory-a.svg
+++ b/interface/resources/icons/tablet-icons/inventory-a.svg
@@ -1,3 +1,16 @@
-