preferences: allow to change account password
Gitlab: #534
Change-Id: Ibec8aedba8c52cec0075a6455aa8bae7b6717788
Reviewed-by: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
diff --git a/ring-android/app/src/main/java/cx/ring/account/ChangePasswordDialog.java b/ring-android/app/src/main/java/cx/ring/account/ChangePasswordDialog.java
new file mode 100644
index 0000000..89aa6f0
--- /dev/null
+++ b/ring-android/app/src/main/java/cx/ring/account/ChangePasswordDialog.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2004-2019 Savoir-faire Linux Inc.
+ *
+ * Author: Adrien Beraud <adrien.beraud@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package cx.ring.account;
+
+import android.app.Dialog;
+import android.os.Bundle;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.inputmethod.EditorInfo;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.TextView;
+
+import com.google.android.material.textfield.TextInputLayout;
+
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AlertDialog;
+import androidx.fragment.app.DialogFragment;
+import butterknife.BindString;
+import butterknife.BindView;
+import butterknife.ButterKnife;
+import butterknife.OnEditorAction;
+import cx.ring.R;
+
+public class ChangePasswordDialog extends DialogFragment {
+ static final String TAG = ChangePasswordDialog.class.getSimpleName();
+
+ @BindView(R.id.old_password_txt_box)
+ protected TextInputLayout mPasswordTxtBox;
+
+ @BindView(R.id.old_password_txt)
+ protected EditText mPasswordTxt;
+
+ @BindView(R.id.new_password_txt_box)
+ protected TextInputLayout mNewPasswordTxtBox;
+
+ @BindView(R.id.new_password_txt)
+ protected EditText mNewPasswordTxt;
+
+ @BindView(R.id.new_password_repeat_txt_box)
+ protected TextInputLayout mNewPasswordRepeatsTxtBox;
+
+ @BindView(R.id.new_password_repeat_txt)
+ protected EditText mNewPasswordRepeatsTxt;
+
+ @BindString(R.string.enter_password)
+ protected String mPromptPassword;
+
+ private PasswordChangedListener mListener = null;
+
+ public void setListener(PasswordChangedListener listener) {
+ mListener = listener;
+ }
+
+ @NonNull
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ View view = requireActivity().getLayoutInflater().inflate(R.layout.dialog_set_password, null);
+ ButterKnife.bind(this, view);
+
+ String accountId = "";
+ boolean hasPassword = true;
+ Bundle args = getArguments();
+ if (args != null) {
+ accountId = args.getString(AccountEditionActivity.ACCOUNT_ID_KEY, accountId);
+ hasPassword = args.getBoolean(AccountEditionActivity.ACCOUNT_HAS_PASSWORD_KEY, true);
+ }
+ int passwordMessage = hasPassword ? R.string.account_password_change : R.string.account_password_set;
+ mPasswordTxtBox.setVisibility(hasPassword ? View.VISIBLE : View.GONE);
+
+ final AlertDialog result = new AlertDialog.Builder(requireContext())
+ .setView(view)
+ .setMessage(R.string.help_password_choose)
+ .setTitle(passwordMessage)
+ .setPositiveButton(passwordMessage, null) //Set to null. We override the onclick
+ .setNegativeButton(android.R.string.cancel, (dialog, whichButton) -> dismiss())
+ .create();
+ result.setOnShowListener(dialog -> {
+ Button positiveButton = ((AlertDialog) dialog).getButton(AlertDialog.BUTTON_POSITIVE);
+ positiveButton.setOnClickListener(view1 -> {
+ if (validate()) {
+ dismiss();
+ }
+ });
+ });
+ result.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
+ return result;
+ }
+
+ public boolean checkInput() {
+ if (!mNewPasswordTxt.getText().toString().contentEquals(mNewPasswordRepeatsTxt.getText())) {
+ mNewPasswordTxtBox.setErrorEnabled(true);
+ mNewPasswordTxtBox.setError(getText(R.string.error_passwords_not_equals));
+ mNewPasswordRepeatsTxtBox.setErrorEnabled(true);
+ mNewPasswordRepeatsTxtBox.setError(getText(R.string.error_passwords_not_equals));
+ return false;
+ } else {
+ mNewPasswordTxtBox.setErrorEnabled(false);
+ mNewPasswordTxtBox.setError(null);
+ mNewPasswordRepeatsTxtBox.setErrorEnabled(false);
+ mNewPasswordRepeatsTxtBox.setError(null);
+ }
+ return true;
+ }
+
+ private boolean validate() {
+ if (checkInput() && mListener != null) {
+ final String oldPassword = mPasswordTxt.getText().toString();
+ final String newPassword = mNewPasswordTxt.getText().toString();
+ mListener.onPasswordChanged(oldPassword, newPassword);
+ return true;
+ }
+ return false;
+ }
+
+ @OnEditorAction({R.id.new_password_repeat_txt})
+ public boolean onEditorAction(TextView v, int actionId) {
+ if (actionId == EditorInfo.IME_ACTION_DONE) {
+ if (validate()) {
+ getDialog().dismiss();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public interface PasswordChangedListener {
+ void onPasswordChanged(String oldPassword, String newPassword);
+ }
+}
diff --git a/ring-android/app/src/main/java/cx/ring/account/ConfirmRevocationDialog.java b/ring-android/app/src/main/java/cx/ring/account/ConfirmRevocationDialog.java
index 759dbce..42377cd 100644
--- a/ring-android/app/src/main/java/cx/ring/account/ConfirmRevocationDialog.java
+++ b/ring-android/app/src/main/java/cx/ring/account/ConfirmRevocationDialog.java
@@ -22,6 +22,8 @@
import android.app.Dialog;
import android.os.Bundle;
import com.google.android.material.textfield.TextInputLayout;
+
+import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import android.view.View;
import android.view.WindowManager;
@@ -55,14 +57,15 @@
mListener = listener;
}
+ @NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
- View view = getActivity().getLayoutInflater().inflate(R.layout.dialog_confirm_revocation, null);
+ View view = requireActivity().getLayoutInflater().inflate(R.layout.dialog_confirm_revocation, null);
ButterKnife.bind(this, view);
mDeviceId = getArguments().getString(DEVICEID_KEY);
- final AlertDialog result = new AlertDialog.Builder(getActivity())
+ final AlertDialog result = new AlertDialog.Builder(requireContext())
.setView(view)
.setMessage(getString(R.string.revoke_device_message, mDeviceId))
.setTitle(mRegisterTitle)
@@ -83,7 +86,7 @@
return result;
}
- public boolean checkInput() {
+ private boolean checkInput() {
if (mPasswordTxt.getText().toString().isEmpty()) {
mPasswordTxtBox.setErrorEnabled(true);
mPasswordTxtBox.setError(mPromptPassword);
@@ -95,7 +98,7 @@
return true;
}
- boolean validate() {
+ private boolean validate() {
if (checkInput() && mListener != null) {
final String password = mPasswordTxt.getText().toString();
mListener.onConfirmRevocation(mDeviceId, password);
diff --git a/ring-android/app/src/main/java/cx/ring/account/RegisterNameDialog.java b/ring-android/app/src/main/java/cx/ring/account/RegisterNameDialog.java
index 570b6df..ee66aec 100644
--- a/ring-android/app/src/main/java/cx/ring/account/RegisterNameDialog.java
+++ b/ring-android/app/src/main/java/cx/ring/account/RegisterNameDialog.java
@@ -34,6 +34,7 @@
import javax.inject.Inject;
+import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.DialogFragment;
import butterknife.BindString;
@@ -113,9 +114,10 @@
}
}
+ @NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
- final AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
+ final AlertDialog.Builder builder = new AlertDialog.Builder(requireContext());
View view = getActivity().getLayoutInflater().inflate(R.layout.frag_register_name, null);
diff --git a/ring-android/app/src/main/java/cx/ring/account/RenameDeviceDialog.java b/ring-android/app/src/main/java/cx/ring/account/RenameDeviceDialog.java
index f748bd0..6b8e296 100644
--- a/ring-android/app/src/main/java/cx/ring/account/RenameDeviceDialog.java
+++ b/ring-android/app/src/main/java/cx/ring/account/RenameDeviceDialog.java
@@ -18,7 +18,6 @@
*/
package cx.ring.account;
-import android.app.Activity;
import android.app.Dialog;
import android.os.Bundle;
import com.google.android.material.textfield.TextInputLayout;
@@ -57,13 +56,12 @@
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
- Activity activity = getActivity();
- View view = activity.getLayoutInflater().inflate(R.layout.dialog_device_rename, null);
+ View view = requireActivity().getLayoutInflater().inflate(R.layout.dialog_device_rename, null);
ButterKnife.bind(this, view);
mDeviceNameTxt.setText(getArguments().getString(DEVICENAME_KEY));
- final AlertDialog dialog = new AlertDialog.Builder(activity)
+ final AlertDialog dialog = new AlertDialog.Builder(requireContext())
.setView(view)
.setTitle(R.string.rename_device_title)
.setMessage(R.string.rename_device_message)
diff --git a/ring-android/app/src/main/java/cx/ring/account/RingAccountSummaryFragment.java b/ring-android/app/src/main/java/cx/ring/account/RingAccountSummaryFragment.java
index 6afed88..c7d083f 100644
--- a/ring-android/app/src/main/java/cx/ring/account/RingAccountSummaryFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/account/RingAccountSummaryFragment.java
@@ -22,14 +22,12 @@
import android.app.ProgressDialog;
import android.graphics.Typeface;
-import android.graphics.drawable.Drawable;
import android.os.Bundle;
+import com.google.android.material.chip.Chip;
import com.google.android.material.textfield.TextInputLayout;
import androidx.annotation.NonNull;
-import androidx.core.content.ContextCompat;
-import androidx.core.graphics.drawable.DrawableCompat;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.SwitchCompat;
@@ -58,7 +56,6 @@
import cx.ring.dependencyinjection.RingInjectionComponent;
import cx.ring.interfaces.BackHandlerInterface;
import cx.ring.model.Account;
-import cx.ring.model.ConfigKey;
import cx.ring.mvp.BaseSupportFragment;
import cx.ring.utils.KeyboardVisibilityManager;
import cx.ring.views.LinkNewDeviceLayout;
@@ -68,10 +65,12 @@
RenameDeviceDialog.RenameDeviceListener,
DeviceAdapter.DeviceRevocationListener,
ConfirmRevocationDialog.ConfirmRevocationListener,
- RingAccountSummaryView {
+ RingAccountSummaryView, ChangePasswordDialog.PasswordChangedListener {
public static final String TAG = RingAccountSummaryFragment.class.getSimpleName();
- private static final String FRAGMENT_DIALOG_REVOCATION = RingAccountSummaryFragment.class.getSimpleName() + ".dialog.deviceRevocation";
+ private static final String FRAGMENT_DIALOG_REVOCATION = TAG + ".dialog.deviceRevocation";
+ private static final String FRAGMENT_DIALOG_RENAME = TAG + ".dialog.deviceRename";
+ private static final String FRAGMENT_DIALOG_PASSWORD = TAG + ".dialog.changePassword";
/*
UI Bindings
@@ -97,6 +96,9 @@
@BindView(R.id.account_id_txt)
TextView mAccountIdTxt;
+ @BindView(R.id.change_password_btn)
+ Button mChangePasswordBtn;
+
@BindView(R.id.registered_name_txt)
TextView mAccountUsernameTxt;
@@ -122,7 +124,7 @@
SwitchCompat mAccountSwitch;
@BindView(R.id.account_status)
- TextView mAccountStatus;
+ Chip mAccountStatus;
/*
Declarations
@@ -145,14 +147,14 @@
}
@Override
- public void accountChanged(final Account account) {
- if (account == null) {
- Log.w(TAG, "No account to display!");
- return;
+ public void accountChanged(@NonNull final Account account) {
+ if (mDeviceAdapter == null) {
+ mDeviceAdapter = new DeviceAdapter(requireContext(), account.getDevices(), account.getDeviceId(),
+ RingAccountSummaryFragment.this);
+ mDeviceList.setAdapter(mDeviceAdapter);
+ } else {
+ mDeviceAdapter.setData(account.getDevices(), account.getDeviceId());
}
- mDeviceAdapter = new DeviceAdapter(getActivity(), account.getDevices(), account.getDeviceId(),
- RingAccountSummaryFragment.this);
- mDeviceList.setAdapter(mDeviceAdapter);
int totalHeight = 0;
for (int i = 0; i < mDeviceAdapter.getCount(); i++) {
@@ -166,6 +168,8 @@
mDeviceList.setLayoutParams(par);
mDeviceList.requestLayout();
+ mChangePasswordBtn.setText(account.hasPassword() ? R.string.account_password_change : R.string.account_password_set);
+
mAccountSwitch.setChecked(account.isEnabled());
mAccountNameTxt.setText(account.getAlias());
mAccountIdTxt.setText(account.getUsername());
@@ -179,11 +183,12 @@
mAccountUsernameTxt.setText(username);
}
- int color = ContextCompat.getColor(getContext(), R.color.holo_red_light);
+ int color = R.color.red_400;
String status;
if (account.isEnabled()) {
if (account.isTrying()) {
+ color = R.color.orange_400;
status = getString(R.string.account_status_connecting);
} else if (account.needsMigration()) {
status = getString(R.string.account_update_needed);
@@ -191,21 +196,19 @@
status = getString(R.string.account_status_connection_error);
} else if (account.isRegistered()) {
status = getString(R.string.account_status_online);
- color = ContextCompat.getColor(getContext(), R.color.holo_green_dark);
+ color = R.color.green_400;
} else {
status = getString(R.string.account_status_unknown);
}
} else {
- color = ContextCompat.getColor(getContext(), R.color.darker_gray);
+ color = R.color.grey_400;
status = getString(R.string.account_status_offline);
}
mAccountStatus.setText(status);
- Drawable wrapped = DrawableCompat.wrap(getContext().getDrawable(R.drawable.static_rounded_background));
- DrawableCompat.setTint(wrapped, color);
- mAccountStatus.setBackground(wrapped);
+ mAccountStatus.setChipBackgroundColorResource(color);
- mAccountHasPassword = account.getDetailBoolean(ConfigKey.ARCHIVE_HAS_PASSWORD);
+ mAccountHasPassword = account.hasPassword();
mPasswordLayout.setVisibility(mAccountHasPassword ? View.VISIBLE : View.GONE);
}
@@ -254,8 +257,8 @@
@Override
public void showNetworkError() {
- mWaitDialog.dismiss();
- new AlertDialog.Builder(getActivity())
+ dismissWaitDialog();
+ new AlertDialog.Builder(requireActivity())
.setTitle(R.string.account_export_end_network_title)
.setMessage(R.string.account_export_end_network_message)
.setPositiveButton(android.R.string.ok, null)
@@ -264,15 +267,15 @@
@Override
public void showPasswordError() {
- mWaitDialog.dismiss();
+ dismissWaitDialog();
mPasswordLayout.setError(getString(R.string.account_export_end_decryption_message));
mRingPassword.setText("");
}
@Override
public void showGenericError() {
- mWaitDialog.dismiss();
- new AlertDialog.Builder(getActivity())
+ dismissWaitDialog();
+ new AlertDialog.Builder(requireActivity())
.setTitle(R.string.account_export_end_error_title)
.setMessage(R.string.account_export_end_error_message)
.setPositiveButton(android.R.string.ok, null)
@@ -284,8 +287,7 @@
}
@OnEditorAction(R.id.ring_password)
- @SuppressWarnings("unused")
- public boolean onPasswordEditorAction(TextView pwd, int actionId, KeyEvent event) {
+ boolean onPasswordEditorAction(TextView pwd, int actionId, KeyEvent event) {
Log.i(TAG, "onEditorAction " + actionId + " " + (event == null ? null : event.toString()));
if (actionId == EditorInfo.IME_ACTION_DONE) {
if (pwd.getText().length() == 0) {
@@ -299,26 +301,26 @@
}
@OnClick(R.id.btn_start_export)
- public void onClickStart() {
+ void onClickStart() {
mPasswordLayout.setError(null);
String password = mRingPassword.getText().toString();
presenter.startAccountExport(password);
}
@OnClick(R.id.account_switch)
- public void onToggleAccount() {
+ void onToggleAccount() {
presenter.enableAccount(mAccountSwitch.isChecked());
}
@OnClick(R.id.register_name_btn)
- public void showUsernameRegistrationPopup() {
+ void showUsernameRegistrationPopup() {
Bundle args = new Bundle();
args.putString(AccountEditionActivity.ACCOUNT_ID_KEY, getArguments().getString(AccountEditionActivity.ACCOUNT_ID_KEY));
args.putBoolean(AccountEditionActivity.ACCOUNT_HAS_PASSWORD_KEY, mAccountHasPassword);
RegisterNameDialog registrationDialog = new RegisterNameDialog();
registrationDialog.setArguments(args);
registrationDialog.setListener(this);
- registrationDialog.show(getFragmentManager(), TAG);
+ registrationDialog.show(requireFragmentManager(), TAG);
}
@Override
@@ -341,8 +343,15 @@
}
@Override
+ public void showPasswordProgressDialog() {
+ mWaitDialog = ProgressDialog.show(getActivity(),
+ getString(R.string.export_account_wait_title),
+ getString(R.string.account_password_change_wait_message));
+ }
+
+ @Override
public int getLayout() {
- return R.layout.frag_device_list;
+ return R.layout.frag_acc_summary;
}
@Override
@@ -350,15 +359,22 @@
component.inject(this);
}
+ private void dismissWaitDialog() {
+ if (mWaitDialog != null) {
+ mWaitDialog.dismiss();
+ mWaitDialog = null;
+ }
+ }
+
+
@Override
public void showPIN(final String pin) {
hideWizard();
- mWaitDialog.dismiss();
mLinkAccountView.setVisibility(View.VISIBLE);
mPasswordLayout.setVisibility(View.GONE);
mEndBtn.setVisibility(View.VISIBLE);
mStartBtn.setVisibility(View.GONE);
-
+ dismissWaitDialog();
String pined = getString(R.string.account_end_export_infos).replace("%%", pin);
final SpannableString styledResultText = new SpannableString(pined);
int pos = pined.lastIndexOf(pin);
@@ -380,8 +396,20 @@
}
@Override
+ public void passwordChangeEnded(boolean ok) {
+ dismissWaitDialog();
+ if (!ok) {
+ new AlertDialog.Builder(requireActivity())
+ .setTitle(R.string.account_device_revocation_wrong_password)
+ .setMessage(R.string.account_export_end_decryption_message)
+ .setPositiveButton(android.R.string.ok, null)
+ .show();
+ }
+ }
+
+ @Override
public void deviceRevocationEnded(final String device, final int status) {
- mWaitDialog.dismiss();
+ dismissWaitDialog();
int message, title = R.string.account_device_revocation_error_title;
switch (status) {
case 0:
@@ -397,7 +425,7 @@
default:
message = R.string.account_device_revocation_error_unknown;
}
- new AlertDialog.Builder(getActivity())
+ new AlertDialog.Builder(requireActivity())
.setTitle(title)
.setMessage(message)
.setPositiveButton(android.R.string.ok, (dialog, which) -> {
@@ -421,7 +449,7 @@
args.putString(ConfirmRevocationDialog.DEVICEID_KEY, deviceId);
dialog.setArguments(args);
dialog.setListener(this);
- dialog.show(getFragmentManager(), FRAGMENT_DIALOG_REVOCATION);
+ dialog.show(requireFragmentManager(), FRAGMENT_DIALOG_REVOCATION);
}
@Override
@@ -432,7 +460,18 @@
args.putString(RenameDeviceDialog.DEVICENAME_KEY, dev_name);
dialog.setArguments(args);
dialog.setListener(this);
- dialog.show(getFragmentManager(), TAG);
+ dialog.show(requireFragmentManager(), FRAGMENT_DIALOG_RENAME);
+ }
+
+ @OnClick(R.id.change_password_btn)
+ public void onPasswordChangeAsked() {
+ ChangePasswordDialog dialog = new ChangePasswordDialog();
+ Bundle args = new Bundle();
+ args.putString(AccountEditionActivity.ACCOUNT_ID_KEY, getArguments().getString(AccountEditionActivity.ACCOUNT_ID_KEY));
+ args.putBoolean(AccountEditionActivity.ACCOUNT_HAS_PASSWORD_KEY, mAccountHasPassword);
+ dialog.setArguments(args);
+ dialog.setListener(this);
+ dialog.show(requireFragmentManager(), FRAGMENT_DIALOG_PASSWORD);
}
@Override
@@ -440,4 +479,9 @@
Log.d(TAG, "onDeviceRename: " + presenter.getDeviceName() + " -> " + newName);
presenter.renameDevice(newName);
}
+
+ @Override
+ public void onPasswordChanged(String oldPassword, String newPassword) {
+ presenter.changePassword(oldPassword, newPassword);
+ }
}
diff --git a/ring-android/app/src/main/java/cx/ring/tv/account/TVAccountExport.java b/ring-android/app/src/main/java/cx/ring/tv/account/TVAccountExport.java
index e4fa66e..0069281 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/account/TVAccountExport.java
+++ b/ring-android/app/src/main/java/cx/ring/tv/account/TVAccountExport.java
@@ -106,6 +106,11 @@
}
@Override
+ public void showPasswordProgressDialog() {
+
+ }
+
+ @Override
public void accountChanged(Account account) {
}
@@ -165,4 +170,9 @@
public void deviceRevocationEnded(String device, int status) {
}
+
+ @Override
+ public void passwordChangeEnded(boolean ok) {
+
+ }
}
diff --git a/ring-android/app/src/main/res/layout/add_new_device_layout.xml b/ring-android/app/src/main/res/layout/add_new_device_layout.xml
index de24102..34fb9ea 100644
--- a/ring-android/app/src/main/res/layout/add_new_device_layout.xml
+++ b/ring-android/app/src/main/res/layout/add_new_device_layout.xml
@@ -25,7 +25,7 @@
android:clipToPadding="false"
android:paddingTop="20dp"
android:theme="@style/Wizard"
- tools:showIn="@layout/frag_device_list">
+ tools:showIn="@layout/frag_acc_summary">
<LinearLayout
android:layout_width="match_parent"
diff --git a/ring-android/app/src/main/res/layout/dialog_set_password.xml b/ring-android/app/src/main/res/layout/dialog_set_password.xml
new file mode 100644
index 0000000..f0ce638
--- /dev/null
+++ b/ring-android/app/src/main/res/layout/dialog_set_password.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:fadeScrollbars="false"
+ android:scrollIndicators="top|bottom">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:scrollbars="vertical"
+ android:scrollbarAlwaysDrawVerticalTrack="true">
+
+ <com.google.android.material.textfield.TextInputLayout
+ android:id="@+id/old_password_txt_box"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="12dp"
+ android:layout_marginRight="12dp"
+ android:layout_marginBottom="16dp">
+
+ <com.google.android.material.textfield.TextInputEditText
+ android:id="@+id/old_password_txt"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:hint="@string/help_password_enter"
+ android:imeOptions="actionNext"
+ android:inputType="textPassword"
+ android:lines="1"
+ android:maxLines="1" />
+ </com.google.android.material.textfield.TextInputLayout>
+
+ <com.google.android.material.textfield.TextInputLayout
+ android:id="@+id/new_password_txt_box"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="12dp"
+ android:layout_marginRight="12dp"
+ android:layout_marginBottom="16dp">
+
+ <com.google.android.material.textfield.TextInputEditText
+ android:id="@+id/new_password_txt"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:hint="@string/prompt_new_password"
+ android:imeOptions="actionNext"
+ android:inputType="textPassword"
+ android:lines="1"
+ android:maxLines="1" />
+ </com.google.android.material.textfield.TextInputLayout>
+
+ <com.google.android.material.textfield.TextInputLayout
+ android:id="@+id/new_password_repeat_txt_box"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="12dp"
+ android:layout_marginRight="12dp"
+ android:layout_marginBottom="16dp">
+
+ <com.google.android.material.textfield.TextInputEditText
+ android:id="@+id/new_password_repeat_txt"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:hint="@string/prompt_new_password_repeat"
+ android:imeOptions="actionDone"
+ android:inputType="textPassword"
+ android:lines="1"
+ android:maxLines="1" />
+ </com.google.android.material.textfield.TextInputLayout>
+
+ </LinearLayout>
+
+</ScrollView>
\ No newline at end of file
diff --git a/ring-android/app/src/main/res/layout/frag_device_list.xml b/ring-android/app/src/main/res/layout/frag_acc_summary.xml
similarity index 77%
rename from ring-android/app/src/main/res/layout/frag_device_list.xml
rename to ring-android/app/src/main/res/layout/frag_acc_summary.xml
index 59093f1..ca8d04e 100644
--- a/ring-android/app/src/main/res/layout/frag_device_list.xml
+++ b/ring-android/app/src/main/res/layout/frag_acc_summary.xml
@@ -46,20 +46,17 @@
android:layout_height="wrap_content"
android:layout_toStartOf="@+id/account_switch"
android:paddingBottom="8dp"
- android:textAppearance="@style/Base.TextAppearance.AppCompat.Large"
+ android:textAppearance="@style/TextAppearance.MaterialComponents.Headline4"
tools:text="@string/ring_account" />
- <TextView
+ <com.google.android.material.chip.Chip
android:id="@+id/account_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/account_alias_txt"
- android:textAppearance="@style/Base.TextAppearance.AppCompat.Small.Inverse"
android:textColor="@color/white"
- android:textStyle="bold"
tools:text="Registered" />
-
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/account_switch"
android:layout_width="50dp"
@@ -73,58 +70,75 @@
android:layout_height="match_parent"
android:layout_below="@+id/ring_account_status_container"
android:orientation="vertical"
- android:paddingBottom="8dp"
- android:paddingEnd="16dp"
android:paddingStart="16dp"
- android:paddingTop="24dp">
+ android:paddingTop="12dp"
+ android:paddingEnd="16dp"
+ android:paddingBottom="8dp">
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dip"
+ android:layout_marginVertical="16dp"
+ android:background="?android:attr/listDivider"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/ring_account_identity"
- android:textAppearance="@style/Base.TextAppearance.AppCompat.Large" />
+ android:textAppearance="@style/TextAppearance.MaterialComponents.Overline" />
<TextView
android:id="@+id/account_id_txt"
- style="@style/Subheader"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="middle"
- android:gravity="center_vertical"
- android:paddingBottom="8dp"
- android:paddingLeft="16dp"
- android:paddingRight="16dp"
- android:paddingTop="8dp"
android:singleLine="true"
android:textIsSelectable="true"
- android:textStyle="bold"
+ android:textAppearance="@style/TextAppearance.MaterialComponents.Subtitle2"
tools:text="ring:8F29045378ACA68F2ACA2346078ACA68F2ACA290" />
+ <com.google.android.material.button.MaterialButton
+ android:id="@+id/change_password_btn"
+ style="@style/Widget.MaterialComponents.Button.OutlinedButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end"
+ android:paddingStart="16dp"
+ android:paddingEnd="16dp"
+ android:text="@string/account_password_change" />
+
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dip"
+ android:layout_marginVertical="16dp"
+ android:background="?android:attr/listDivider" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/registered_username"
+ android:textAppearance="@style/TextAppearance.MaterialComponents.Overline" />
+
<LinearLayout
android:id="@+id/group_register_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_margin="16dp"
- android:gravity="center_horizontal"
android:orientation="vertical">
<TextView
- style="@style/Subheader"
- android:layout_width="match_parent"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:gravity="center_vertical"
- android:paddingBottom="8dp"
- android:paddingTop="8dp"
- android:text="@string/no_registered_name_for_account"
- android:textAlignment="center" />
+ android:text="@string/no_registered_name_for_account" />
<com.google.android.material.button.MaterialButton
android:id="@+id/register_name_btn"
style="@style/Widget.MaterialComponents.Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:paddingEnd="16dp"
+ android:layout_gravity="end"
android:paddingStart="16dp"
+ android:paddingEnd="16dp"
android:text="@string/register_name" />
</LinearLayout>
@@ -133,9 +147,7 @@
android:id="@+id/group_registering_name"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_margin="16dp"
- android:orientation="horizontal"
- android:visibility="gone">
+ android:orientation="horizontal">
<TextView
android:id="@+id/textView"
@@ -155,51 +167,34 @@
android:id="@+id/group_registered_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_margin="16dp"
- android:orientation="horizontal"
- android:visibility="gone">
-
- <TextView
- style="@style/Subheader"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:gravity="center_vertical"
- android:paddingBottom="16dp"
- android:paddingTop="4dp"
- android:text="@string/registered_username" />
+ android:orientation="horizontal">
<TextView
android:id="@+id/registered_name_txt"
- style="@style/Base.TextAppearance.AppCompat.Title"
+ android:textAppearance="@style/TextAppearance.MaterialComponents.Subtitle2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="start"
- android:paddingBottom="16dp"
- android:paddingEnd="8dp"
- android:paddingStart="16dp"
- android:paddingTop="4dp"
android:textAlignment="viewStart"
android:textIsSelectable="true"
tools:text="blockchain_name" />
</LinearLayout>
- <TextView
- style="@style/Subheader"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center_vertical"
- android:paddingBottom="8dp"
- android:paddingEnd="16dp"
- android:paddingStart="16dp"
- android:paddingTop="8dp"
- android:text="@string/normal_devices_titles" />
<View
android:layout_width="match_parent"
android:layout_height="1dip"
+ android:layout_marginVertical="16dp"
android:background="?android:attr/listDivider" />
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical"
+ android:text="@string/normal_devices_titles"
+ android:textAppearance="@style/TextAppearance.MaterialComponents.Overline" />
+
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
@@ -208,7 +203,7 @@
android:id="@+id/device_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:divider="#CCCCCC"
+ android:divider="#DDDDDD"
android:dividerHeight="1dp"
android:footerDividersEnabled="true"
android:headerDividersEnabled="true" />
diff --git a/ring-android/app/src/main/res/layout/item_device.xml b/ring-android/app/src/main/res/layout/item_device.xml
index 03785a4..aa7c566 100644
--- a/ring-android/app/src/main/res/layout/item_device.xml
+++ b/ring-android/app/src/main/res/layout/item_device.xml
@@ -72,6 +72,7 @@
android:layout_height="wrap_content"
android:layout_alignWithParentIfMissing="true"
android:layout_centerVertical="true"
+ android:layout_marginStart="8dp"
android:layout_toStartOf="@+id/revoke_button"
android:background="?selectableItemBackgroundBorderless"
android:contentDescription="@string/account_device_revoke"
@@ -85,6 +86,7 @@
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
+ android:layout_marginStart="8dp"
android:background="?selectableItemBackgroundBorderless"
android:contentDescription="@string/account_device_revoke"
android:padding="8dp"
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 f0f9262..7a8d12f 100644
--- a/ring-android/app/src/main/res/values/strings_account.xml
+++ b/ring-android/app/src/main/res/values/strings_account.xml
@@ -72,6 +72,9 @@
<string name="account_device_revocation_wrong_password">Wrong password.</string>
<string name="account_device_revocation_unknown_device">Unknown device.</string>
<string name="account_device_revocation_error_unknown">Unknown error.</string>
+ <string name="account_password_change">Change password</string>
+ <string name="account_password_set">Set password</string>
+ <string name="account_password_change_wait_message">Changing account password</string>
<!-- Basic Details -->
<string name="account_preferences_basic_tab">General</string>
diff --git a/ring-android/libringclient/src/main/java/cx/ring/account/RingAccountSummaryPresenter.java b/ring-android/libringclient/src/main/java/cx/ring/account/RingAccountSummaryPresenter.java
index b83311d..3739e56 100644
--- a/ring-android/libringclient/src/main/java/cx/ring/account/RingAccountSummaryPresenter.java
+++ b/ring-android/libringclient/src/main/java/cx/ring/account/RingAccountSummaryPresenter.java
@@ -88,7 +88,6 @@
RingAccountSummaryView view = getView();
if (view != null) {
view.accountChanged(account);
- view.updateDeviceList(account.getDevices(), account.getDeviceId());
}
}));
}
@@ -119,6 +118,17 @@
mAccountService.renameDevice(mAccountID, newName);
}
+ public void changePassword(String oldPassword, String newPassword) {
+ RingAccountSummaryView view = getView();
+ if (view != null)
+ view.showPasswordProgressDialog();
+ mCompositeDisposable.add(mAccountService.setAccountPassword(mAccountID, oldPassword, newPassword)
+ .observeOn(mUiScheduler)
+ .subscribe(
+ () -> getView().passwordChangeEnded(true),
+ e -> getView().passwordChangeEnded(false)));
+ }
+
public String getDeviceName() {
Account account = mAccountService.getAccount(mAccountID);
if (account == null) {
diff --git a/ring-android/libringclient/src/main/java/cx/ring/account/RingAccountSummaryView.java b/ring-android/libringclient/src/main/java/cx/ring/account/RingAccountSummaryView.java
index 413f0b0..c4047f0 100644
--- a/ring-android/libringclient/src/main/java/cx/ring/account/RingAccountSummaryView.java
+++ b/ring-android/libringclient/src/main/java/cx/ring/account/RingAccountSummaryView.java
@@ -29,6 +29,8 @@
void showRevokingProgressDialog();
+ void showPasswordProgressDialog();
+
void accountChanged(final Account account);
void showNetworkError();
@@ -42,5 +44,6 @@
void updateDeviceList(Map<String, String> devices, String currentDeviceId);
void deviceRevocationEnded(String device, int status);
+ void passwordChangeEnded(boolean ok);
}
diff --git a/ring-android/libringclient/src/main/java/cx/ring/model/Account.java b/ring-android/libringclient/src/main/java/cx/ring/model/Account.java
index ffcdc4d..5cf4d59 100644
--- a/ring-android/libringclient/src/main/java/cx/ring/model/Account.java
+++ b/ring-android/libringclient/src/main/java/cx/ring/model/Account.java
@@ -396,6 +396,10 @@
mDetails.put(ConfigKey.ACCOUNT_ENABLE, isChecked);
}
+ public boolean hasPassword() {
+ return mDetails.getBool(ConfigKey.ARCHIVE_HAS_PASSWORD);
+ }
+
public HashMap<String, String> getDetails() {
return mDetails.getAll();
}
diff --git a/ring-android/libringclient/src/main/java/cx/ring/services/AccountService.java b/ring-android/libringclient/src/main/java/cx/ring/services/AccountService.java
index 6619e51..6947699 100644
--- a/ring-android/libringclient/src/main/java/cx/ring/services/AccountService.java
+++ b/ring-android/libringclient/src/main/java/cx/ring/services/AccountService.java
@@ -58,6 +58,7 @@
import cx.ring.utils.SwigNativeConverter;
import cx.ring.utils.VCardUtils;
import ezvcard.VCard;
+import io.reactivex.Completable;
import io.reactivex.Single;
import io.reactivex.schedulers.Schedulers;
import io.reactivex.subjects.BehaviorSubject;
@@ -672,6 +673,17 @@
}
/**
+ * @param accountId id of the account
+ * @param oldPassword old account password
+ */
+ public Completable setAccountPassword(final String accountId, final String oldPassword, final String newPassword) {
+ return Completable.fromAction(() -> {
+ if (!Ringservice.changeAccountPassword(accountId, oldPassword, newPassword))
+ throw new IllegalArgumentException("Can't change password");
+ }).subscribeOn(Schedulers.from(mExecutor));
+ }
+
+ /**
* Sets the active codecs list of the account in the Daemon
*/
public void setActiveCodecList(final String accountId, final List<Long> codecs) {