Actually save key in identity select dialog, and some more design updates

This commit is contained in:
Vincent Breitmoser 2018-03-30 22:20:44 +02:00
parent b92ff86988
commit 336c43cfde
6 changed files with 286 additions and 57 deletions

View file

@ -31,6 +31,7 @@ import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Drawable.ConstantState;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.annotation.NonNull;
import android.support.transition.Fade;
import android.support.transition.Transition;
@ -50,18 +51,26 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.PopupMenu;
import android.widget.PopupMenu.OnDismissListener;
import android.widget.TextView;
import android.widget.Toast;
import com.mikepenz.materialdrawer.util.KeyboardUtil;
import org.openintents.openpgp.util.OpenPgpApi;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.livedata.KeyInfoInteractor.KeyInfo;
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
import org.sufficientlysecure.keychain.remote.ui.dialog.RemoteSelectIdentityKeyPresenter.RemoteSelectIdentityKeyView;
import org.sufficientlysecure.keychain.service.ImportKeyringParcel;
import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper;
import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper.AbstractCallback;
import org.sufficientlysecure.keychain.ui.dialog.CustomAlertDialogBuilder;
import org.sufficientlysecure.keychain.ui.util.ThemeChanger;
import org.sufficientlysecure.keychain.ui.util.recyclerview.DividerItemDecoration;
import org.sufficientlysecure.keychain.ui.util.recyclerview.RecyclerItemClickListener;
import org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator;
import timber.log.Timber;
public class RemoteSelectIdKeyActivity extends FragmentActivity {
@ -71,6 +80,7 @@ public class RemoteSelectIdKeyActivity extends FragmentActivity {
private RemoteSelectIdentityKeyPresenter presenter;
private Parcelable currentlyImportingParcel;
@Override
@ -115,6 +125,7 @@ public class RemoteSelectIdKeyActivity extends FragmentActivity {
private View buttonNoKeysCancel;
private View buttonNoKeysExisting;
private View buttonKeyListOther;
private View buttonOverflow;
@NonNull
@Override
@ -129,6 +140,8 @@ public class RemoteSelectIdKeyActivity extends FragmentActivity {
ViewGroup view = (ViewGroup) layoutInflater.inflate(R.layout.api_select_identity_key, null, false);
alert.setView(view);
buttonOverflow = view.findViewById(R.id.overflow_menu);
buttonKeyListCancel = view.findViewById(R.id.button_key_list_cancel);
buttonKeyListOther = view.findViewById(R.id.button_key_list_other);
@ -182,7 +195,7 @@ public class RemoteSelectIdKeyActivity extends FragmentActivity {
@NonNull
private RemoteSelectIdentityKeyView createMvpView(final ViewGroup rootView, LayoutInflater layoutInflater) {
final ImageView iconClientApp = rootView.findViewById(R.id.icon_client_app);
// final ImageView iconClientApp = rootView.findViewById(R.id.icon_client_app);
final KeyChoiceAdapter keyChoiceAdapter = new KeyChoiceAdapter(layoutInflater, getResources());
final TextView titleText = rootView.findViewById(R.id.text_title_select_key);
final TextView addressText = rootView.findViewById(R.id.text_user_id);
@ -217,7 +230,7 @@ public class RemoteSelectIdKeyActivity extends FragmentActivity {
@Override
public void setTitleClientIconAndName(Drawable drawable, CharSequence name) {
titleText.setText(getString(R.string.title_select_key, name));
iconClientApp.setImageDrawable(drawable);
// iconClientApp.setImageDrawable(drawable);
setSelectionIcons(drawable);
}
@ -270,6 +283,11 @@ public class RemoteSelectIdKeyActivity extends FragmentActivity {
layoutAnimator.setDisplayedChildId(R.id.select_key_layout_generate_ok);
}
@Override
public void showLayoutGenerateSave() {
layoutAnimator.setDisplayedChildId(R.id.select_key_layout_generate_save);
}
@Override
public void setKeyListData(List<KeyInfo> data) {
keyChoiceAdapter.setData(data);
@ -292,10 +310,26 @@ public class RemoteSelectIdKeyActivity extends FragmentActivity {
buttonKeyListCancel.setVisibility(View.INVISIBLE);
keyChoiceAdapter.setActiveItem(position);
}
@Override
public void showImportInternalError() {
Toast.makeText(getContext(), R.string.error_save_key_internal, Toast.LENGTH_LONG).show();
}
@Override
public void launchImportOperation(ImportKeyringParcel importKeyringParcel) {
RemoteSelectIdKeyActivity activity = (RemoteSelectIdKeyActivity) getActivity();
if (activity == null) {
return;
}
activity.launchImportOperation(importKeyringParcel);
}
};
}
private void setupListenersForPresenter() {
buttonOverflow.setOnClickListener(this::showContextMenu);
buttonKeyListOther.setOnClickListener(view -> presenter.onClickKeyListOther());
buttonKeyListCancel.setOnClickListener(view -> presenter.onClickKeyListCancel());
@ -312,6 +346,23 @@ public class RemoteSelectIdKeyActivity extends FragmentActivity {
keyChoiceList.addOnItemTouchListener(new RecyclerItemClickListener(getContext(),
(view, position) -> presenter.onKeyItemClick(position)));
}
private void showContextMenu(View view) {
PopupMenu menu = new PopupMenu(getActivity(), view);
menu.inflate(R.menu.identity_context_menu);
// menu.setOnMenuItemClickListener(DecryptListFragment.this);
menu.show();
}
}
private void launchImportOperation(ImportKeyringParcel importKeyringParcel) {
if (currentlyImportingParcel != null) {
Timber.e("Starting import while already running? Inconsistent state!");
return;
}
currentlyImportingParcel = importKeyringParcel;
importOpHelper.cryptoOperation();
}
private static class KeyChoiceAdapter extends Adapter<KeyChoiceViewHolder> {
@ -333,21 +384,21 @@ public class RemoteSelectIdKeyActivity extends FragmentActivity {
return new KeyChoiceViewHolder(keyChoiceItemView);
}
public void setActiveItem(Integer activeItem) {
if (this.activeItem != null) {
notifyItemChanged(activeItem);
}
void setActiveItem(Integer activeItem) {
this.activeItem = activeItem;
if (this.activeItem != null) {
notifyItemChanged(activeItem);
}
notifyDataSetChanged();
}
@Override
public void onBindViewHolder(KeyChoiceViewHolder holder, int position) {
KeyInfo keyInfo = data.get(position);
Drawable icon = (activeItem != null && position == activeItem) ? iconSelected : iconUnselected;
boolean hasActiveItem = activeItem != null;
boolean isActiveItem = hasActiveItem && position == activeItem;
Drawable icon = isActiveItem ? iconSelected : iconUnselected;
holder.bind(keyInfo, icon);
holder.itemView.setVisibility(!hasActiveItem || isActiveItem ? View.VISIBLE : View.INVISIBLE);
}
@Override
@ -400,4 +451,34 @@ public class RemoteSelectIdKeyActivity extends FragmentActivity {
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (importOpHelper.handleActivityResult(requestCode, resultCode, data)) {
return;
}
super.onActivityResult(requestCode, resultCode, data);
}
private CryptoOperationHelper<Parcelable, ImportKeyResult> importOpHelper =
new CryptoOperationHelper<>(0, this,
new AbstractCallback<Parcelable, ImportKeyResult>() {
@Override
public Parcelable createOperationInput() {
return currentlyImportingParcel;
}
@Override
public void onCryptoOperationError(ImportKeyResult result) {
currentlyImportingParcel = null;
presenter.onImportOpError();
}
@Override
public void onCryptoOperationSuccess(ImportKeyResult result) {
currentlyImportingParcel = null;
presenter.onImportOpSuccess(result);
}
}, null);
}

View file

@ -12,7 +12,6 @@ public class RemoteSelectIdViewModel extends ViewModel {
private KeyInfoLiveData keyInfo;
private PgpKeyGenerationLiveData keyGenerationData;
public long selectedMasterKeyId;
public KeyInfoLiveData getKeyInfo(Context context) {
if (keyInfo == null) {

View file

@ -18,6 +18,7 @@
package org.sufficientlysecure.keychain.remote.ui.dialog;
import java.io.IOException;
import java.util.List;
import android.arch.lifecycle.LifecycleOwner;
@ -32,9 +33,13 @@ import org.openintents.openpgp.util.OpenPgpUtils.UserId;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.livedata.KeyInfoInteractor.KeyInfo;
import org.sufficientlysecure.keychain.livedata.KeyInfoInteractor.KeySelector;
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
import org.sufficientlysecure.keychain.operations.results.PgpEditKeyResult;
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.service.ImportKeyringParcel;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper;
import timber.log.Timber;
@ -44,11 +49,12 @@ class RemoteSelectIdentityKeyPresenter {
private final RemoteSelectIdViewModel viewModel;
private UserId userId;
private RemoteSelectIdentityKeyView view;
private List<KeyInfo> keyInfoData;
private long masterKeyId;
private UserId userId;
private long selectedMasterKeyId;
private byte[] generatedKeyData;
RemoteSelectIdentityKeyPresenter(Context context, RemoteSelectIdViewModel viewModel, LifecycleOwner lifecycleOwner) {
@ -106,11 +112,18 @@ class RemoteSelectIdentityKeyPresenter {
}
private void onChangeKeyGeneration(PgpEditKeyResult pgpEditKeyResult) {
viewModel.getKeyGenerationLiveData(context).setSaveKeyringParcel(null);
if (pgpEditKeyResult == null) {
return;
}
try {
UncachedKeyRing generatedRing = pgpEditKeyResult.getRing();
this.generatedKeyData = generatedRing.getEncoded();
} catch (IOException e) {
throw new AssertionError("Newly generated key ring must be encodable!");
}
viewModel.getKeyGenerationLiveData(context).setSaveKeyringParcel(null);
view.showLayoutGenerateOk();
}
@ -145,7 +158,7 @@ class RemoteSelectIdentityKeyPresenter {
}
void onKeyItemClick(int position) {
viewModel.selectedMasterKeyId = keyInfoData.get(position).getMasterKeyId();
selectedMasterKeyId = keyInfoData.get(position).getMasterKeyId();
view.highlightKey(position);
}
@ -162,12 +175,28 @@ class RemoteSelectIdentityKeyPresenter {
}
void onClickGenerateOkFinish() {
// saveKey
// view.finishAndReturn
if (generatedKeyData == null) {
return;
}
ImportKeyringParcel importKeyringParcel = ImportKeyringParcel.createFromBytes(generatedKeyData);
generatedKeyData = null;
view.launchImportOperation(importKeyringParcel);
view.showLayoutGenerateSave();
}
void onHighlightFinished() {
view.finishAndReturn(viewModel.selectedMasterKeyId);
view.finishAndReturn(selectedMasterKeyId);
}
void onImportOpSuccess(ImportKeyResult result) {
long importedMasterKeyId = result.getImportedMasterKeyIds()[0];
view.finishAndReturn(importedMasterKeyId);
}
void onImportOpError() {
view.showImportInternalError();
}
interface RemoteSelectIdentityKeyView {
@ -183,9 +212,14 @@ class RemoteSelectIdentityKeyPresenter {
void showLayoutImportExplanation();
void showLayoutGenerateProgress();
void showLayoutGenerateOk();
void showLayoutGenerateSave();
void setKeyListData(List<KeyInfo> data);
void highlightKey(int position);
void launchImportOperation(ImportKeyringParcel importKeyringParcel);
void showImportInternalError();
}
}

View file

@ -50,6 +50,11 @@ public abstract class ImportKeyringParcel implements Parcelable {
return new AutoValue_ImportKeyringParcel(Collections.singletonList(key), null, false);
}
public static ImportKeyringParcel createFromBytes(byte[] keyData) {
ParcelableKeyRing keyRing = ParcelableKeyRing.createFromEncodedBytes(keyData);
return new AutoValue_ImportKeyringParcel(Collections.singletonList(keyRing), null, false);
}
public static ImportKeyringParcel createFromFileCacheWithSkipSave() {
return new AutoValue_ImportKeyringParcel(null, null, true);
}

View file

@ -2,8 +2,8 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
tools:layout_marginTop="24dp"
>
@ -13,30 +13,37 @@
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:elevation="4dp"
android:gravity="center_horizontal"
android:padding="16dp"
android:gravity="center_vertical"
tools:targetApi="lollipop">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:src="@mipmap/ic_launcher"
/>
<ImageView
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="24dp"
android:layout_marginRight="24dp"
android:src="@drawable/link_24dp"
android:layout_marginLeft="16dp"
android:text="OpenKeychain"
style="?android:textAppearanceLarge"
/>
<Space
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
/>
<ImageView
android:id="@+id/icon_client_app"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:src="@drawable/apps_k9"
android:src="@drawable/ic_more_vert_black_24dp"
android:background="?selectableItemBackground"
android:id="@+id/overflow_menu"
/>
</LinearLayout>
@ -69,8 +76,8 @@
android:layout_height="wrap_content"
android:inAnimation="@anim/fade_in"
android:outAnimation="@anim/fade_out"
android:measureAllChildren="true"
custom:initialView="05">
android:measureAllChildren="false"
custom:initialView="04">
<Space
android:layout_width="wrap_content"
@ -138,7 +145,7 @@
android:layout_height="24dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:src="@drawable/ic_save_black_24dp"
android:src="@drawable/ic_help_black_24dp"
android:tint="@color/md_grey_600"
/>
@ -231,7 +238,7 @@
android:layout_height="24dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:src="@drawable/ic_save_black_24dp"
android:src="@drawable/ic_help_black_24dp"
android:tint="@color/md_grey_600"
/>
@ -285,7 +292,7 @@
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:text="To use an existing end-to-end key, you can either:\n\n① Open Autocrypt Setup Message from another e-mail app in K-9 Mail\n\n② Manually manage keys in OpenKeychain"
android:text="To import your key, you can either:\n\n① Open Autocrypt Setup Message from another e-mail app in K-9 Mail\n\n② Manually manage keys in OpenKeychain"
android:textAppearance="?android:attr/textAppearanceMedium"
/>
@ -330,35 +337,71 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?listPreferredItemHeight"
android:orientation="horizontal"
android:id="@+id/select_key_layout_generate_progress"
android:layout_marginTop="36dp"
android:orientation="vertical"
android:paddingLeft="16dp"
android:paddingRight="16dp">
android:paddingRight="16dp"
android:id="@+id/select_key_layout_generate_progress">
<ProgressBar
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_gravity="center_vertical"
android:indeterminate="true"
/>
<TextView
android:layout_width="wrap_content"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="Generating end-to-end key…"
android:textAppearance="?android:attr/textAppearanceMedium"
/>
android:minHeight="?listPreferredItemHeight">
<ProgressBar
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_gravity="center_vertical"
android:indeterminate="true"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="Please wait…"
android:textAppearance="?android:attr/textAppearanceMedium"
/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?listPreferredItemHeight"
android:background="?selectableItemBackground"
android:orientation="horizontal"
style="?buttonBarStyle">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:enabled="false"
android:text="Back"
style="?buttonBarButtonStyle"
/>
<Space
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:enabled="false"
android:text="Finish"
style="?buttonBarButtonStyle"
/>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="36dp"
android:orientation="vertical"
android:id="@+id/select_key_layout_generate_ok"
android:paddingLeft="16dp"
@ -395,8 +438,7 @@
android:id="@+id/button_gen_back"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:layout_marginBottom="8dp"
android:minHeight="?listPreferredItemHeight"
android:background="?selectableItemBackground"
android:orientation="horizontal"
style="?buttonBarStyle">
@ -426,6 +468,73 @@
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:id="@+id/select_key_layout_generate_save"
android:paddingLeft="16dp"
android:paddingRight="16dp"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?listPreferredItemHeight"
android:gravity="center_vertical"
android:orientation="horizontal">
<ProgressBar
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:indeterminate="true"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="Finishing setup…"
android:textAppearance="?android:attr/textAppearanceMedium"
/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?listPreferredItemHeight"
android:background="?selectableItemBackground"
android:orientation="horizontal"
style="?buttonBarStyle">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:enabled="false"
android:text="Back"
style="?buttonBarButtonStyle"
/>
<Space
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:enabled="false"
android:text="Finish"
style="?buttonBarButtonStyle"
/>
</LinearLayout>
</LinearLayout>
</org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator>
</LinearLayout>

View file

@ -1991,7 +1991,8 @@
<string name="use_key">Use key: %s</string>
<string name="use_key_no_name">Use key: <![CDATA[<no name>]]></string>
<string name="title_select_key">%s wants to end-to-end encrypt with this address:</string>
<string name="title_select_key">%s wants to set up end-to-end encryption for this address:</string>
<string name="select_identity_cancel">Cancel</string>
<string name="select_identity_create">Create a key for me</string>
<string name="error_save_key_internal">"Internal error saving key!"</string>
</resources>