diff --git a/app/build.gradle b/app/build.gradle
index 27c1421e..70372839 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -31,7 +31,6 @@ dependencies {
compile 'com.android.support:recyclerview-v7:25.0.0'
compile 'com.android.support:appcompat-v7:25.0.0'
compile 'com.android.support:design:25.0.0'
- compile 'agency.tango.android:material-intro-screen:0.0.3'
compile 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1'
compile 'me.dm7.barcodescanner:zxing:1.9'
compile 'com.android.support:cardview-v7:25.0.0'
@@ -39,5 +38,6 @@ dependencies {
compile 'com.yarolegovich:lovely-dialog:1.0.4'
compile 'com.mattprecious.swirl:swirl:1.0.0'
compile 'com.madgag.spongycastle:core:1.56.0.0'
+ compile 'com.github.apl-devs:appintro:v4.2.2'
testCompile 'junit:junit:4.12'
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 55887724..c769b8c0 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -30,14 +30,11 @@
-
-
diff --git a/app/src/main/java/me/impy/aegis/CustomAuthenticatedSlide.java b/app/src/main/java/me/impy/aegis/CustomAuthenticatedSlide.java
index b485b82a..5e2b52cf 100644
--- a/app/src/main/java/me/impy/aegis/CustomAuthenticatedSlide.java
+++ b/app/src/main/java/me/impy/aegis/CustomAuthenticatedSlide.java
@@ -2,12 +2,17 @@ package me.impy.aegis;
import android.content.Intent;
import android.os.Bundle;
+import android.support.design.widget.Snackbar;
+import android.support.v4.app.Fragment;
import android.text.Editable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
+import com.github.paolorotolo.appintro.ISlidePolicy;
+import com.github.paolorotolo.appintro.ISlideSelectionListener;
+
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
@@ -17,80 +22,29 @@ import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
-import agency.tango.materialintroscreen.SlideFragment;
import me.impy.aegis.crypto.CryptoUtils;
import me.impy.aegis.crypto.slots.PasswordSlot;
import me.impy.aegis.crypto.slots.Slot;
-public class CustomAuthenticatedSlide extends SlideFragment {
+public class CustomAuthenticatedSlide extends Fragment implements ISlidePolicy, ISlideSelectionListener {
private int cryptType;
private EditText textPassword;
private EditText textPasswordConfirm;
+ private int bgColor;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- View view = inflater.inflate(R.layout.fragment_authenticated_slide, container, false);
+ final View view = inflater.inflate(R.layout.fragment_authenticated_slide, container, false);
textPassword = (EditText) view.findViewById(R.id.text_password);
textPasswordConfirm = (EditText) view.findViewById(R.id.text_password_confirm);
+ view.findViewById(R.id.main).setBackgroundColor(bgColor);
return view;
}
- @Override
- public void setUserVisibleHint(boolean isVisibleToUser) {
- super.setUserVisibleHint(isVisibleToUser);
-
- if (!isVisibleToUser) {
- return;
- }
-
- Intent intent = getActivity().getIntent();
- cryptType = intent.getIntExtra("cryptType", 1337);
-
- switch(cryptType) {
- case CustomAuthenticationSlide.CRYPT_TYPE_NONE:
- break;
- case CustomAuthenticationSlide.CRYPT_TYPE_PASS:
- break;
- case CustomAuthenticationSlide.CRYPT_TYPE_FINGER:
- break;
- default:
- throw new RuntimeException();
- }
- }
-
- @Override
- public int backgroundColor() {
- return R.color.colorHeaderSuccess;
- }
-
- @Override
+ /*@Override
public int buttonsColor() {
return R.color.colorAccent;
- }
-
- @Override
- public boolean canMoveFurther() {
- switch(cryptType) {
- case CustomAuthenticationSlide.CRYPT_TYPE_NONE:
- return true;
- case CustomAuthenticationSlide.CRYPT_TYPE_PASS:
- char[] password = getEditTextChars(textPassword);
- char[] passwordConfirm = getEditTextChars(textPasswordConfirm);
- boolean equal = password.length != 0 && Arrays.equals(password, passwordConfirm);
- CryptoUtils.zero(password);
- CryptoUtils.zero(passwordConfirm);
- return equal;
- case CustomAuthenticationSlide.CRYPT_TYPE_FINGER:
- return false;
- default:
- throw new RuntimeException();
- }
- }
-
- @Override
- public String cantMoveFurtherErrorMessage() {
- return "Passwords should be equal and non-empty";
- }
+ }*/
public int getCryptType() {
return cryptType;
@@ -121,4 +75,57 @@ public class CustomAuthenticatedSlide extends SlideFragment {
editable.getChars(0, editable.length(), chars, 0);
return chars;
}
+
+ @Override
+ public void onSlideSelected() {
+ Intent intent = getActivity().getIntent();
+ cryptType = intent.getIntExtra("cryptType", 1337);
+
+ switch(cryptType) {
+ case CustomAuthenticationSlide.CRYPT_TYPE_NONE:
+ break;
+ case CustomAuthenticationSlide.CRYPT_TYPE_PASS:
+ break;
+ case CustomAuthenticationSlide.CRYPT_TYPE_FINGER:
+ break;
+ default:
+ throw new RuntimeException();
+ }
+ }
+
+ public void setBgColor(int color) {
+ bgColor = color;
+ }
+
+ @Override
+ public void onSlideDeselected() {
+ }
+
+ @Override
+ public boolean isPolicyRespected() {
+ switch(cryptType) {
+ case CustomAuthenticationSlide.CRYPT_TYPE_NONE:
+ return true;
+ case CustomAuthenticationSlide.CRYPT_TYPE_PASS:
+ char[] password = getEditTextChars(textPassword);
+ char[] passwordConfirm = getEditTextChars(textPasswordConfirm);
+ boolean equal = password.length != 0 && Arrays.equals(password, passwordConfirm);
+ CryptoUtils.zero(password);
+ CryptoUtils.zero(passwordConfirm);
+ return equal;
+ case CustomAuthenticationSlide.CRYPT_TYPE_FINGER:
+ return false;
+ default:
+ throw new RuntimeException();
+ }
+ }
+
+ @Override
+ public void onUserIllegallyRequestedNextPage() {
+ View view = getView();
+ if (view != null) {
+ Snackbar snackbar = Snackbar.make(getView(), "Passwords should be equal and non-empty", Snackbar.LENGTH_LONG);
+ snackbar.show();
+ }
+ }
}
diff --git a/app/src/main/java/me/impy/aegis/CustomAuthenticationSlide.java b/app/src/main/java/me/impy/aegis/CustomAuthenticationSlide.java
index f6c9e03e..ca2599ad 100644
--- a/app/src/main/java/me/impy/aegis/CustomAuthenticationSlide.java
+++ b/app/src/main/java/me/impy/aegis/CustomAuthenticationSlide.java
@@ -7,24 +7,28 @@ import android.content.pm.PackageManager;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Build;
import android.os.Bundle;
-import android.support.annotation.IdRes;
+import android.support.design.widget.Snackbar;
import android.support.v4.app.ActivityCompat;
+import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.LinearLayout;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.TextView;
import android.widget.Toast;
-import agency.tango.materialintroscreen.SlideFragment;
+import com.github.paolorotolo.appintro.ISlidePolicy;
-public class CustomAuthenticationSlide extends SlideFragment {
- public static final int CRYPT_TYPE_NONE = 0;
- public static final int CRYPT_TYPE_PASS = 1;
- public static final int CRYPT_TYPE_FINGER = 2;
+public class CustomAuthenticationSlide extends Fragment implements ISlidePolicy {
+ public static final int CRYPT_TYPE_INVALID = 0;
+ public static final int CRYPT_TYPE_NONE = 1;
+ public static final int CRYPT_TYPE_PASS = 2;
+ public static final int CRYPT_TYPE_FINGER = 3;
private RadioGroup buttonGroup;
+ private int bgColor;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
@@ -34,7 +38,7 @@ public class CustomAuthenticationSlide extends SlideFragment {
buttonGroup = (RadioGroup) view.findViewById(R.id.rg_authenticationMethod);
buttonGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
- public void onCheckedChanged(RadioGroup group, @IdRes int checkedId) {
+ public void onCheckedChanged(RadioGroup group, int checkedId) {
if (checkedId == -1) {
return;
}
@@ -72,26 +76,27 @@ public class CustomAuthenticationSlide extends SlideFragment {
}
}
+ view.findViewById(R.id.main).setBackgroundColor(bgColor);
return view;
}
- @Override
- public int backgroundColor() {
- return R.color.colorHeaderSuccess;
+ public void setBgColor(int color) {
+ bgColor = color;
}
@Override
- public int buttonsColor() {
- return R.color.colorAccent;
- }
-
- @Override
- public boolean canMoveFurther() {
+ public boolean isPolicyRespected() {
return buttonGroup.getCheckedRadioButtonId() != -1;
}
@Override
- public String cantMoveFurtherErrorMessage() {
- return "Please select an authentication method";
+ public void onUserIllegallyRequestedNextPage() {
+ Snackbar snackbar = Snackbar.make(getView(), "Please select an authentication method", Snackbar.LENGTH_LONG);
+ snackbar.show();
}
+
+ /*@Override
+ public int buttonsColor() {
+ return R.color.colorAccent;
+ }*/
}
diff --git a/app/src/main/java/me/impy/aegis/EditProfileBottomSheetdialog.java b/app/src/main/java/me/impy/aegis/EditProfileBottomSheetdialog.java
index 1326a605..2599d0ef 100644
--- a/app/src/main/java/me/impy/aegis/EditProfileBottomSheetdialog.java
+++ b/app/src/main/java/me/impy/aegis/EditProfileBottomSheetdialog.java
@@ -1,9 +1,5 @@
package me.impy.aegis;
-import android.app.Dialog;
-import android.content.ClipData;
-import android.content.ClipboardManager;
-import android.content.Context;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.design.widget.BottomSheetDialogFragment;
@@ -11,7 +7,6 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
-import android.widget.Toast;
public class EditProfileBottomSheetdialog extends BottomSheetDialogFragment {
LinearLayout copyLayout;
diff --git a/app/src/main/java/me/impy/aegis/IntroActivity.java b/app/src/main/java/me/impy/aegis/IntroActivity.java
index 88d3be69..79a15193 100644
--- a/app/src/main/java/me/impy/aegis/IntroActivity.java
+++ b/app/src/main/java/me/impy/aegis/IntroActivity.java
@@ -5,17 +5,14 @@ import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
-import android.support.annotation.Nullable;
-import android.view.View;
+import android.support.v4.app.Fragment;
-import java.lang.reflect.UndeclaredThrowableException;
-import java.security.NoSuchAlgorithmException;
+import com.github.paolorotolo.appintro.AppIntro;
+import com.github.paolorotolo.appintro.AppIntroFragment;
+import com.github.paolorotolo.appintro.model.SliderPage;
import javax.crypto.Cipher;
-import agency.tango.materialintroscreen.MaterialIntroActivity;
-import agency.tango.materialintroscreen.MessageButtonBehaviour;
-import agency.tango.materialintroscreen.SlideFragmentBuilder;
import me.impy.aegis.crypto.CryptResult;
import me.impy.aegis.crypto.MasterKey;
import me.impy.aegis.crypto.slots.PasswordSlot;
@@ -23,63 +20,77 @@ import me.impy.aegis.crypto.slots.SlotCollection;
import me.impy.aegis.db.Database;
import me.impy.aegis.db.DatabaseFile;
-public class IntroActivity extends MaterialIntroActivity {
+public class IntroActivity extends AppIntro {
public static final int RESULT_OK = 0;
public static final int RESULT_EXCEPTION = 1;
private CustomAuthenticatedSlide authenticatedSlide;
+ private CustomAuthenticationSlide authenticationSlide;
+ private Fragment endSlide;
@Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
+ protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- hideBackButton();
+ showSkipButton(false);
+ //showPagerIndicator(false);
+ setGoBackLock(true);
+ // TODO: remove this once github.com/apl-devs/AppIntro/issues/347 is fixed
+ setSwipeLock(true);
- addSlide(new SlideFragmentBuilder()
- .backgroundColor(R.color.colorPrimary)
- .buttonsColor(R.color.colorAccent)
- .image(R.drawable.intro_shield)
- .title("Welcome")
- .description("Aegis is a brand new open source(!) authenticator app which generates tokens for your accounts.")
- .build());
+ SliderPage homeSliderPage = new SliderPage();
+ homeSliderPage.setTitle("Welcome");
+ homeSliderPage.setDescription("Aegis is a secure, free and open source 2FA app");
+ homeSliderPage.setImageDrawable(R.drawable.intro_shield);
+ homeSliderPage.setBgColor(getResources().getColor(R.color.colorPrimary));
+ addSlide(AppIntroFragment.newInstance(homeSliderPage));
- addSlide(new SlideFragmentBuilder()
- .backgroundColor(R.color.colorAccent)
- .buttonsColor(R.color.colorPrimary)
- .neededPermissions(new String[]{Manifest.permission.CAMERA})
- .image(R.drawable.intro_scanner)
- .title("Permissions")
- .description("Aegis needs permission to your camera in order to function properly. This is needed to scan QR codes.")
- .build(),
- new MessageButtonBehaviour(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
-
- }
- }, "Permission granted"));
-
- addSlide(new CustomAuthenticationSlide());
+ SliderPage permSliderPage = new SliderPage();
+ permSliderPage.setTitle("Permissions");
+ permSliderPage.setDescription("Aegis needs permission to use your camera in order to scan QR codes.");
+ permSliderPage.setImageDrawable(R.drawable.intro_scanner);
+ permSliderPage.setBgColor(getResources().getColor(R.color.colorAccent));
+ addSlide(AppIntroFragment.newInstance(permSliderPage));
+ askForPermissions(new String[]{Manifest.permission.CAMERA}, 2);
+ authenticationSlide = new CustomAuthenticationSlide();
+ authenticationSlide.setBgColor(getResources().getColor(R.color.colorHeaderSuccess));
+ addSlide(authenticationSlide);
authenticatedSlide = new CustomAuthenticatedSlide();
+ authenticatedSlide.setBgColor(getResources().getColor(R.color.colorPrimary));
addSlide(authenticatedSlide);
- addSlide(new SlideFragmentBuilder()
- .backgroundColor(R.color.colorPrimary)
- .buttonsColor(R.color.colorAccent)
- .image(R.drawable.intro_shield)
- .title("All done!")
- .description("Aegis has been set up and is ready to go.")
- .build());
+ SliderPage endSliderPage = new SliderPage();
+ endSliderPage.setTitle("All done!");
+ endSliderPage.setDescription("Aegis has been set up and is ready to go.");
+ endSliderPage.setImageDrawable(R.drawable.intro_shield);
+ endSliderPage.setBgColor(getResources().getColor(R.color.colorPrimary));
+ endSlide = AppIntroFragment.newInstance(endSliderPage);
+ addSlide(endSlide);
}
private void setException(Exception e) {
Intent result = new Intent();
result.putExtra("exception", e);
setResult(RESULT_EXCEPTION, result);
+ finish();
}
@Override
- public void onFinish() {
- super.onFinish();
+ public void onSlideChanged(Fragment oldFragment, Fragment newFragment) {
+ // skip to the last slide if no encryption will be used
+ if (oldFragment == authenticationSlide && newFragment != endSlide) {
+ Intent intent = getIntent();
+ int cryptType = intent.getIntExtra("cryptType", CustomAuthenticationSlide.CRYPT_TYPE_INVALID);
+ if (cryptType == CustomAuthenticationSlide.CRYPT_TYPE_NONE) {
+ // TODO: no magic indices
+ getPager().setCurrentItem(5);
+ }
+ }
+ }
+
+ @Override
+ public void onDonePressed(Fragment currentFragment) {
+ super.onDonePressed(currentFragment);
// create the database and database file
Database database = new Database();
@@ -142,5 +153,6 @@ public class IntroActivity extends MaterialIntroActivity {
// TODO: show the intro if we can't find any database files
SharedPreferences prefs = this.getSharedPreferences("me.impy.aegis", Context.MODE_PRIVATE);
prefs.edit().putBoolean("passedIntro", true).apply();
+ finish();
}
}
diff --git a/app/src/main/java/me/impy/aegis/MainActivity.java b/app/src/main/java/me/impy/aegis/MainActivity.java
index 3871ab36..62925152 100644
--- a/app/src/main/java/me/impy/aegis/MainActivity.java
+++ b/app/src/main/java/me/impy/aegis/MainActivity.java
@@ -409,9 +409,4 @@ public class MainActivity extends AppCompatActivity {
e.printStackTrace();
}
}
-
- private boolean causeIsKeyUserNotAuthenticated(Exception e) {
- // TODO: is there a way to catch "Key user not authenticated" specifically aside from checking the exception message?
- return e.getCause().getMessage().equals("Key user not authenticated");
- }
}
diff --git a/app/src/main/java/me/impy/aegis/SetPasswordActivity.java b/app/src/main/java/me/impy/aegis/SetPasswordActivity.java
deleted file mode 100644
index 879a2dea..00000000
--- a/app/src/main/java/me/impy/aegis/SetPasswordActivity.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package me.impy.aegis;
-
-import android.support.v7.app.AppCompatActivity;
-import android.os.Bundle;
-
-public class SetPasswordActivity extends AppCompatActivity {
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_set_password);
- }
-}
diff --git a/app/src/main/res/layout/activity_intro.xml b/app/src/main/res/layout/activity_intro.xml
index c7b5f978..3882726a 100644
--- a/app/src/main/res/layout/activity_intro.xml
+++ b/app/src/main/res/layout/activity_intro.xml
@@ -1,35 +1,10 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/activity_set_password.xml b/app/src/main/res/layout/activity_set_password.xml
deleted file mode 100644
index 11394179..00000000
--- a/app/src/main/res/layout/activity_set_password.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/content_intro.xml b/app/src/main/res/layout/content_intro.xml
deleted file mode 100644
index 3edcaaa5..00000000
--- a/app/src/main/res/layout/content_intro.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
diff --git a/app/src/main/res/layout/fragment_authenticated_slide.xml b/app/src/main/res/layout/fragment_authenticated_slide.xml
index d872250a..65f0c990 100644
--- a/app/src/main/res/layout/fragment_authenticated_slide.xml
+++ b/app/src/main/res/layout/fragment_authenticated_slide.xml
@@ -1,75 +1,64 @@
-
+ android:padding="32dp">
+
+
+ android:layout_marginTop="12dp">
+ android:layout_alignParentTop="true"
+ android:layout_alignParentStart="true"
+ android:id="@+id/textView4"
+ android:text="@string/set_password"/>
-
+ android:layout_height="wrap_content"
+ android:inputType="textPassword"
+ android:ems="10"
+ android:id="@+id/text_password"
+ android:layout_below="@+id/textView3"
+ android:layout_alignParentStart="true"
+ android:layout_marginTop="10dp"
+ android:layout_alignParentEnd="true"/>
-
+
-
-
-
-
-
-
-
+
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/fragment_authentication_slide.xml b/app/src/main/res/layout/fragment_authentication_slide.xml
index 5c8237bc..95336507 100644
--- a/app/src/main/res/layout/fragment_authentication_slide.xml
+++ b/app/src/main/res/layout/fragment_authentication_slide.xml
@@ -1,100 +1,88 @@
-
+ android:padding="32dp">
+
+
+ android:layout_height="200dp"
+ android:layout_marginTop="12dp">
-
+ android:id="@+id/rg_authenticationMethod"
+ android:layout_height="187dp">
-
+
-
+ android:textColor="@color/secondary_text_inverted"
+ android:layout_marginTop="-5dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="32dp"
+ />
-
+
-
+
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
+
-
\ No newline at end of file
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index e9ddc6a8..df562fbc 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -24,6 +24,11 @@
- @null
+
+