First part of the authentication slide (WIP)
This commit is contained in:
parent
324f84b36c
commit
14a7e2c174
3 changed files with 181 additions and 32 deletions
|
@ -2,13 +2,12 @@ package org.shadowice.flocke.andotp.Activities;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.v4.view.ViewPager;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.AdapterView;
|
import android.widget.AdapterView;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
import android.widget.Spinner;
|
import android.widget.Spinner;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
@ -25,6 +24,7 @@ public class MainIntroActivity extends IntroActivity {
|
||||||
private Settings settings;
|
private Settings settings;
|
||||||
|
|
||||||
private EncryptionFragment encryptionFragment;
|
private EncryptionFragment encryptionFragment;
|
||||||
|
private AuthenticationFragment authenticationFragment;
|
||||||
|
|
||||||
@Override protected void onCreate(Bundle savedInstanceState){
|
@Override protected void onCreate(Bundle savedInstanceState){
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
@ -32,6 +32,15 @@ public class MainIntroActivity extends IntroActivity {
|
||||||
settings = new Settings(this);
|
settings = new Settings(this);
|
||||||
|
|
||||||
encryptionFragment = new EncryptionFragment();
|
encryptionFragment = new EncryptionFragment();
|
||||||
|
authenticationFragment = new AuthenticationFragment();
|
||||||
|
|
||||||
|
encryptionFragment.setEncryptionChangedCallback(new EncryptionFragment.EncryptionChangedCallback() {
|
||||||
|
@Override
|
||||||
|
public void onEncryptionChanged(Constants.EncryptionType newEncryptionType) {
|
||||||
|
authenticationFragment.updateEncryptionType(newEncryptionType);
|
||||||
|
settings.setEncryption(newEncryptionType);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
setButtonBackFunction(BUTTON_BACK_FUNCTION_BACK);
|
setButtonBackFunction(BUTTON_BACK_FUNCTION_BACK);
|
||||||
|
|
||||||
|
@ -53,36 +62,12 @@ public class MainIntroActivity extends IntroActivity {
|
||||||
.build()
|
.build()
|
||||||
);
|
);
|
||||||
|
|
||||||
// TODO: Set authentication
|
addSlide(new FragmentSlide.Builder()
|
||||||
addSlide(new SimpleSlide.Builder()
|
|
||||||
.title(R.string.intro_slide1_title)
|
|
||||||
.description(R.string.intro_slide1_desc)
|
|
||||||
.image(R.mipmap.ic_launcher)
|
|
||||||
.background(R.color.colorPrimary)
|
.background(R.color.colorPrimary)
|
||||||
.backgroundDark(R.color.colorPrimaryDark)
|
.backgroundDark(R.color.colorPrimaryDark)
|
||||||
.scrollable(false)
|
.fragment(authenticationFragment)
|
||||||
.build()
|
.build()
|
||||||
);
|
);
|
||||||
|
|
||||||
addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
|
|
||||||
@Override
|
|
||||||
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPageSelected(int position) {
|
|
||||||
if (position == 2) {
|
|
||||||
// TODO: Inter-page communication
|
|
||||||
settings.setEncryption(encryptionFragment.getSelectedEncryption());
|
|
||||||
Log.d("INTRO", "Encryption saved");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPageScrollStateChanged(int state) {
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -92,6 +77,8 @@ public class MainIntroActivity extends IntroActivity {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class EncryptionFragment extends SlideFragment {
|
public static class EncryptionFragment extends SlideFragment {
|
||||||
|
private EncryptionChangedCallback encryptionChangedCallback = null;
|
||||||
|
|
||||||
private Spinner selection;
|
private Spinner selection;
|
||||||
private TextView desc;
|
private TextView desc;
|
||||||
|
|
||||||
|
@ -100,6 +87,10 @@ public class MainIntroActivity extends IntroActivity {
|
||||||
public EncryptionFragment() {
|
public EncryptionFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setEncryptionChangedCallback(EncryptionChangedCallback cb) {
|
||||||
|
encryptionChangedCallback = cb;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
|
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
|
||||||
Bundle savedInstanceState) {
|
Bundle savedInstanceState) {
|
||||||
|
@ -108,7 +99,7 @@ public class MainIntroActivity extends IntroActivity {
|
||||||
selection = root.findViewById(R.id.introEncryptionSelection);
|
selection = root.findViewById(R.id.introEncryptionSelection);
|
||||||
desc = root.findViewById(R.id.introEncryptionDesc);
|
desc = root.findViewById(R.id.introEncryptionDesc);
|
||||||
|
|
||||||
final String[] encValues = getResources().getStringArray(R.array.settings_values_encryption);
|
String[] encValues = getResources().getStringArray(R.array.settings_values_encryption);
|
||||||
|
|
||||||
selectionMapping = new SparseArray<>();
|
selectionMapping = new SparseArray<>();
|
||||||
for (int i = 0; i < encValues.length; i++)
|
for (int i = 0; i < encValues.length; i++)
|
||||||
|
@ -123,6 +114,9 @@ public class MainIntroActivity extends IntroActivity {
|
||||||
desc.setText(R.string.intro_slide2_desc_password);
|
desc.setText(R.string.intro_slide2_desc_password);
|
||||||
else if (encryptionType == Constants.EncryptionType.KEYSTORE)
|
else if (encryptionType == Constants.EncryptionType.KEYSTORE)
|
||||||
desc.setText(R.string.intro_slide2_desc_keystore);
|
desc.setText(R.string.intro_slide2_desc_keystore);
|
||||||
|
|
||||||
|
if (encryptionChangedCallback != null)
|
||||||
|
encryptionChangedCallback.onEncryptionChanged(encryptionType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -133,8 +127,78 @@ public class MainIntroActivity extends IntroActivity {
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Constants.EncryptionType getSelectedEncryption() {
|
public interface EncryptionChangedCallback {
|
||||||
return selectionMapping.get(selection.getSelectedItemPosition());
|
void onEncryptionChanged(Constants.EncryptionType newEncryptionType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class AuthenticationFragment extends SlideFragment {
|
||||||
|
private Constants.EncryptionType encryptionType = Constants.EncryptionType.KEYSTORE;
|
||||||
|
|
||||||
|
private TextView desc = null;
|
||||||
|
private Spinner selection = null;
|
||||||
|
|
||||||
|
private SparseArray<Constants.AuthMethod> selectionMapping;
|
||||||
|
|
||||||
|
public AuthenticationFragment() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateEncryptionType(Constants.EncryptionType encryptionType) {
|
||||||
|
this.encryptionType = encryptionType;
|
||||||
|
|
||||||
|
if (desc != null) {
|
||||||
|
if (encryptionType == Constants.EncryptionType.KEYSTORE) {
|
||||||
|
desc.setText(R.string.intro_slide3_desc_keystore);
|
||||||
|
} else if (encryptionType == Constants.EncryptionType.PASSWORD) {
|
||||||
|
desc.setText(R.string.intro_slide3_desc_password);
|
||||||
|
|
||||||
|
Constants.AuthMethod selectedMethod = selectionMapping.get(selection.getSelectedItemPosition());
|
||||||
|
if (selectedMethod != Constants.AuthMethod.PASSWORD && selectedMethod != Constants.AuthMethod.PIN )
|
||||||
|
selection.setSelection(selectionMapping.indexOfValue(Constants.AuthMethod.PASSWORD));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
|
||||||
|
Bundle savedInstanceState) {
|
||||||
|
View root = inflater.inflate(R.layout.component_intro_authentication, container, false);
|
||||||
|
|
||||||
|
desc = root.findViewById(R.id.introAuthDesc);
|
||||||
|
selection = root.findViewById(R.id.introAuthSelection);
|
||||||
|
|
||||||
|
Constants.AuthMethod[] authValues = Constants.AuthMethod.values();
|
||||||
|
String[] authEntries = getResources().getStringArray(R.array.settings_entries_auth);
|
||||||
|
|
||||||
|
selectionMapping = new SparseArray<>();
|
||||||
|
for (int i = 0; i < authValues.length; i++)
|
||||||
|
selectionMapping.put(i, authValues[i]);
|
||||||
|
|
||||||
|
ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<String>(getIntroActivity(), android.R.layout.simple_spinner_item, authEntries) {
|
||||||
|
@Override
|
||||||
|
public boolean isEnabled(int position){
|
||||||
|
return encryptionType != Constants.EncryptionType.PASSWORD ||
|
||||||
|
position == selectionMapping.indexOfValue(Constants.AuthMethod.PASSWORD) ||
|
||||||
|
position == selectionMapping.indexOfValue(Constants.AuthMethod.PIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View getDropDownView(int position, View convertView, @NonNull ViewGroup parent) {
|
||||||
|
View view = super.getDropDownView(position, convertView, parent);
|
||||||
|
TextView tv = (TextView) view;
|
||||||
|
|
||||||
|
tv.setEnabled(encryptionType != Constants.EncryptionType.PASSWORD ||
|
||||||
|
position == selectionMapping.indexOfValue(Constants.AuthMethod.PASSWORD) ||
|
||||||
|
position == selectionMapping.indexOfValue(Constants.AuthMethod.PIN));
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||||
|
selection.setAdapter(spinnerArrayAdapter);
|
||||||
|
|
||||||
|
return root;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
79
app/src/main/res/layout/component_intro_authentication.xml
Normal file
79
app/src/main/res/layout/component_intro_authentication.xml
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:gravity="center"
|
||||||
|
android:padding="@dimen/activity_margin_large">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Headline"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:text="@string/settings_title_auth" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/introAuthDesc"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="@dimen/activity_margin"
|
||||||
|
android:text="@string/intro_slide3_desc_keystore"/>
|
||||||
|
|
||||||
|
<Spinner
|
||||||
|
android:id="@+id/introAuthSelection"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="@dimen/activity_margin_large"
|
||||||
|
android:layout_marginStart="@dimen/activity_margin"
|
||||||
|
android:layout_marginEnd="@dimen/activity_margin"
|
||||||
|
android:entries="@array/settings_entries_auth" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/introCredentialsLayout"
|
||||||
|
android:visibility="invisible"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginTop="@dimen/activity_margin_large"
|
||||||
|
android:paddingStart="@dimen/activity_margin"
|
||||||
|
android:paddingEnd="@dimen/activity_margin">
|
||||||
|
|
||||||
|
<android.support.design.widget.TextInputLayout
|
||||||
|
android:id="@+id/introPasswordLayout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/settings_hint_password"
|
||||||
|
app:passwordToggleEnabled="true" >
|
||||||
|
|
||||||
|
<android.support.design.widget.TextInputEditText
|
||||||
|
android:id="@+id/introPasswordEdit"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:inputType="textPassword" />
|
||||||
|
|
||||||
|
</android.support.design.widget.TextInputLayout>
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/introPasswordConfirm"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/settings_hint_password_confirm"
|
||||||
|
android:inputType="textPassword" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/introPasswordToShortWarning"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:paddingBottom="@dimen/activity_margin"
|
||||||
|
android:paddingTop="@dimen/activity_margin"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:text="@string/settings_label_short_password" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
|
@ -4,7 +4,7 @@
|
||||||
<string name="intro_slide1_desc">This wizard will guide you through the initial setup.</string>
|
<string name="intro_slide1_desc">This wizard will guide you through the initial setup.</string>
|
||||||
|
|
||||||
<string name="intro_slide2_desc">To ensure the security of your accounts andOTP only stores them
|
<string name="intro_slide2_desc">To ensure the security of your accounts andOTP only stores them
|
||||||
in encrypted data files. Here you can choose which method of encryption will be used:</string>
|
in encrypted data files. Here you can choose which method of encryption will be used.</string>
|
||||||
<string name="intro_slide2_desc_keystore">The KeyStore is a system component of Android for
|
<string name="intro_slide2_desc_keystore">The KeyStore is a system component of Android for
|
||||||
securely storing cryptographic keys. The advantage of this method is that the keys are
|
securely storing cryptographic keys. The advantage of this method is that the keys are
|
||||||
stored separated from the data files and can be backed by hardware cryptography (if your
|
stored separated from the data files and can be backed by hardware cryptography (if your
|
||||||
|
@ -18,4 +18,10 @@
|
||||||
generated from a password or PIN. The main advantage here is that this will work with
|
generated from a password or PIN. The main advantage here is that this will work with
|
||||||
external backup solutions (like Titanium). However, you will have to enter your credentials
|
external backup solutions (like Titanium). However, you will have to enter your credentials
|
||||||
every time you start andOTP.</string>
|
every time you start andOTP.</string>
|
||||||
|
|
||||||
|
<string name="intro_slide3_desc_keystore">Here you can setup an authentication to lock andOTP.
|
||||||
|
Since you have chosen <b>Android KeyStore</b> as encryption method this is optional.</string>
|
||||||
|
<string name="intro_slide3_desc_password">Here you can setup an authentication to lock andOTP.
|
||||||
|
Since you have chosen <b>Password / PIN</b> as encryption method you need to set either a
|
||||||
|
password or a PIN to proceed.</string>
|
||||||
</resources>
|
</resources>
|
Loading…
Reference in a new issue