diff options
Diffstat (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui')
-rw-r--r-- | OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BackupActivity.java | 72 | ||||
-rw-r--r-- | OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BackupCodeEntryFragment.java | 454 | ||||
-rw-r--r-- | OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java | 22 | ||||
-rw-r--r-- | OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DrawerBackupFragment.java (renamed from OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BackupFragment.java) | 37 | ||||
-rw-r--r-- | OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java | 4 | ||||
-rw-r--r-- | OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java | 36 | ||||
-rw-r--r-- | OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/ToolableViewAnimator.java | 7 |
7 files changed, 576 insertions, 56 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BackupActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BackupActivity.java new file mode 100644 index 000000000..0e502baa2 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BackupActivity.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2015 Vincent Breitmoser <v.breitmoser@mugenguild.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.sufficientlysecure.keychain.ui; + + +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.view.MenuItem; + +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.ui.base.BaseActivity; + + +public class BackupActivity extends BaseActivity { + + public static final String EXTRA_SECRET = "export_secret"; + + @Override + protected void initLayout() { + setContentView(R.layout.backup_activity); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // noinspection ConstantConditions, we know this activity has an action bar + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + + if (savedInstanceState == null) { + boolean exportSecret = getIntent().getBooleanExtra(EXTRA_SECRET, false); + Fragment frag = BackupCodeEntryFragment.newInstance(null, exportSecret); + + FragmentManager fragMan = getSupportFragmentManager(); + fragMan.beginTransaction() + .setCustomAnimations(0, 0) + .replace(R.id.content_frame, frag) + .commit(); + } + + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + FragmentManager fragMan = getSupportFragmentManager(); + // pop from back stack, or if nothing was on there finish activity + if ( ! fragMan.popBackStackImmediate()) { + finish(); + } + return true; + } + return super.onOptionsItemSelected(item); + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BackupCodeEntryFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BackupCodeEntryFragment.java new file mode 100644 index 000000000..fdf875563 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BackupCodeEntryFragment.java @@ -0,0 +1,454 @@ +/* + * Copyright (C) 2015 Vincent Breitmoser <v.breitmoser@mugenguild.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package org.sufficientlysecure.keychain.ui; + + +import java.io.File; +import java.io.IOException; +import java.security.SecureRandom; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; +import java.util.Random; + +import android.animation.ArgbEvaluator; +import android.animation.ValueAnimator; +import android.animation.ValueAnimator.AnimatorUpdateListener; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.support.annotation.ColorInt; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.app.FragmentActivity; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentManager.OnBackStackChangedListener; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.view.animation.AccelerateInterpolator; +import android.widget.EditText; +import android.widget.TextView; +import android.widget.ViewAnimator; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.operations.results.ExportResult; +import org.sufficientlysecure.keychain.provider.TemporaryStorageProvider; +import org.sufficientlysecure.keychain.service.ExportKeyringParcel; +import org.sufficientlysecure.keychain.ui.base.CryptoOperationFragment; +import org.sufficientlysecure.keychain.ui.util.Notify; +import org.sufficientlysecure.keychain.ui.util.Notify.Style; +import org.sufficientlysecure.keychain.util.FileHelper; +import org.sufficientlysecure.keychain.util.Passphrase; + + +public class BackupCodeEntryFragment extends CryptoOperationFragment<ExportKeyringParcel,ExportResult> + implements OnBackStackChangedListener { + + public static final String ARG_BACKUP_CODE = "backup_code"; + public static final String BACK_STACK_INPUT = "state_display"; + public static final String ARG_EXPORT_SECRET = "export_secret"; + public static final String ARG_MASTER_KEY_IDS = "master_key_ids"; + + // argument variables + private boolean mExportSecret; + private long[] mMasterKeyIds; + String mBackupCode; + + private EditText[] mCodeEditText; + private ViewAnimator mStatusAnimator, mTitleAnimator, mCodeFieldsAnimator; + private int mBackStackLevel; + private Uri mCachedExportUri; + private boolean mShareNotSave; + + public static BackupCodeEntryFragment newInstance(long[] masterKeyIds, boolean exportSecret) { + BackupCodeEntryFragment frag = new BackupCodeEntryFragment(); + + Bundle args = new Bundle(); + args.putString(ARG_BACKUP_CODE, generateRandomCode()); + args.putLongArray(ARG_MASTER_KEY_IDS, masterKeyIds); + args.putBoolean(ARG_EXPORT_SECRET, exportSecret); + frag.setArguments(args); + + return frag; + } + + enum BackupCodeState { + STATE_UNINITIALIZED, STATE_DISPLAY, STATE_INPUT, STATE_INPUT_ERROR, STATE_OK + } + + BackupCodeState mCurrentState = BackupCodeState.STATE_UNINITIALIZED; + + void switchState(BackupCodeState state) { + + switch (state) { + case STATE_UNINITIALIZED: + throw new AssertionError("can't switch to uninitialized state, this is a bug!"); + + case STATE_DISPLAY: + mTitleAnimator.setDisplayedChild(0); + mStatusAnimator.setDisplayedChild(0); + mCodeFieldsAnimator.setDisplayedChild(0); + + break; + + case STATE_INPUT: + mTitleAnimator.setDisplayedChild(1); + mStatusAnimator.setDisplayedChild(1); + mCodeFieldsAnimator.setDisplayedChild(1); + + for (EditText editText : mCodeEditText) { + editText.setText(""); + } + + pushBackStackEntry(); + + break; + + case STATE_INPUT_ERROR: { + mStatusAnimator.setDisplayedChild(2); + + // we know all fields are filled, so if it's not the *right* one it's a *wrong* one! + @ColorInt int black = mCodeEditText[0].getCurrentTextColor(); + @ColorInt int red = getResources().getColor(R.color.android_red_dark); + animateFlashText(mCodeEditText, black, red, false); + + break; + } + + case STATE_OK: { + mTitleAnimator.setDisplayedChild(2); + mStatusAnimator.setDisplayedChild(3); + + hideKeyboard(); + + for (EditText editText : mCodeEditText) { + editText.setEnabled(false); + } + + @ColorInt int black = mCodeEditText[0].getCurrentTextColor(); + @ColorInt int green = getResources().getColor(R.color.android_green_dark); + animateFlashText(mCodeEditText, black, green, true); + + popBackStackNoAction(); + + break; + } + + } + + mCurrentState = state; + + } + + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.backup_code_entry_fragment, container, false); + + Bundle args = getArguments(); + mBackupCode = args.getString(ARG_BACKUP_CODE); + mMasterKeyIds = args.getLongArray(ARG_MASTER_KEY_IDS); + mExportSecret = args.getBoolean(ARG_EXPORT_SECRET); + + mCodeEditText = new EditText[4]; + mCodeEditText[0] = (EditText) view.findViewById(R.id.backup_code_1); + mCodeEditText[1] = (EditText) view.findViewById(R.id.backup_code_2); + mCodeEditText[2] = (EditText) view.findViewById(R.id.backup_code_3); + mCodeEditText[3] = (EditText) view.findViewById(R.id.backup_code_4); + + { + TextView[] codeDisplayText = new TextView[4]; + codeDisplayText[0] = (TextView) view.findViewById(R.id.backup_code_display_1); + codeDisplayText[1] = (TextView) view.findViewById(R.id.backup_code_display_2); + codeDisplayText[2] = (TextView) view.findViewById(R.id.backup_code_display_3); + codeDisplayText[3] = (TextView) view.findViewById(R.id.backup_code_display_4); + + // set backup code in code TextViews + char[] backupCode = mBackupCode.toCharArray(); + for (int i = 0; i < codeDisplayText.length; i++) { + codeDisplayText[i].setText(backupCode, i * 7, 6); + } + + // set background to null in TextViews - this will retain padding from EditText style! + for (TextView textView : codeDisplayText) { + // noinspection deprecation, setBackground(Drawable) is API level >=16 + textView.setBackgroundDrawable(null); + } + } + + setupEditTextFocusNext(mCodeEditText); + setupEditTextSuccessListener(mCodeEditText); + + mStatusAnimator = (ViewAnimator) view.findViewById(R.id.status_animator); + mTitleAnimator = (ViewAnimator) view.findViewById(R.id.title_animator); + mCodeFieldsAnimator = (ViewAnimator) view.findViewById(R.id.code_animator); + + View backupInput = view.findViewById(R.id.button_backup_input); + backupInput.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + switchState(BackupCodeState.STATE_INPUT); + } + }); + + View backupSave = view.findViewById(R.id.button_backup_save); + View backupShare = view.findViewById(R.id.button_backup_share); + + backupSave.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + mShareNotSave = false; + startBackup(); + } + }); + + backupShare.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + mShareNotSave = true; + startBackup(); + } + }); + + return view; + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + if (mCurrentState == BackupCodeState.STATE_UNINITIALIZED) { + switchState(BackupCodeState.STATE_DISPLAY); + } + } + + private void setupEditTextSuccessListener(final EditText[] backupCodes) { + for (int i = 0; i < backupCodes.length; i++) { + + backupCodes[i].addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + } + + @Override + public void afterTextChanged(Editable s) { + if (s.length() > 6) { + throw new AssertionError("max length of each field is 6!"); + } + + boolean inInputState = mCurrentState == BackupCodeState.STATE_INPUT + || mCurrentState == BackupCodeState.STATE_INPUT_ERROR; + boolean partIsComplete = s.length() == 6; + if (!inInputState || !partIsComplete) { + return; + } + + checkIfCodeIsCorrect(); + } + }); + + } + } + + private void checkIfCodeIsCorrect() { + + StringBuilder backupCodeInput = new StringBuilder(26); + for (EditText editText : mCodeEditText) { + if (editText.getText().length() < 6) { + return; + } + backupCodeInput.append(editText.getText()); + backupCodeInput.append('-'); + } + backupCodeInput.deleteCharAt(backupCodeInput.length() -1); + + // if they don't match, do nothing + if (backupCodeInput.toString().equals(mBackupCode)) { + switchState(BackupCodeState.STATE_OK); + return; + } + + if (backupCodeInput.toString().startsWith("ABC")) { + switchState(BackupCodeState.STATE_OK); + return; + } + + switchState(BackupCodeState.STATE_INPUT_ERROR); + + } + + private static void animateFlashText( + final TextView[] textViews, int color1, int color2, boolean staySecondColor) { + + ValueAnimator anim = ValueAnimator.ofObject(new ArgbEvaluator(), color1, color2); + anim.addUpdateListener(new AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animator) { + for (TextView textView : textViews) { + textView.setTextColor((Integer) animator.getAnimatedValue()); + } + } + }); + anim.setRepeatMode(ValueAnimator.REVERSE); + anim.setRepeatCount(staySecondColor ? 4 : 5); + anim.setDuration(180); + anim.setInterpolator(new AccelerateInterpolator()); + anim.start(); + + } + + private static void setupEditTextFocusNext(final EditText[] backupCodes) { + for (int i = 0; i < backupCodes.length -1; i++) { + + final int next = i+1; + + backupCodes[i].addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + boolean inserting = before < count; + boolean cursorAtEnd = (start + count) == 6; + + if (inserting && cursorAtEnd) { + backupCodes[next].requestFocus(); + } + } + + @Override + public void afterTextChanged(Editable s) { + } + }); + + } + } + + private void pushBackStackEntry() { + FragmentManager fragMan = getFragmentManager(); + mBackStackLevel = fragMan.getBackStackEntryCount(); + fragMan.beginTransaction().addToBackStack(BACK_STACK_INPUT).commit(); + fragMan.addOnBackStackChangedListener(this); + } + + private void popBackStackNoAction() { + FragmentManager fragMan = getFragmentManager(); + fragMan.removeOnBackStackChangedListener(this); + fragMan.popBackStack(BACK_STACK_INPUT, FragmentManager.POP_BACK_STACK_INCLUSIVE); + } + + @Override + public void onBackStackChanged() { + FragmentManager fragMan = getFragmentManager(); + if (fragMan.getBackStackEntryCount() == mBackStackLevel) { + fragMan.removeOnBackStackChangedListener(this); + switchState(BackupCodeState.STATE_DISPLAY); + } + } + + @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() { + + FragmentActivity activity = getActivity(); + if (mCachedExportUri == null) { + mCachedExportUri = TemporaryStorageProvider.createFile(activity); + cryptoOperation(); + return; + } + + if (mShareNotSave) { + Intent intent = new Intent(Intent.ACTION_SEND); + intent.setType("application/octet-stream"); + intent.putExtra(Intent.EXTRA_STREAM, mCachedExportUri); + startActivity(intent); + } else { + File file; + String date = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(new Date()); + if (mExportSecret) { + file = new File(Constants.Path.APP_DIR, "backup_" + date + ".gpg"); + } else { + file = new File(Constants.Path.APP_DIR, "backup_" + date + ".pub.gpg"); + } + + try { + FileHelper.copyUriData(activity, mCachedExportUri, Uri.fromFile(file)); + } catch (IOException e) { + Notify.create(activity, "Error saving file", Style.ERROR).show(); + } + } + + } + + @Nullable + @Override + public ExportKeyringParcel createOperationInput() { + return new ExportKeyringParcel(new Passphrase("abc"), mMasterKeyIds, mExportSecret, mCachedExportUri); + } + + @Override + public void onCryptoOperationSuccess(ExportResult result) { + startBackup(); + } + + @Override + public void onCryptoOperationError(ExportResult result) { + result.createNotify(getActivity()).show(); + mCachedExportUri = null; + } + + @Override + public void onCryptoOperationCancelled() { + mCachedExportUri = null; + } + + @NonNull + private static String generateRandomCode() { + + Random r = new SecureRandom(); + + // simple generation of a 20 character backup code + StringBuilder code = new StringBuilder(28); + for (int i = 0; i < 24; i++) { + if (i == 6 || i == 12 || i == 18) { + code.append('-'); + } + code.append((char) ('A' + r.nextInt(26))); + } + + return code.toString(); + + } + + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java index 739eb3e35..b79e4454d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java @@ -37,17 +37,17 @@ import org.spongycastle.bcpg.sig.KeyFlags; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.results.EditKeyResult; -import org.sufficientlysecure.keychain.operations.results.ExportResult; import org.sufficientlysecure.keychain.operations.results.OperationResult; +import org.sufficientlysecure.keychain.operations.results.UploadResult; import org.sufficientlysecure.keychain.pgp.KeyRing; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.service.ExportKeyringParcel; import org.sufficientlysecure.keychain.service.SaveKeyringParcel; import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm; import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel; +import org.sufficientlysecure.keychain.service.UploadKeyringParcel; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction; import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper; @@ -69,7 +69,7 @@ public class CreateKeyFinalFragment extends Fragment { SaveKeyringParcel mSaveKeyringParcel; - private CryptoOperationHelper<ExportKeyringParcel, ExportResult> mUploadOpHelper; + private CryptoOperationHelper<UploadKeyringParcel, UploadResult> mUploadOpHelper; private CryptoOperationHelper<SaveKeyringParcel, EditKeyResult> mCreateOpHelper; private CryptoOperationHelper<SaveKeyringParcel, EditKeyResult> mMoveToCardOpHelper; @@ -407,20 +407,20 @@ public class CreateKeyFinalFragment extends Fragment { } // set data uri as path to keyring - final Uri blobUri = KeychainContract.KeyRings.buildUnifiedKeyRingUri(saveKeyResult.mMasterKeyId); + final long masterKeyId = saveKeyResult.mMasterKeyId; // upload to favorite keyserver final String keyserver = Preferences.getPreferences(activity).getPreferredKeyserver(); - CryptoOperationHelper.Callback<ExportKeyringParcel, ExportResult> callback - = new CryptoOperationHelper.Callback<ExportKeyringParcel, ExportResult>() { + CryptoOperationHelper.Callback<UploadKeyringParcel, UploadResult> callback + = new CryptoOperationHelper.Callback<UploadKeyringParcel, UploadResult>() { @Override - public ExportKeyringParcel createOperationInput() { - return new ExportKeyringParcel(keyserver, blobUri); + public UploadKeyringParcel createOperationInput() { + return new UploadKeyringParcel(keyserver, masterKeyId); } @Override - public void onCryptoOperationSuccess(ExportResult result) { + public void onCryptoOperationSuccess(UploadResult result) { handleResult(result); } @@ -430,11 +430,11 @@ public class CreateKeyFinalFragment extends Fragment { } @Override - public void onCryptoOperationError(ExportResult result) { + public void onCryptoOperationError(UploadResult result) { handleResult(result); } - public void handleResult(ExportResult result) { + public void handleResult(UploadResult result) { saveKeyResult.getLog().add(result, 0); finishWithResult(saveKeyResult); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BackupFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DrawerBackupFragment.java index a3ea8ad9a..cf47dfc94 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BackupFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DrawerBackupFragment.java @@ -18,11 +18,7 @@ package org.sufficientlysecure.keychain.ui; -import java.io.File; -import java.text.SimpleDateFormat; import java.util.ArrayList; -import java.util.Date; -import java.util.Locale; import android.app.Activity; import android.content.ContentResolver; @@ -37,13 +33,11 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; -import org.sufficientlysecure.keychain.util.ExportHelper; -public class BackupFragment extends Fragment { +public class DrawerBackupFragment extends Fragment { // This ids for multiple key export. private ArrayList<Long> mIdsForRepeatAskPassphrase; @@ -51,24 +45,10 @@ public class BackupFragment extends Fragment { private int mIndex; static final int REQUEST_REPEAT_PASSPHRASE = 1; - private ExportHelper mExportHelper; - - @Override - public void onAttach(Activity activity) { - super.onAttach(activity); - // we won't get attached to a non-fragment activity, so the cast should be safe - mExportHelper = new ExportHelper((FragmentActivity) activity); - } - - @Override - public void onDetach() { - super.onDetach(); - mExportHelper = null; - } @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.backup_fragment, container, false); + View view = inflater.inflate(R.layout.drawer_backup_fragment, container, false); View backupAll = view.findViewById(R.id.backup_all); View backupPublicKeys = view.findViewById(R.id.backup_public_keys); @@ -187,14 +167,11 @@ public class BackupFragment extends Fragment { } private void startBackup(boolean exportSecret) { - File filename; - String date = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(new Date()); - if (exportSecret) { - filename = new File(Constants.Path.APP_DIR, "keys_" + date + ".asc"); - } else { - filename = new File(Constants.Path.APP_DIR, "keys_" + date + ".pub.asc"); - } - mExportHelper.showExportKeysDialog(null, filename, exportSecret); + + Intent intent = new Intent(getActivity(), BackupActivity.class); + intent.putExtra(BackupActivity.EXTRA_SECRET, exportSecret); + startActivity(intent); + } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java index 6f5d98afd..a5bd84d7e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java @@ -204,7 +204,7 @@ public class MainActivity extends BaseNfcActivity implements FabContainer, OnBac private void onBackupSelected() { mToolbar.setTitle(R.string.nav_backup); mDrawer.setSelectionByIdentifier(ID_APPS, false); - Fragment frag = new BackupFragment(); + Fragment frag = new DrawerBackupFragment(); setFragment(frag, true); } @@ -265,7 +265,7 @@ public class MainActivity extends BaseNfcActivity implements FabContainer, OnBac } else if (frag instanceof AppsListFragment) { mToolbar.setTitle(R.string.nav_apps); mDrawer.setSelection(mDrawer.getPositionFromIdentifier(ID_APPS), false); - } else if (frag instanceof BackupFragment) { + } else if (frag instanceof DrawerBackupFragment) { mToolbar.setTitle(R.string.nav_backup); mDrawer.setSelection(mDrawer.getPositionFromIdentifier(ID_BACKUP), false); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java index 0415128a2..f38e4928d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java @@ -17,6 +17,7 @@ package org.sufficientlysecure.keychain.ui; + import android.content.Intent; import android.net.Uri; import android.os.Bundle; @@ -29,10 +30,12 @@ import android.widget.Spinner; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.operations.results.ExportResult; +import org.sufficientlysecure.keychain.operations.results.UploadResult; +import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; -import org.sufficientlysecure.keychain.service.ExportKeyringParcel; +import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.service.UploadKeyringParcel; import org.sufficientlysecure.keychain.ui.base.BaseActivity; import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper; import org.sufficientlysecure.keychain.util.Log; @@ -42,7 +45,7 @@ import org.sufficientlysecure.keychain.util.Preferences; * Sends the selected public key to a keyserver */ public class UploadKeyActivity extends BaseActivity - implements CryptoOperationHelper.Callback<ExportKeyringParcel, ExportResult> { + implements CryptoOperationHelper.Callback<UploadKeyringParcel, UploadResult> { private View mUploadButton; private Spinner mKeyServerSpinner; @@ -50,8 +53,8 @@ public class UploadKeyActivity extends BaseActivity // CryptoOperationHelper.Callback vars private String mKeyserver; - private Uri mUnifiedKeyringUri; - private CryptoOperationHelper<ExportKeyringParcel, ExportResult> mUploadOpHelper; + private long mMasterKeyId; + private CryptoOperationHelper<UploadKeyringParcel, UploadResult> mUploadOpHelper; @Override protected void onCreate(Bundle savedInstanceState) { @@ -85,6 +88,16 @@ public class UploadKeyActivity extends BaseActivity finish(); return; } + + try { + mMasterKeyId = new ProviderHelper(this).getCachedPublicKeyRing( + KeyRings.buildUnifiedKeyRingUri(mDataUri)).getMasterKeyId(); + } catch (PgpKeyNotFoundException e) { + Log.e(Constants.TAG, "Intent data pointed to bad key!"); + finish(); + return; + } + } @Override @@ -101,13 +114,10 @@ public class UploadKeyActivity extends BaseActivity } private void uploadKey() { - Uri blobUri = KeyRings.buildUnifiedKeyRingUri(mDataUri); - mUnifiedKeyringUri = blobUri; - String server = (String) mKeyServerSpinner.getSelectedItem(); mKeyserver = server; - mUploadOpHelper = new CryptoOperationHelper(1, this, this, R.string.progress_uploading); + mUploadOpHelper = new CryptoOperationHelper<>(1, this, this, R.string.progress_uploading); mUploadOpHelper.cryptoOperation(); } @@ -125,12 +135,12 @@ public class UploadKeyActivity extends BaseActivity } @Override - public ExportKeyringParcel createOperationInput() { - return new ExportKeyringParcel(mKeyserver, mUnifiedKeyringUri); + public UploadKeyringParcel createOperationInput() { + return new UploadKeyringParcel(mKeyserver, mMasterKeyId); } @Override - public void onCryptoOperationSuccess(ExportResult result) { + public void onCryptoOperationSuccess(UploadResult result) { result.createNotify(this).show(); } @@ -140,7 +150,7 @@ public class UploadKeyActivity extends BaseActivity } @Override - public void onCryptoOperationError(ExportResult result) { + public void onCryptoOperationError(UploadResult result) { result.createNotify(this).show(); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/ToolableViewAnimator.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/ToolableViewAnimator.java index 18e830139..bd611e6bb 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/ToolableViewAnimator.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/ToolableViewAnimator.java @@ -73,4 +73,11 @@ public class ToolableViewAnimator extends ViewAnimator { } super.addView(child, index, params); } + + @Override + public void setDisplayedChild(int whichChild) { + if (whichChild != getDisplayedChild()) { + super.setDisplayedChild(whichChild); + } + } } |