First part of the authentication slide (WIP)

This commit is contained in:
Jakob Nixdorf 2018-02-27 22:41:32 +01:00
parent 324f84b36c
commit 14a7e2c174
No known key found for this signature in database
GPG key ID: BE99BF86574A7DBC
3 changed files with 181 additions and 32 deletions

View file

@ -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;
} }
} }
} }

View 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>

View file

@ -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>