diff --git a/android/app/build.gradle b/android/app/build.gradle index d3463411b8..24c067b176 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -133,6 +133,10 @@ dependencies { implementation 'com.android.support.constraint:constraint-layout:1.0.2' implementation 'com.android.support:design:26.1.0' + compile 'com.android.support:support-v4:26.1.0' + compile 'com.android.support:appcompat-v7:26.1.0' + compile 'com.android.support:support-vector-drawable: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' diff --git a/android/app/src/main/cpp/native.cpp b/android/app/src/main/cpp/native.cpp index 6b44b2dc7a..269fa792d6 100644 --- a/android/app/src/main/cpp/native.cpp +++ b/android/app/src/main/cpp/native.cpp @@ -255,6 +255,16 @@ JNIEXPORT jstring JNICALL Java_io_highfidelity_hifiinterface_fragment_HomeFragme return env->NewStringUTF(lastLocation.toString().toLatin1().data()); } +JNIEXPORT void JNICALL +Java_io_highfidelity_hifiinterface_fragment_LoginFragment_nativeCancelLogin(JNIEnv *env, jobject instance) { + + auto accountManager = DependencyManager::get(); + + QObject::disconnect(accountManager.data(), &AccountManager::loginComplete, nullptr, nullptr); + QObject::disconnect(accountManager.data(), &AccountManager::loginFailed, nullptr, nullptr); + +} + JNIEXPORT void JNICALL Java_io_highfidelity_hifiinterface_fragment_LoginFragment_nativeLogin(JNIEnv *env, jobject instance, jstring username_, jstring password_, @@ -273,17 +283,23 @@ Java_io_highfidelity_hifiinterface_fragment_LoginFragment_nativeLogin(JNIEnv *en QObject::connect(accountManager.data(), &AccountManager::loginComplete, [](const QUrl& authURL) { jboolean jSuccess = (jboolean) true; - __loginCompletedListener.callMethod("handleLoginCompleted", "(Z)V", jSuccess); + if (__loginCompletedListener.isValid()) { + __loginCompletedListener.callMethod("handleLoginCompleted", "(Z)V", jSuccess); + } }); QObject::connect(accountManager.data(), &AccountManager::loginFailed, []() { jboolean jSuccess = (jboolean) false; - __loginCompletedListener.callMethod("handleLoginCompleted", "(Z)V", jSuccess); + if (__loginCompletedListener.isValid()) { + __loginCompletedListener.callMethod("handleLoginCompleted", "(Z)V", jSuccess); + } }); QObject::connect(accountManager.data(), &AccountManager::usernameChanged, [](const QString& username) { QAndroidJniObject string = QAndroidJniObject::fromString(username); - __usernameChangedListener.callMethod("handleUsernameChanged", "(Ljava/lang/String;)V", string.object()); + if (__usernameChangedListener.isValid()) { + __usernameChangedListener.callMethod("handleUsernameChanged", "(Ljava/lang/String;)V", string.object()); + } }); QMetaObject::invokeMethod(accountManager.data(), "requestAccessToken", 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 f29c237ed7..92cdec19a1 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 @@ -4,12 +4,10 @@ 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.text.Editable; -import android.text.TextWatcher; -import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -19,8 +17,13 @@ import android.widget.Button; import android.widget.EditText; import android.widget.TextView; +import org.qtproject.qt5.android.QtNative; + import io.highfidelity.hifiinterface.R; +import static org.qtproject.qt5.android.QtActivityDelegate.ApplicationActive; +import static org.qtproject.qt5.android.QtActivityDelegate.ApplicationInactive; + public class LoginFragment extends Fragment { private EditText mUsername; @@ -32,6 +35,7 @@ public class LoginFragment extends Fragment { private ProgressDialog mDialog; public native void nativeLogin(String username, String password, Activity usernameChangedListener); + public native void nativeCancelLogin(); private LoginFragment.OnLoginInteractionListener mListener; @@ -55,44 +59,6 @@ public class LoginFragment extends Fragment { mLoginButton = rootView.findViewById(R.id.loginButton); mForgotPassword = rootView.findViewById(R.id.forgotPassword); - mUsername.addTextChangedListener(new TextWatcher() { - boolean ignoreNextChange = false; - boolean hadBlankSpace = false; - @Override - public void beforeTextChanged(CharSequence charSequence, int start, int count, int after) { - hadBlankSpace = charSequence.length() > 0 && charSequence.charAt(charSequence.length()-1) == ' '; - } - - @Override - public void onTextChanged(CharSequence charSequence, int start, int count, int after) { - - } - - @Override - public void afterTextChanged(Editable editable) { - if (!ignoreNextChange) { - ignoreNextChange = true; - boolean spaceFound = false; - for (int i = 0; i < editable.length(); i++) { - if (editable.charAt(i) == ' ') { - spaceFound=true; - editable.delete(i, i + 1); - i--; - } - } - - if (hadBlankSpace && !spaceFound && editable.length() > 0) { - editable.delete(editable.length()-1, editable.length()); - } - - editable.append(' '); - ignoreNextChange = false; - } - - } - }); - - mLoginButton.setOnClickListener(view -> login()); mForgotPassword.setOnClickListener(view -> forgotPassword()); @@ -125,10 +91,19 @@ public class LoginFragment extends Fragment { mListener = null; } + @Override + public void onResume() { + super.onResume(); + // This hack intends to keep Qt threads running even after the app comes from background + QtNative.setApplicationState(ApplicationActive); + } + @Override public void onStop() { super.onStop(); cancelActivityIndicator(); + // Leave the Qt app paused + QtNative.setApplicationState(ApplicationInactive); hideKeyboard(); } @@ -164,7 +139,15 @@ public class LoginFragment extends Fragment { mDialog = new ProgressDialog(getContext()); } mDialog.setMessage(getString(R.string.logging_in)); - mDialog.setCancelable(false); + mDialog.setCancelable(true); + mDialog.setOnCancelListener(new DialogInterface.OnCancelListener() { + @Override + public void onCancel(DialogInterface dialogInterface) { + nativeCancelLogin(); + cancelActivityIndicator(); + mLoginButton.setEnabled(true); + } + }); mDialog.show(); } @@ -184,7 +167,6 @@ public class LoginFragment extends Fragment { } public void handleLoginCompleted(boolean success) { - Log.d("[LOGIN]", "handleLoginCompleted " + success); getActivity().runOnUiThread(() -> { mLoginButton.setEnabled(true); cancelActivityIndicator(); diff --git a/android/app/src/main/res/drawable/ic_eye_noshow.xml b/android/app/src/main/res/drawable/ic_eye_noshow.xml new file mode 100644 index 0000000000..1d5304afac --- /dev/null +++ b/android/app/src/main/res/drawable/ic_eye_noshow.xml @@ -0,0 +1,27 @@ + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/drawable/ic_eye_show.xml b/android/app/src/main/res/drawable/ic_eye_show.xml new file mode 100644 index 0000000000..273ecc8339 --- /dev/null +++ b/android/app/src/main/res/drawable/ic_eye_show.xml @@ -0,0 +1,15 @@ + + + + + + diff --git a/android/app/src/main/res/drawable/selector_show_password.xml b/android/app/src/main/res/drawable/selector_show_password.xml new file mode 100644 index 0000000000..a44092aceb --- /dev/null +++ b/android/app/src/main/res/drawable/selector_show_password.xml @@ -0,0 +1,5 @@ + + + + + \ 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 c50e6c1380..46ed783898 100644 --- a/android/app/src/main/res/layout/fragment_login.xml +++ b/android/app/src/main/res/layout/fragment_login.xml @@ -41,38 +41,51 @@ android:paddingTop="14dp" android:ems="10" android:fontFamily="@font/raleway" - android:textSize="14sp" + android:textSize="17sp" android:inputType="textEmailAddress" android:textStyle="italic" android:textColor="@color/editTextColor" android:textColorHint="@color/editTextColor" - android:gravity="right|center_vertical" + android:gravity="left|center_vertical" app:layout_constraintTop_toBottomOf="@id/header" android:layout_marginTop="70dp" android:hint="@string/username_or_email" /> - + + android:inputType="textPassword" /> +