Add optional password field on user creation

Change-Id: Ia4e71290b97e6efb3c08f41badebf909d83ac845
diff --git a/ring-android/app/src/main/java/cx/ring/tv/account/RingGuidedStepFragment.java b/ring-android/app/src/main/java/cx/ring/tv/account/RingGuidedStepFragment.java
index 5b115cf..af4f86a 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/account/RingGuidedStepFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/tv/account/RingGuidedStepFragment.java
@@ -1,6 +1,9 @@
 package cx.ring.tv.account;
 
+import android.graphics.drawable.Drawable;
 import android.os.Bundle;
+import android.support.annotation.DrawableRes;
+import android.support.annotation.IdRes;
 import android.support.v17.leanback.app.GuidedStepFragment;
 import android.support.v17.leanback.widget.GuidedAction;
 import android.text.InputType;
@@ -37,6 +40,16 @@
                 .build());
     }
 
+    protected static void addDisabledAction(List<GuidedAction> actions, long id, String title, String desc, Drawable icon) {
+        actions.add(new GuidedAction.Builder()
+                .id(id)
+                .title(title)
+                .description(desc)
+                .enabled(false)
+                .icon(icon)
+                .build());
+    }
+
     protected static void addEditTextAction(List<GuidedAction> actions, long id,
                                             String title, String desc, String editdesc) {
         actions.add(
diff --git a/ring-android/app/src/main/java/cx/ring/tv/account/TVRingAccountCreationFragment.java b/ring-android/app/src/main/java/cx/ring/tv/account/TVRingAccountCreationFragment.java
index 9f3a361..0fa939d 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/account/TVRingAccountCreationFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/tv/account/TVRingAccountCreationFragment.java
@@ -6,12 +6,7 @@
 import android.support.annotation.NonNull;
 import android.support.v17.leanback.widget.GuidanceStylist;
 import android.support.v17.leanback.widget.GuidedAction;
-import android.text.Editable;
-import android.text.TextWatcher;
 import android.view.View;
-import android.view.ViewGroup;
-import android.widget.EditText;
-import android.widget.LinearLayout;
 
 import java.util.List;
 
@@ -23,6 +18,7 @@
 import cx.ring.application.RingApplication;
 import cx.ring.mvp.RingAccountViewModel;
 import cx.ring.utils.Log;
+import cx.ring.utils.StringUtils;
 
 public class TVRingAccountCreationFragment
         extends RingGuidedStepFragment<RingAccountCreationPresenter>
@@ -30,26 +26,9 @@
 
     private static final String TAG = TVRingAccountCreationFragment.class.getSimpleName();
     private static final int USERNAME = 0;
+    private static final int PASSWORD = 1;
+    private static final int PASSWORD_CONFIRMATION = 2;
     private static final int CONTINUE = 3;
-    TextWatcher usernameWatcher = new TextWatcher() {
-        @Override
-        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
-
-        }
-
-        @Override
-        public void onTextChanged(CharSequence s, int start, int before, int count) {
-
-        }
-
-        @Override
-        public void afterTextChanged(Editable s) {
-            Log.d(TAG, "userNameChanged(" + s.toString() + ")");
-            findActionById(USERNAME).setDescription(s.toString());
-            presenter.ringCheckChanged(!s.toString().isEmpty());
-            presenter.userNameChanged(s.toString());
-        }
-    };
 
     public static TVRingAccountCreationFragment newInstance(RingAccountViewModelImpl ringAccountViewModel) {
         Bundle bundle = new Bundle();
@@ -73,8 +52,6 @@
         presenter.init(ringAccountViewModel);
 
         presenter.ringCheckChanged(false);
-        presenter.passwordChanged("");
-        presenter.passwordConfirmChanged("");
     }
 
     @Override
@@ -91,32 +68,58 @@
     @Override
     public void onCreateActions(@NonNull List<GuidedAction> actions, Bundle savedInstanceState) {
         addEditTextAction(actions, USERNAME, getString(R.string.register_username), getString(R.string.prompt_new_username), "");
-        addDisabledAction(actions, CONTINUE, getString(R.string.action_create), "");
+        addPasswordAction(actions, PASSWORD, getString(R.string.prompt_new_password_optional), getString(R.string.enter_password), "");
+        addPasswordAction(actions, PASSWORD_CONFIRMATION, getString(R.string.prompt_new_password_repeat), getString(R.string.enter_password), "");
+        addDisabledAction(actions, CONTINUE, getString(R.string.action_create), "", getResources().getDrawable(R.drawable.ic_good));
     }
 
-    //FIXME: Leanback doesn't provide methode to know when action are initialised
-    // so we use this, the down effect is what we initialise several time the textwatcher
     @Override
     public void onGuidedActionFocused(GuidedAction action) {
-        super.onGuidedActionFocused(action);
-        //FIXME: Leanback doesn't provide access to the EditText Textwatcher
-        //So we need to access it by parsing children, this code will break if
-        //view architecture change
-        ViewGroup view = (ViewGroup) getActionItemView(findActionPositionById(USERNAME));
-        for (int index = 0; index < view.getChildCount(); ++index) {
-            View nextChild = view.getChildAt(index);
-            if (nextChild instanceof LinearLayout) {
-                ViewGroup editContainer = ((ViewGroup) nextChild);
-                if (editContainer.getChildCount() >= 2 && editContainer.getChildAt(1) instanceof EditText) {
-                    EditText text = (EditText) editContainer.getChildAt(1);
-                    text.removeTextChangedListener(usernameWatcher);
-                    text.addTextChangedListener(usernameWatcher);
-                }
-            }
+        if (action.getId() == PASSWORD) {
+            passwordChanged(action);
+        } else if (action.getId() == PASSWORD_CONFIRMATION) {
+            confirmPasswordChanged(action);
         }
     }
 
     @Override
+    public long onGuidedActionEditedAndProceed(GuidedAction action) {
+        if (action.getId() == USERNAME) {
+            String username = action.getEditDescription().toString();
+            findActionById(USERNAME).setDescription(username);
+            presenter.ringCheckChanged(!username.isEmpty());
+            presenter.userNameChanged(username);
+        } else if (action.getId() == PASSWORD) {
+            passwordChanged(action);
+        } else if (action.getId() == PASSWORD_CONFIRMATION) {
+            confirmPasswordChanged(action);
+        }
+        return GuidedAction.ACTION_ID_NEXT;
+    }
+
+    private void passwordChanged(GuidedAction action) {
+        String password = action.getEditDescription().toString();
+        if (password.length() > 0) {
+            action.setDescription(StringUtils.toPassword(password));
+        } else {
+            action.setDescription(getString(R.string.account_enter_password));
+        }
+        notifyActionChanged(findActionPositionById(PASSWORD));
+        presenter.passwordChanged(password);
+    }
+
+    private void confirmPasswordChanged(GuidedAction action) {
+        String passwordConfirm = action.getEditDescription().toString();
+        if (passwordConfirm.length() > 0) {
+            action.setDescription(StringUtils.toPassword(passwordConfirm));
+        } else {
+            action.setDescription(getString(R.string.account_enter_password));
+        }
+        notifyActionChanged(findActionPositionById(PASSWORD_CONFIRMATION));
+        presenter.passwordConfirmChanged(passwordConfirm);
+    }
+
+    @Override
     public int onProvideTheme() {
         return R.style.Theme_Ring_Leanback_GuidedStep_First;
     }
@@ -153,12 +156,24 @@
 
     @Override
     public void showInvalidPasswordError(boolean display) {
-        //NOOP on TV
+        Log.d(TAG, "showInvalidPasswordError");
+        if (display) {
+            findActionById(CONTINUE).setIcon(getResources().getDrawable(R.drawable.ic_error));
+            findActionById(CONTINUE).setDescription(getString(R.string.error_password_char_count));
+            findActionById(CONTINUE).setEnabled(false);
+        }
+        notifyActionChanged(findActionPositionById(CONTINUE));
     }
 
     @Override
     public void showNonMatchingPasswordError(boolean display) {
-        //NOOP on TV
+        Log.d(TAG, "showNonMatchingPasswordError");
+        if (display) {
+            findActionById(CONTINUE).setIcon(getResources().getDrawable(R.drawable.ic_error));
+            findActionById(CONTINUE).setDescription(getString(R.string.error_passwords_not_equals));
+            findActionById(CONTINUE).setEnabled(false);
+        }
+        notifyActionChanged(findActionPositionById(CONTINUE));
     }
 
     @Override
diff --git a/ring-android/app/src/main/res/values/strings.xml b/ring-android/app/src/main/res/values/strings.xml
index c18d8f2..f7960aa 100644
--- a/ring-android/app/src/main/res/values/strings.xml
+++ b/ring-android/app/src/main/res/values/strings.xml
@@ -163,6 +163,7 @@
     <!-- Contacts -->
     <string name="add_call_contact_number_to_contacts">Add %1$s ?</string>
     <string name="prompt_new_password">New password</string>
+    <string name="prompt_new_password_optional">New password (optional)</string>
     <string name="prompt_new_password_repeat">Repeat new password</string>
     <string name="account_create_title">Create a Ring account</string>
     <string name="prompt_new_username">Enter new username</string>
diff --git a/ring-android/app/src/main/res/values/strings_account.xml b/ring-android/app/src/main/res/values/strings_account.xml
index ea98331..df536ad 100644
--- a/ring-android/app/src/main/res/values/strings_account.xml
+++ b/ring-android/app/src/main/res/values/strings_account.xml
@@ -197,7 +197,7 @@
     <string name="register_name">Register name</string>
     <string name="trying_to_register_name">Trying to register name</string>
     <string name="registered_username">Registered username</string>
-    <string name="register_username">Register public username (optionnal)</string>
+    <string name="register_username">Register public username (optional)</string>
     <string name="username_already_taken">Username already taken</string>
     <string name="invalid_username">Invalid username</string>
     <string name="looking_for_username_availability">Looking for username availability…</string>
diff --git a/ring-android/libringclient/src/main/java/cx/ring/account/RingAccountCreationPresenter.java b/ring-android/libringclient/src/main/java/cx/ring/account/RingAccountCreationPresenter.java
index 5a74e2e..ac62d34 100644
--- a/ring-android/libringclient/src/main/java/cx/ring/account/RingAccountCreationPresenter.java
+++ b/ring-android/libringclient/src/main/java/cx/ring/account/RingAccountCreationPresenter.java
@@ -41,10 +41,10 @@
     private RingAccountViewModel mRingAccountViewModel;
 
     private boolean isRingUserNameCorrect = false;
-    private boolean isPasswordCorrect = false;
-    private boolean isConfirmCorrect = false;
+    private boolean isPasswordCorrect = true;
+    private boolean isConfirmCorrect = true;
     private boolean isRingUsernameCheck = true;
-    private String mPasswordConfirm;
+    private String mPasswordConfirm = "";
 
     @Inject
     public RingAccountCreationPresenter(AccountService accountService) {
@@ -92,14 +92,12 @@
     }
 
     public void passwordChanged(String password) {
-        if (mPasswordConfirm != null && !mPasswordConfirm.isEmpty()) {
-            if (!password.equals(mPasswordConfirm)) {
-                getView().showNonMatchingPasswordError(true);
-                isConfirmCorrect = false;
-            } else {
-                getView().showNonMatchingPasswordError(false);
-                isConfirmCorrect = true;
-            }
+        if (!password.equals(mPasswordConfirm)) {
+            getView().showNonMatchingPasswordError(true);
+            isConfirmCorrect = false;
+        } else {
+            getView().showNonMatchingPasswordError(false);
+            isConfirmCorrect = true;
         }
         if (!password.isEmpty() && password.length() < PASSWORD_MIN_LENGTH) {
             getView().showInvalidPasswordError(true);
@@ -113,7 +111,7 @@
     }
 
     public void passwordConfirmChanged(String passwordConfirm) {
-        if (!passwordConfirm.isEmpty() && !passwordConfirm.equals(mRingAccountViewModel.getPassword())) {
+        if (!passwordConfirm.equals(mRingAccountViewModel.getPassword())) {
             getView().showNonMatchingPasswordError(true);
             isConfirmCorrect = false;
         } else {