Create an initial intro screen on first launch
This commit is contained in:
parent
b610afdf93
commit
324f84b36c
9 changed files with 222 additions and 4 deletions
|
@ -25,6 +25,9 @@ android {
|
|||
lintOptions {
|
||||
abortOnError false
|
||||
}
|
||||
dataBinding {
|
||||
enabled = true
|
||||
}
|
||||
}
|
||||
|
||||
ext {
|
||||
|
@ -41,6 +44,7 @@ dependencies {
|
|||
compile "com.android.support:recyclerview-v7:$supportLibVersion"
|
||||
compile "com.android.support.constraint:constraint-layout:1.0.2"
|
||||
compile "com.github.aakira:expandable-layout:1.6.0"
|
||||
compile "com.heinrichreimersoftware:material-intro:1.6.2"
|
||||
compile "com.journeyapps:zxing-android-embedded:3.5.0"
|
||||
compile "com.vanniktech:vntnumberpickerpreference:1.0.0"
|
||||
compile "de.psdev.licensesdialog:licensesdialog:1.8.3"
|
||||
|
|
|
@ -35,6 +35,10 @@
|
|||
android:name=".Activities.BackupActivity"
|
||||
android:parentActivityName=".Activities.MainActivity"
|
||||
android:theme="@style/AppTheme.NoActionBar" />
|
||||
<activity
|
||||
android:name=".Activities.MainIntroActivity"
|
||||
android:parentActivityName=".Activities.MainActivity"
|
||||
android:theme="@style/Theme.Intro" />
|
||||
<activity
|
||||
android:name=".Activities.SettingsActivity"
|
||||
android:parentActivityName=".Activities.MainActivity"
|
||||
|
|
|
@ -103,7 +103,7 @@ public class MainActivity extends BaseActivity
|
|||
.initiateScan();
|
||||
}
|
||||
|
||||
private void showFirstTimeWarning() {
|
||||
/*private void showFirstTimeWarning() {
|
||||
ViewGroup container = findViewById(R.id.main_content);
|
||||
View msgView = getLayoutInflater().inflate(R.layout.dialog_database_encryption, container, false);
|
||||
|
||||
|
@ -135,6 +135,11 @@ public class MainActivity extends BaseActivity
|
|||
})
|
||||
.create()
|
||||
.show();
|
||||
}*/
|
||||
|
||||
private void showFirstTimeWarning() {
|
||||
Intent introIntent = new Intent(this, MainIntroActivity.class);
|
||||
startActivityForResult(introIntent, Constants.INTENT_MAIN_INTRO);
|
||||
}
|
||||
|
||||
public void authenticate(int messageId) {
|
||||
|
|
|
@ -0,0 +1,140 @@
|
|||
package org.shadowice.flocke.andotp.Activities;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.view.ViewPager;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.heinrichreimersoftware.materialintro.app.IntroActivity;
|
||||
import com.heinrichreimersoftware.materialintro.app.SlideFragment;
|
||||
import com.heinrichreimersoftware.materialintro.slide.FragmentSlide;
|
||||
import com.heinrichreimersoftware.materialintro.slide.SimpleSlide;
|
||||
|
||||
import org.shadowice.flocke.andotp.R;
|
||||
import org.shadowice.flocke.andotp.Utilities.Constants;
|
||||
import org.shadowice.flocke.andotp.Utilities.Settings;
|
||||
|
||||
public class MainIntroActivity extends IntroActivity {
|
||||
private Settings settings;
|
||||
|
||||
private EncryptionFragment encryptionFragment;
|
||||
|
||||
@Override protected void onCreate(Bundle savedInstanceState){
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
settings = new Settings(this);
|
||||
|
||||
encryptionFragment = new EncryptionFragment();
|
||||
|
||||
setButtonBackFunction(BUTTON_BACK_FUNCTION_BACK);
|
||||
|
||||
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)
|
||||
.backgroundDark(R.color.colorPrimaryDark)
|
||||
.canGoBackward(false)
|
||||
.scrollable(false)
|
||||
.build()
|
||||
);
|
||||
|
||||
addSlide(new FragmentSlide.Builder()
|
||||
.background(R.color.colorPrimary)
|
||||
.backgroundDark(R.color.colorPrimaryDark)
|
||||
.fragment(encryptionFragment)
|
||||
.build()
|
||||
);
|
||||
|
||||
// TODO: Set authentication
|
||||
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)
|
||||
.backgroundDark(R.color.colorPrimaryDark)
|
||||
.scrollable(false)
|
||||
.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
|
||||
public void onBackPressed() {
|
||||
if (getCurrentSlidePosition() != 0)
|
||||
super.onBackPressed();
|
||||
}
|
||||
|
||||
public static class EncryptionFragment extends SlideFragment {
|
||||
private Spinner selection;
|
||||
private TextView desc;
|
||||
|
||||
private SparseArray<Constants.EncryptionType> selectionMapping;
|
||||
|
||||
public EncryptionFragment() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
View root = inflater.inflate(R.layout.component_intro_encryption, container, false);
|
||||
|
||||
selection = root.findViewById(R.id.introEncryptionSelection);
|
||||
desc = root.findViewById(R.id.introEncryptionDesc);
|
||||
|
||||
final String[] encValues = getResources().getStringArray(R.array.settings_values_encryption);
|
||||
|
||||
selectionMapping = new SparseArray<>();
|
||||
for (int i = 0; i < encValues.length; i++)
|
||||
selectionMapping.put(i, Constants.EncryptionType.valueOf(encValues[i].toUpperCase()));
|
||||
|
||||
selection.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
|
||||
Constants.EncryptionType encryptionType = selectionMapping.get(i);
|
||||
|
||||
if (encryptionType == Constants.EncryptionType.PASSWORD)
|
||||
desc.setText(R.string.intro_slide2_desc_password);
|
||||
else if (encryptionType == Constants.EncryptionType.KEYSTORE)
|
||||
desc.setText(R.string.intro_slide2_desc_keystore);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> adapterView) {
|
||||
}
|
||||
});
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
private Constants.EncryptionType getSelectedEncryption() {
|
||||
return selectionMapping.get(selection.getSelectedItemPosition());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -52,6 +52,7 @@ public class Constants {
|
|||
public final static int INTENT_MAIN_AUTHENTICATE = 100;
|
||||
public final static int INTENT_MAIN_SETTINGS = 101;
|
||||
public final static int INTENT_MAIN_BACKUP = 102;
|
||||
public final static int INTENT_MAIN_INTRO = 103;
|
||||
|
||||
public final static int INTENT_BACKUP_OPEN_DOCUMENT_PLAIN = 200;
|
||||
public final static int INTENT_BACKUP_SAVE_DOCUMENT_PLAIN = 201;
|
||||
|
|
|
@ -290,6 +290,10 @@ public class Settings {
|
|||
return EncryptionType.valueOf(encType.toUpperCase());
|
||||
}
|
||||
|
||||
public void setEncryption(EncryptionType encryptionType) {
|
||||
setEncryption(encryptionType.name().toLowerCase());
|
||||
}
|
||||
|
||||
public void setEncryption(String encryption) {
|
||||
setString(R.string.settings_key_encryption, encryption);
|
||||
}
|
||||
|
|
40
app/src/main/res/layout/component_intro_encryption.xml
Normal file
40
app/src/main/res/layout/component_intro_encryption.xml
Normal file
|
@ -0,0 +1,40 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
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_encryption" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/activity_margin"
|
||||
android:text="@string/intro_slide2_desc"/>
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/introEncryptionSelection"
|
||||
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_encryption" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/introEncryptionDesc"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="@dimen/activity_margin_large"
|
||||
android:text="@string/intro_slide2_desc_keystore"/>
|
||||
|
||||
</LinearLayout>
|
21
app/src/main/res/values/strings_intro.xml
Normal file
21
app/src/main/res/values/strings_intro.xml
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="intro_slide1_title">Welcome to andOTP</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
|
||||
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
|
||||
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
|
||||
device supports it). However, as the keys are not stored with the apps data <b>this method
|
||||
prevents external backup solutions (like Titanium) from working</b>. If you choose this
|
||||
method you will have to rely on the internal backup functions provided by andOTP.
|
||||
\n\n<b>Warning</b>: The KeyStore is known to cause problems on some custom ROMs (and a few
|
||||
stock ones as well). If you don\'t mind entering a password / PIN every time you start
|
||||
andOTP it is highly recommended to use the password-based encryption.</string>
|
||||
<string name="intro_slide2_desc_password">This method will encrypt your data with a key
|
||||
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
|
||||
every time you start andOTP.</string>
|
||||
</resources>
|
|
@ -18,9 +18,8 @@ buildscript {
|
|||
allprojects {
|
||||
repositories {
|
||||
jcenter()
|
||||
maven {
|
||||
url "https://maven.google.com"
|
||||
}
|
||||
maven { url "https://maven.google.com" }
|
||||
maven { url "https://jitpack.io" }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue