enc-export: handle onSaveInstanceState, add nicer layout for landscape
This commit is contained in:
@@ -440,7 +440,7 @@
|
|||||||
android:windowSoftInputMode="stateHidden" />
|
android:windowSoftInputMode="stateHidden" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.BackupActivity"
|
android:name=".ui.BackupActivity"
|
||||||
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
|
android:configChanges="keyboardHidden|keyboard"
|
||||||
android:label="@string/title_backup">
|
android:label="@string/title_backup">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ import android.view.ViewGroup;
|
|||||||
import android.view.animation.AccelerateInterpolator;
|
import android.view.animation.AccelerateInterpolator;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.ViewAnimator;
|
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
@@ -59,6 +58,7 @@ import org.sufficientlysecure.keychain.ui.base.CryptoOperationFragment;
|
|||||||
import org.sufficientlysecure.keychain.ui.util.Notify;
|
import org.sufficientlysecure.keychain.ui.util.Notify;
|
||||||
import org.sufficientlysecure.keychain.ui.util.Notify.ActionListener;
|
import org.sufficientlysecure.keychain.ui.util.Notify.ActionListener;
|
||||||
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
|
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
|
||||||
|
import org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator;
|
||||||
import org.sufficientlysecure.keychain.util.FileHelper;
|
import org.sufficientlysecure.keychain.util.FileHelper;
|
||||||
import org.sufficientlysecure.keychain.util.Passphrase;
|
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||||
|
|
||||||
@@ -70,7 +70,11 @@ public class BackupCodeFragment extends CryptoOperationFragment<ExportKeyringPar
|
|||||||
public static final String BACK_STACK_INPUT = "state_display";
|
public static final String BACK_STACK_INPUT = "state_display";
|
||||||
public static final String ARG_EXPORT_SECRET = "export_secret";
|
public static final String ARG_EXPORT_SECRET = "export_secret";
|
||||||
public static final String ARG_MASTER_KEY_IDS = "master_key_ids";
|
public static final String ARG_MASTER_KEY_IDS = "master_key_ids";
|
||||||
public static final int REQUEST_SAVE = 0;
|
|
||||||
|
public static final String ARG_CURRENT_STATE = "current_state";
|
||||||
|
|
||||||
|
public static final int REQUEST_SAVE = 1;
|
||||||
|
public static final String ARG_BACK_STACK = "back_stack";
|
||||||
|
|
||||||
// argument variables
|
// argument variables
|
||||||
private boolean mExportSecret;
|
private boolean mExportSecret;
|
||||||
@@ -78,9 +82,9 @@ public class BackupCodeFragment extends CryptoOperationFragment<ExportKeyringPar
|
|||||||
String mBackupCode;
|
String mBackupCode;
|
||||||
|
|
||||||
private EditText[] mCodeEditText;
|
private EditText[] mCodeEditText;
|
||||||
private ViewAnimator mStatusAnimator, mTitleAnimator, mCodeFieldsAnimator;
|
private ToolableViewAnimator mStatusAnimator, mTitleAnimator, mCodeFieldsAnimator;
|
||||||
|
|
||||||
private int mBackStackLevel;
|
private Integer mBackStackLevel;
|
||||||
|
|
||||||
private Uri mCachedExportUri;
|
private Uri mCachedExportUri;
|
||||||
private boolean mShareNotSave;
|
private boolean mShareNotSave;
|
||||||
@@ -103,23 +107,23 @@ public class BackupCodeFragment extends CryptoOperationFragment<ExportKeyringPar
|
|||||||
|
|
||||||
BackupCodeState mCurrentState = BackupCodeState.STATE_UNINITIALIZED;
|
BackupCodeState mCurrentState = BackupCodeState.STATE_UNINITIALIZED;
|
||||||
|
|
||||||
void switchState(BackupCodeState state) {
|
void switchState(BackupCodeState state, boolean animate) {
|
||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case STATE_UNINITIALIZED:
|
case STATE_UNINITIALIZED:
|
||||||
throw new AssertionError("can't switch to uninitialized state, this is a bug!");
|
throw new AssertionError("can't switch to uninitialized state, this is a bug!");
|
||||||
|
|
||||||
case STATE_DISPLAY:
|
case STATE_DISPLAY:
|
||||||
mTitleAnimator.setDisplayedChild(0);
|
mTitleAnimator.setDisplayedChild(0, animate);
|
||||||
mStatusAnimator.setDisplayedChild(0);
|
mStatusAnimator.setDisplayedChild(0, animate);
|
||||||
mCodeFieldsAnimator.setDisplayedChild(0);
|
mCodeFieldsAnimator.setDisplayedChild(0, animate);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case STATE_INPUT:
|
case STATE_INPUT:
|
||||||
mTitleAnimator.setDisplayedChild(1);
|
mTitleAnimator.setDisplayedChild(1, animate);
|
||||||
mStatusAnimator.setDisplayedChild(1);
|
mStatusAnimator.setDisplayedChild(1, animate);
|
||||||
mCodeFieldsAnimator.setDisplayedChild(1);
|
mCodeFieldsAnimator.setDisplayedChild(1, animate);
|
||||||
|
|
||||||
for (EditText editText : mCodeEditText) {
|
for (EditText editText : mCodeEditText) {
|
||||||
editText.setText("");
|
editText.setText("");
|
||||||
@@ -130,20 +134,25 @@ public class BackupCodeFragment extends CryptoOperationFragment<ExportKeyringPar
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case STATE_INPUT_ERROR: {
|
case STATE_INPUT_ERROR: {
|
||||||
mStatusAnimator.setDisplayedChild(2);
|
mTitleAnimator.setDisplayedChild(1, false);
|
||||||
|
mStatusAnimator.setDisplayedChild(2, animate);
|
||||||
|
mCodeFieldsAnimator.setDisplayedChild(1, false);
|
||||||
|
|
||||||
hideKeyboard();
|
hideKeyboard();
|
||||||
|
|
||||||
@ColorInt int black = mCodeEditText[0].getCurrentTextColor();
|
if (animate) {
|
||||||
@ColorInt int red = getResources().getColor(R.color.android_red_dark);
|
@ColorInt int black = mCodeEditText[0].getCurrentTextColor();
|
||||||
animateFlashText(mCodeEditText, black, red, false);
|
@ColorInt int red = getResources().getColor(R.color.android_red_dark);
|
||||||
|
animateFlashText(mCodeEditText, black, red, false);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case STATE_OK: {
|
case STATE_OK: {
|
||||||
mTitleAnimator.setDisplayedChild(2);
|
mTitleAnimator.setDisplayedChild(2, animate);
|
||||||
mStatusAnimator.setDisplayedChild(3);
|
mStatusAnimator.setDisplayedChild(3, animate);
|
||||||
|
mCodeFieldsAnimator.setDisplayedChild(1, false);
|
||||||
|
|
||||||
hideKeyboard();
|
hideKeyboard();
|
||||||
|
|
||||||
@@ -151,9 +160,15 @@ public class BackupCodeFragment extends CryptoOperationFragment<ExportKeyringPar
|
|||||||
editText.setEnabled(false);
|
editText.setEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ColorInt int black = mCodeEditText[0].getCurrentTextColor();
|
|
||||||
@ColorInt int green = getResources().getColor(R.color.android_green_dark);
|
@ColorInt int green = getResources().getColor(R.color.android_green_dark);
|
||||||
animateFlashText(mCodeEditText, black, green, true);
|
if (animate) {
|
||||||
|
@ColorInt int black = mCodeEditText[0].getCurrentTextColor();
|
||||||
|
animateFlashText(mCodeEditText, black, green, true);
|
||||||
|
} else {
|
||||||
|
for (TextView textView : mCodeEditText) {
|
||||||
|
textView.setTextColor(green);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
popBackStackNoAction();
|
popBackStackNoAction();
|
||||||
|
|
||||||
@@ -204,15 +219,15 @@ public class BackupCodeFragment extends CryptoOperationFragment<ExportKeyringPar
|
|||||||
setupEditTextFocusNext(mCodeEditText);
|
setupEditTextFocusNext(mCodeEditText);
|
||||||
setupEditTextSuccessListener(mCodeEditText);
|
setupEditTextSuccessListener(mCodeEditText);
|
||||||
|
|
||||||
mStatusAnimator = (ViewAnimator) view.findViewById(R.id.status_animator);
|
mStatusAnimator = (ToolableViewAnimator) view.findViewById(R.id.status_animator);
|
||||||
mTitleAnimator = (ViewAnimator) view.findViewById(R.id.title_animator);
|
mTitleAnimator = (ToolableViewAnimator) view.findViewById(R.id.title_animator);
|
||||||
mCodeFieldsAnimator = (ViewAnimator) view.findViewById(R.id.code_animator);
|
mCodeFieldsAnimator = (ToolableViewAnimator) view.findViewById(R.id.code_animator);
|
||||||
|
|
||||||
View backupInput = view.findViewById(R.id.button_backup_input);
|
View backupInput = view.findViewById(R.id.button_backup_input);
|
||||||
backupInput.setOnClickListener(new OnClickListener() {
|
backupInput.setOnClickListener(new OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
switchState(BackupCodeState.STATE_INPUT);
|
switchState(BackupCodeState.STATE_INPUT, true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -249,11 +264,27 @@ public class BackupCodeFragment extends CryptoOperationFragment<ExportKeyringPar
|
|||||||
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
|
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
|
||||||
super.onViewCreated(view, savedInstanceState);
|
super.onViewCreated(view, savedInstanceState);
|
||||||
|
|
||||||
if (mCurrentState == BackupCodeState.STATE_UNINITIALIZED) {
|
if (savedInstanceState != null) {
|
||||||
switchState(BackupCodeState.STATE_DISPLAY);
|
int savedBackStack = savedInstanceState.getInt(ARG_BACK_STACK);
|
||||||
|
if (savedBackStack >= 0) {
|
||||||
|
mBackStackLevel = savedBackStack;
|
||||||
|
// unchecked use, we know that this one is available in onViewCreated
|
||||||
|
getFragmentManager().addOnBackStackChangedListener(this);
|
||||||
|
}
|
||||||
|
BackupCodeState savedState = BackupCodeState.values()[savedInstanceState.getInt(ARG_CURRENT_STATE)];
|
||||||
|
switchState(savedState, false);
|
||||||
|
} else if (mCurrentState == BackupCodeState.STATE_UNINITIALIZED) {
|
||||||
|
switchState(BackupCodeState.STATE_DISPLAY, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSaveInstanceState(Bundle outState) {
|
||||||
|
super.onSaveInstanceState(outState);
|
||||||
|
outState.putInt(ARG_CURRENT_STATE, mCurrentState.ordinal());
|
||||||
|
outState.putInt(ARG_BACK_STACK, mBackStackLevel == null ? -1 : mBackStackLevel);
|
||||||
|
}
|
||||||
|
|
||||||
private void setupEditTextSuccessListener(final EditText[] backupCodes) {
|
private void setupEditTextSuccessListener(final EditText[] backupCodes) {
|
||||||
for (EditText backupCode : backupCodes) {
|
for (EditText backupCode : backupCodes) {
|
||||||
|
|
||||||
@@ -301,17 +332,17 @@ public class BackupCodeFragment extends CryptoOperationFragment<ExportKeyringPar
|
|||||||
|
|
||||||
// if they don't match, do nothing
|
// if they don't match, do nothing
|
||||||
if (backupCodeInput.toString().equals(mBackupCode)) {
|
if (backupCodeInput.toString().equals(mBackupCode)) {
|
||||||
switchState(BackupCodeState.STATE_OK);
|
switchState(BackupCodeState.STATE_OK, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO remove debug code
|
// TODO remove debug code
|
||||||
if (backupCodeInput.toString().startsWith("ABC")) {
|
if (backupCodeInput.toString().startsWith("ABC")) {
|
||||||
switchState(BackupCodeState.STATE_OK);
|
switchState(BackupCodeState.STATE_OK, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switchState(BackupCodeState.STATE_INPUT_ERROR);
|
switchState(BackupCodeState.STATE_INPUT_ERROR, true);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -364,6 +395,9 @@ public class BackupCodeFragment extends CryptoOperationFragment<ExportKeyringPar
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void pushBackStackEntry() {
|
private void pushBackStackEntry() {
|
||||||
|
if (mBackStackLevel != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
FragmentManager fragMan = getFragmentManager();
|
FragmentManager fragMan = getFragmentManager();
|
||||||
mBackStackLevel = fragMan.getBackStackEntryCount();
|
mBackStackLevel = fragMan.getBackStackEntryCount();
|
||||||
fragMan.beginTransaction().addToBackStack(BACK_STACK_INPUT).commit();
|
fragMan.beginTransaction().addToBackStack(BACK_STACK_INPUT).commit();
|
||||||
@@ -373,25 +407,20 @@ public class BackupCodeFragment extends CryptoOperationFragment<ExportKeyringPar
|
|||||||
private void popBackStackNoAction() {
|
private void popBackStackNoAction() {
|
||||||
FragmentManager fragMan = getFragmentManager();
|
FragmentManager fragMan = getFragmentManager();
|
||||||
fragMan.removeOnBackStackChangedListener(this);
|
fragMan.removeOnBackStackChangedListener(this);
|
||||||
fragMan.popBackStack(BACK_STACK_INPUT, FragmentManager.POP_BACK_STACK_INCLUSIVE);
|
fragMan.popBackStackImmediate(BACK_STACK_INPUT, FragmentManager.POP_BACK_STACK_INCLUSIVE);
|
||||||
|
mBackStackLevel = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBackStackChanged() {
|
public void onBackStackChanged() {
|
||||||
FragmentManager fragMan = getFragmentManager();
|
FragmentManager fragMan = getFragmentManager();
|
||||||
if (fragMan.getBackStackEntryCount() == mBackStackLevel) {
|
if (mBackStackLevel != null && fragMan.getBackStackEntryCount() == mBackStackLevel) {
|
||||||
fragMan.removeOnBackStackChangedListener(this);
|
fragMan.removeOnBackStackChangedListener(this);
|
||||||
switchState(BackupCodeState.STATE_DISPLAY);
|
switchState(BackupCodeState.STATE_DISPLAY, true);
|
||||||
|
mBackStackLevel = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onViewStateRestored(@Nullable Bundle savedInstanceState) {
|
|
||||||
super.onViewStateRestored(savedInstanceState);
|
|
||||||
// we don't really save our state, so at least clean this bit up!
|
|
||||||
popBackStackNoAction();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void startBackup() {
|
private void startBackup() {
|
||||||
|
|
||||||
FragmentActivity activity = getActivity();
|
FragmentActivity activity = getActivity();
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import android.support.annotation.NonNull;
|
|||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.view.animation.Animation;
|
||||||
import android.widget.ViewAnimator;
|
import android.widget.ViewAnimator;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
@@ -80,4 +81,22 @@ public class ToolableViewAnimator extends ViewAnimator {
|
|||||||
super.setDisplayedChild(whichChild);
|
super.setDisplayedChild(whichChild);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setDisplayedChild(int whichChild, boolean animate) {
|
||||||
|
if (animate) {
|
||||||
|
setDisplayedChild(whichChild);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Animation savedInAnim = getInAnimation();
|
||||||
|
Animation savedOutAnim = getOutAnimation();
|
||||||
|
setInAnimation(null);
|
||||||
|
setOutAnimation(null);
|
||||||
|
|
||||||
|
setDisplayedChild(whichChild);
|
||||||
|
|
||||||
|
setInAnimation(savedInAnim);
|
||||||
|
setOutAnimation(savedOutAnim);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:paddingTop="50dp">
|
android:paddingTop="20dp">
|
||||||
|
|
||||||
<org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator
|
<org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
@@ -57,7 +57,7 @@
|
|||||||
android:outAnimation="@anim/fade_out"
|
android:outAnimation="@anim/fade_out"
|
||||||
android:layout_marginTop="15dp"
|
android:layout_marginTop="15dp"
|
||||||
android:layout_marginBottom="15dp"
|
android:layout_marginBottom="15dp"
|
||||||
custom:initialView="0">
|
custom:initialView="1">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
@@ -179,7 +179,7 @@
|
|||||||
android:textSize="18dp"
|
android:textSize="18dp"
|
||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
android:inputType="textNoSuggestions|textCapCharacters"
|
android:inputType="textNoSuggestions|textCapCharacters"
|
||||||
android:hint="ABCDEF"
|
android:hint="______"
|
||||||
android:textColorHint="@android:color/transparent"
|
android:textColorHint="@android:color/transparent"
|
||||||
android:maxLength="6"
|
android:maxLength="6"
|
||||||
tools:ignore="HardcodedText,SpUsage"
|
tools:ignore="HardcodedText,SpUsage"
|
||||||
@@ -206,7 +206,7 @@
|
|||||||
android:textSize="18dp"
|
android:textSize="18dp"
|
||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
android:inputType="textNoSuggestions|textCapCharacters"
|
android:inputType="textNoSuggestions|textCapCharacters"
|
||||||
android:hint="ABCDEF"
|
android:hint="______"
|
||||||
android:textColorHint="@android:color/transparent"
|
android:textColorHint="@android:color/transparent"
|
||||||
android:maxLength="6"
|
android:maxLength="6"
|
||||||
tools:ignore="HardcodedText,SpUsage"
|
tools:ignore="HardcodedText,SpUsage"
|
||||||
@@ -233,7 +233,7 @@
|
|||||||
android:textSize="18dp"
|
android:textSize="18dp"
|
||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
android:inputType="textNoSuggestions|textCapCharacters"
|
android:inputType="textNoSuggestions|textCapCharacters"
|
||||||
android:hint="ABCDEF"
|
android:hint="______"
|
||||||
android:textColorHint="@android:color/transparent"
|
android:textColorHint="@android:color/transparent"
|
||||||
android:maxLength="6"
|
android:maxLength="6"
|
||||||
tools:ignore="HardcodedText,SpUsage"
|
tools:ignore="HardcodedText,SpUsage"
|
||||||
@@ -259,7 +259,7 @@
|
|||||||
android:textSize="18dp"
|
android:textSize="18dp"
|
||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
android:inputType="textNoSuggestions|textCapCharacters"
|
android:inputType="textNoSuggestions|textCapCharacters"
|
||||||
android:hint="ABCDEF"
|
android:hint="______"
|
||||||
android:textColorHint="@android:color/transparent"
|
android:textColorHint="@android:color/transparent"
|
||||||
android:maxLength="6"
|
android:maxLength="6"
|
||||||
tools:ignore="HardcodedText,SpUsage"
|
tools:ignore="HardcodedText,SpUsage"
|
||||||
|
|||||||
Reference in New Issue
Block a user