use LiveData in LinkedIdWizard and related Fragments

This commit is contained in:
Vincent Breitmoser
2018-06-24 12:41:13 +02:00
parent 2a5b93d9c5
commit 4fcc5253ae
15 changed files with 296 additions and 613 deletions

View File

@@ -140,11 +140,6 @@ public class KeychainContract {
.appendPath(PATH_UNIFIED).build(); .appendPath(PATH_UNIFIED).build();
} }
public static Uri buildUnifiedKeyRingUri(Uri uri) {
return CONTENT_URI.buildUpon().appendPath(uri.getPathSegments().get(1))
.appendPath(PATH_UNIFIED).build();
}
public static Uri buildUnifiedKeyRingsFindByEmailUri(String email) { public static Uri buildUnifiedKeyRingsFindByEmailUri(String email) {
return CONTENT_URI.buildUpon().appendPath(PATH_FIND) return CONTENT_URI.buildUpon().appendPath(PATH_FIND)
.appendPath(PATH_BY_EMAIL).appendPath(email).build(); .appendPath(PATH_BY_EMAIL).appendPath(email).build();

View File

@@ -17,40 +17,41 @@
package org.sufficientlysecure.keychain.ui; package org.sufficientlysecure.keychain.ui;
import android.arch.lifecycle.ViewModelProviders;
import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.view.View; import android.view.View;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.ui.base.BaseActivity; import org.sufficientlysecure.keychain.ui.base.BaseActivity;
import org.sufficientlysecure.keychain.ui.keyview.UnifiedKeyInfoViewModel;
import timber.log.Timber; import timber.log.Timber;
public class CertifyFingerprintActivity extends BaseActivity { public class CertifyFingerprintActivity extends BaseActivity {
public static final String EXTRA_MASTER_KEY_ID = "master_key_id";
protected Uri mDataUri;
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
mDataUri = getIntent().getData(); Bundle extras = getIntent().getExtras();
if (mDataUri == null) { if (extras == null || !extras.containsKey(EXTRA_MASTER_KEY_ID)) {
Timber.e("Data missing. Should be uri of key!"); Timber.e("Missing required extra master_key_id!");
finish(); finish();
return; return;
} }
setFullScreenDialogClose(new View.OnClickListener() { setFullScreenDialogClose(v -> finish());
@Override
public void onClick(View v) {
finish();
}
});
Timber.i("dataUri: " + mDataUri.toString()); long masterKeyId = extras.getLong(EXTRA_MASTER_KEY_ID);
UnifiedKeyInfoViewModel viewModel = ViewModelProviders.of(this).get(UnifiedKeyInfoViewModel.class);
viewModel.setMasterKeyId(masterKeyId);
startFragment(savedInstanceState, mDataUri); if (savedInstanceState == null) {
startFragment();
}
} }
@Override @Override
@@ -58,24 +59,9 @@ public class CertifyFingerprintActivity extends BaseActivity {
setContentView(R.layout.certify_fingerprint_activity); setContentView(R.layout.certify_fingerprint_activity);
} }
private void startFragment(Bundle savedInstanceState, Uri dataUri) { private void startFragment() {
// However, if we're being restored from a previous state, CertifyFingerprintFragment frag = CertifyFingerprintFragment.newInstance();
// then we don't need to do anything and should return or else getSupportFragmentManager().beginTransaction().replace(R.id.certify_fingerprint_fragment, frag).commit();
// we could end up with overlapping fragments.
if (savedInstanceState != null) {
return;
}
// Create an instance of the fragment
CertifyFingerprintFragment frag = CertifyFingerprintFragment.newInstance(dataUri);
// Add the fragment to the 'fragment_container' FrameLayout
// NOTE: We use commitAllowingStateLoss() to prevent weird crashes!
getSupportFragmentManager().beginTransaction()
.replace(R.id.certify_fingerprint_fragment, frag)
.commitAllowingStateLoss();
// do it immediately!
getSupportFragmentManager().executePendingTransactions();
} }
} }

View File

@@ -18,79 +18,42 @@
package org.sufficientlysecure.keychain.ui; package org.sufficientlysecure.keychain.ui;
import android.arch.lifecycle.ViewModelProviders;
import android.content.Intent; import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager; import android.support.v4.app.FragmentActivity;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.TextView; import android.widget.TextView;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.provider.KeyRepository; import org.sufficientlysecure.keychain.ui.keyview.UnifiedKeyInfoViewModel;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import timber.log.Timber;
public class CertifyFingerprintFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> { public class CertifyFingerprintFragment extends Fragment {
static final int REQUEST_CERTIFY = 1; static final int REQUEST_CERTIFY = 1;
public static final String ARG_DATA_URI = "uri"; private TextView vFingerprint;
private TextView mActionYes; private UnifiedKeyInfoViewModel viewModel;
private TextView mFingerprint;
private TextView mIntro;
private TextView mHeader;
private static final int LOADER_ID_UNIFIED = 0; public static CertifyFingerprintFragment newInstance() {
return new CertifyFingerprintFragment();
private Uri mDataUri;
/**
* Creates new instance of this fragment
*/
public static CertifyFingerprintFragment newInstance(Uri dataUri) {
CertifyFingerprintFragment frag = new CertifyFingerprintFragment();
Bundle args = new Bundle();
args.putParcelable(ARG_DATA_URI, dataUri);
frag.setArguments(args);
return frag;
} }
@Override @Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup viewGroup, Bundle savedInstanceState) { public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup viewGroup, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.certify_fingerprint_fragment, viewGroup, false); View view = inflater.inflate(R.layout.certify_fingerprint_fragment, viewGroup, false);
TextView actionNo = view.findViewById(R.id.certify_fingerprint_button_no); vFingerprint = view.findViewById(R.id.certify_fingerprint_fingerprint);
mActionYes = view.findViewById(R.id.certify_fingerprint_button_yes);
mFingerprint = view.findViewById(R.id.certify_fingerprint_fingerprint); view.findViewById(R.id.certify_fingerprint_button_no).setOnClickListener(v -> requireActivity().finish());
mIntro = view.findViewById(R.id.certify_fingerprint_intro); view.findViewById(R.id.certify_fingerprint_button_yes).setOnClickListener(v -> startCertifyActivity());
mHeader = view.findViewById(R.id.certify_fingerprint_fingerprint_header);
actionNo.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
getActivity().finish();
}
});
mActionYes.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
certify(mDataUri);
}
});
return view; return view;
} }
@@ -99,103 +62,35 @@ public class CertifyFingerprintFragment extends Fragment implements LoaderManage
public void onActivityCreated(Bundle savedInstanceState) { public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState); super.onActivityCreated(savedInstanceState);
Uri dataUri = getArguments().getParcelable(ARG_DATA_URI); viewModel = ViewModelProviders.of(requireActivity()).get(UnifiedKeyInfoViewModel.class);
if (dataUri == null) { viewModel.getUnifiedKeyInfoLiveData(requireContext()).observe(this, this::onLoadUnifiedKeyInfo);
Timber.e("Data missing. Should be Uri of key!"); }
getActivity().finish();
private void onLoadUnifiedKeyInfo(UnifiedKeyInfo unifiedKeyInfo) {
if (unifiedKeyInfo == null) {
return; return;
} }
loadData(dataUri); String fingerprint = KeyFormattingUtils.convertFingerprintToHex(unifiedKeyInfo.fingerprint());
vFingerprint.setText(KeyFormattingUtils.formatFingerprint(fingerprint));
} }
private void loadData(Uri dataUri) { private void startCertifyActivity() {
mDataUri = dataUri;
Timber.i("dataUri: " + mDataUri.toString());
// Prepare the loaders. Either re-connect with an existing ones,
// or start new ones.
getLoaderManager().initLoader(LOADER_ID_UNIFIED, null, this);
}
static final String[] UNIFIED_PROJECTION = new String[]{
KeyRings._ID, KeyRings.FINGERPRINT,
};
static final int INDEX_UNIFIED_FINGERPRINT = 1;
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
switch (id) {
case LOADER_ID_UNIFIED: {
Uri baseUri = KeyRings.buildUnifiedKeyRingUri(mDataUri);
return new CursorLoader(getActivity(), baseUri, UNIFIED_PROJECTION, null, null, null);
}
default:
return null;
}
}
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
/* TODO better error handling? May cause problems when a key is deleted,
* because the notification triggers faster than the activity closes.
*/
// Avoid NullPointerExceptions...
if (data.getCount() == 0) {
return;
}
// Swap the new cursor in. (The framework will take care of closing the
// old cursor once we return.)
switch (loader.getId()) {
case LOADER_ID_UNIFIED: {
if (data.moveToFirst()) {
byte[] fingerprintBlob = data.getBlob(INDEX_UNIFIED_FINGERPRINT);
displayHexConfirm(fingerprintBlob);
break;
}
}
}
}
private void displayHexConfirm(byte[] fingerprintBlob) {
String fingerprint = KeyFormattingUtils.convertFingerprintToHex(fingerprintBlob);
mFingerprint.setText(KeyFormattingUtils.formatFingerprint(fingerprint));
}
/**
* This is called when the last Cursor provided to onLoadFinished() above is about to be closed.
* We need to make sure we are no longer using it.
*/
public void onLoaderReset(Loader<Cursor> loader) {
}
private void certify(Uri dataUri) {
long keyId = 0;
try {
keyId = KeyRepository.create(getContext())
.getCachedPublicKeyRing(dataUri)
.extractOrGetMasterKeyId();
} catch (PgpKeyNotFoundException e) {
Timber.e(e, "key not found!");
}
Intent certifyIntent = new Intent(getActivity(), CertifyKeyActivity.class); Intent certifyIntent = new Intent(getActivity(), CertifyKeyActivity.class);
certifyIntent.putExtras(getActivity().getIntent()); certifyIntent.putExtras(requireActivity().getIntent());
certifyIntent.putExtra(CertifyKeyActivity.EXTRA_KEY_IDS, new long[]{keyId}); certifyIntent.putExtra(CertifyKeyActivity.EXTRA_KEY_IDS, new long[] { viewModel.getMasterKeyId() });
startActivityForResult(certifyIntent, REQUEST_CERTIFY); startActivityForResult(certifyIntent, REQUEST_CERTIFY);
} }
@Override @Override
public void onActivityResult(int requestCode, int resultCode, Intent data) { public void onActivityResult(int requestCode, int resultCode, Intent data) {
// always just pass this one through
if (requestCode == REQUEST_CERTIFY) { if (requestCode == REQUEST_CERTIFY) {
getActivity().setResult(resultCode, data); FragmentActivity activity = requireActivity();
getActivity().finish(); activity.setResult(resultCode, data);
activity.finish();
return; return;
} }
super.onActivityResult(requestCode, resultCode, data); super.onActivityResult(requestCode, resultCode, data);
} }

View File

@@ -17,8 +17,11 @@
package org.sufficientlysecure.keychain.ui; package org.sufficientlysecure.keychain.ui;
import java.util.Date;
import java.util.HashMap;
import android.app.Activity; import android.app.Activity;
import android.support.v7.app.AlertDialog;
import android.app.Dialog; import android.app.Dialog;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
@@ -26,6 +29,7 @@ import android.os.Bundle;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment; import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentActivity;
import android.support.v7.app.AlertDialog;
import android.view.ContextThemeWrapper; import android.view.ContextThemeWrapper;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
@@ -34,12 +38,11 @@ import android.widget.Spinner;
import android.widget.TextView; import android.widget.TextView;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.keyimport.HkpKeyserverAddress;
import org.sufficientlysecure.keychain.operations.results.DeleteResult; import org.sufficientlysecure.keychain.operations.results.DeleteResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.operations.results.RevokeResult; import org.sufficientlysecure.keychain.operations.results.RevokeResult;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.KeyRepository; import org.sufficientlysecure.keychain.provider.KeyRepository;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.service.DeleteKeyringParcel; import org.sufficientlysecure.keychain.service.DeleteKeyringParcel;
import org.sufficientlysecure.keychain.service.RevokeKeyringParcel; import org.sufficientlysecure.keychain.service.RevokeKeyringParcel;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
@@ -48,9 +51,6 @@ import org.sufficientlysecure.keychain.ui.dialog.CustomAlertDialogBuilder;
import org.sufficientlysecure.keychain.ui.util.ThemeChanger; import org.sufficientlysecure.keychain.ui.util.ThemeChanger;
import timber.log.Timber; import timber.log.Timber;
import java.util.Date;
import java.util.HashMap;
public class DeleteKeyDialogActivity extends FragmentActivity { public class DeleteKeyDialogActivity extends FragmentActivity {
public static final String EXTRA_DELETE_MASTER_KEY_IDS = "extra_delete_master_key_ids"; public static final String EXTRA_DELETE_MASTER_KEY_IDS = "extra_delete_master_key_ids";
public static final String EXTRA_HAS_SECRET = "extra_has_secret"; public static final String EXTRA_HAS_SECRET = "extra_has_secret";
@@ -81,6 +81,7 @@ public class DeleteKeyDialogActivity extends FragmentActivity {
log.add(OperationResult.LogType.MSG_DEL_ERROR_MULTI_SECRET, 0); log.add(OperationResult.LogType.MSG_DEL_ERROR_MULTI_SECRET, 0);
returnResult(new DeleteResult(OperationResult.RESULT_ERROR, log, 0, returnResult(new DeleteResult(OperationResult.RESULT_ERROR, log, 0,
mMasterKeyIds.length)); mMasterKeyIds.length));
return;
} }
if (mMasterKeyIds.length == 1 && mHasSecret) { if (mMasterKeyIds.length == 1 && mHasSecret) {

View File

@@ -0,0 +1,40 @@
package org.sufficientlysecure.keychain.ui.keyview;
import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.ViewModel;
import android.content.Context;
import org.sufficientlysecure.keychain.livedata.GenericLiveData;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.provider.KeyRepository;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
public class UnifiedKeyInfoViewModel extends ViewModel {
private Long masterKeyId;
private LiveData<UnifiedKeyInfo> unifiedKeyInfoLiveData;
public void setMasterKeyId(long masterKeyId) {
if (this.masterKeyId != null) {
throw new IllegalStateException("cannot change masterKeyId once set!");
}
this.masterKeyId = masterKeyId;
}
public long getMasterKeyId() {
return masterKeyId;
}
public LiveData<UnifiedKeyInfo> getUnifiedKeyInfoLiveData(Context context) {
if (masterKeyId == null) {
throw new IllegalStateException("masterKeyId must be set to retrieve this!");
}
if (unifiedKeyInfoLiveData == null) {
KeyRepository keyRepository = KeyRepository.create(context);
unifiedKeyInfoLiveData = new GenericLiveData<>(context, KeyRings.buildGenericKeyRingUri(masterKeyId),
() -> keyRepository.getUnifiedKeyInfo(masterKeyId));
}
return unifiedKeyInfoLiveData;
}
}

View File

@@ -28,8 +28,6 @@ import android.animation.ObjectAnimator;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.app.Activity; import android.app.Activity;
import android.app.ActivityOptions; import android.app.ActivityOptions;
import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.ViewModel;
import android.arch.lifecycle.ViewModelProviders; import android.arch.lifecycle.ViewModelProviders;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
@@ -70,7 +68,6 @@ import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.keyimport.HkpKeyserverAddress; import org.sufficientlysecure.keychain.keyimport.HkpKeyserverAddress;
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
import org.sufficientlysecure.keychain.livedata.GenericLiveData;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.operations.results.EditKeyResult; import org.sufficientlysecure.keychain.operations.results.EditKeyResult;
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
@@ -269,7 +266,7 @@ public class ViewKeyActivity extends BaseSecurityTokenActivity implements
qrCodeLayout.setOnClickListener(v -> showQrCodeDialog()); qrCodeLayout.setOnClickListener(v -> showQrCodeDialog());
ViewKeyViewModel viewModel = ViewModelProviders.of(this).get(ViewKeyViewModel.class); UnifiedKeyInfoViewModel viewModel = ViewModelProviders.of(this).get(UnifiedKeyInfoViewModel.class);
viewModel.setMasterKeyId(getIntent().getLongExtra(EXTRA_MASTER_KEY_ID, 0L)); viewModel.setMasterKeyId(getIntent().getLongExtra(EXTRA_MASTER_KEY_ID, 0L));
if (savedInstanceState == null && intent.hasExtra(EXTRA_DISPLAY_RESULT)) { if (savedInstanceState == null && intent.hasExtra(EXTRA_DISPLAY_RESULT)) {
@@ -296,30 +293,6 @@ public class ViewKeyActivity extends BaseSecurityTokenActivity implements
} }
} }
public static class ViewKeyViewModel extends ViewModel {
private Long masterKeyId;
private LiveData<UnifiedKeyInfo> unifiedKeyInfoLiveData;
void setMasterKeyId(long masterKeyId) {
if (this.masterKeyId != null) {
throw new IllegalStateException("cannot change masterKeyId once set!");
}
this.masterKeyId = masterKeyId;
}
LiveData<UnifiedKeyInfo> getUnifiedKeyInfoLiveData(Context context) {
if (masterKeyId == null) {
throw new IllegalStateException("masterKeyId must be set to retrieve this!");
}
if (unifiedKeyInfoLiveData == null) {
KeyRepository keyRepository = KeyRepository.create(context);
unifiedKeyInfoLiveData = new GenericLiveData<>(context, KeyRings.buildGenericKeyRingUri(masterKeyId),
() -> keyRepository.getUnifiedKeyInfo(masterKeyId));
}
return unifiedKeyInfoLiveData;
}
}
@Override @Override
protected void initLayout() { protected void initLayout() {
setContentView(R.layout.view_key_activity); setContentView(R.layout.view_key_activity);
@@ -467,7 +440,7 @@ public class ViewKeyActivity extends BaseSecurityTokenActivity implements
private void certifyFingerprint() { private void certifyFingerprint() {
Intent intent = new Intent(this, CertifyFingerprintActivity.class); Intent intent = new Intent(this, CertifyFingerprintActivity.class);
intent.setData(KeyRings.buildUnifiedKeyRingUri(unifiedKeyInfo.master_key_id())); intent.putExtra(CertifyFingerprintActivity.EXTRA_MASTER_KEY_ID, unifiedKeyInfo.master_key_id());
startActivityForResult(intent, REQUEST_CERTIFY); startActivityForResult(intent, REQUEST_CERTIFY);
} }

View File

@@ -46,11 +46,9 @@ import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType; import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
import org.sufficientlysecure.keychain.provider.AutocryptPeerDao; import org.sufficientlysecure.keychain.provider.AutocryptPeerDao;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.ui.adapter.IdentityAdapter; import org.sufficientlysecure.keychain.ui.adapter.IdentityAdapter;
import org.sufficientlysecure.keychain.ui.adapter.IdentityAdapter.IdentityClickListener; import org.sufficientlysecure.keychain.ui.adapter.IdentityAdapter.IdentityClickListener;
import org.sufficientlysecure.keychain.ui.dialog.UserIdInfoDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.UserIdInfoDialogFragment;
import org.sufficientlysecure.keychain.ui.keyview.ViewKeyActivity.ViewKeyViewModel;
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityDao.AutocryptPeerInfo; import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityDao.AutocryptPeerInfo;
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityDao.IdentityInfo; import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityDao.IdentityInfo;
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityDao.LinkedIdInfo; import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityDao.LinkedIdInfo;
@@ -119,7 +117,7 @@ public class ViewKeyFragment extends Fragment implements OnMenuItemClickListener
Context context = requireContext(); Context context = requireContext();
ViewKeyViewModel viewKeyViewModel = ViewModelProviders.of(requireActivity()).get(ViewKeyViewModel.class); UnifiedKeyInfoViewModel viewKeyViewModel = ViewModelProviders.of(requireActivity()).get(UnifiedKeyInfoViewModel.class);
LiveData<UnifiedKeyInfo> unifiedKeyInfoLiveData = viewKeyViewModel.getUnifiedKeyInfoLiveData(requireContext()); LiveData<UnifiedKeyInfo> unifiedKeyInfoLiveData = viewKeyViewModel.getUnifiedKeyInfoLiveData(requireContext());
unifiedKeyInfoLiveData.observe(this, this::onLoadUnifiedKeyInfo); unifiedKeyInfoLiveData.observe(this, this::onLoadUnifiedKeyInfo);
@@ -277,7 +275,7 @@ public class ViewKeyFragment extends Fragment implements OnMenuItemClickListener
private void addLinkedIdentity() { private void addLinkedIdentity() {
Intent intent = new Intent(requireContext(), LinkedIdWizard.class); Intent intent = new Intent(requireContext(), LinkedIdWizard.class);
intent.setData(KeyRings.buildUnifiedKeyRingUri(unifiedKeyInfo.master_key_id())); intent.putExtra(LinkedIdWizard.EXTRA_MASTER_KEY_ID, unifiedKeyInfo.master_key_id());
startActivity(intent); startActivity(intent);
} }

View File

@@ -17,6 +17,8 @@
package org.sufficientlysecure.keychain.ui.linked; package org.sufficientlysecure.keychain.ui.linked;
import android.arch.lifecycle.ViewModelProviders;
import android.graphics.PorterDuff; import android.graphics.PorterDuff;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Bundle; import android.os.Bundle;
@@ -25,7 +27,6 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
@@ -34,6 +35,7 @@ import android.widget.ViewAnimator;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.linked.LinkedAttribute; import org.sufficientlysecure.keychain.linked.LinkedAttribute;
import org.sufficientlysecure.keychain.linked.LinkedTokenResource; import org.sufficientlysecure.keychain.linked.LinkedTokenResource;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.operations.results.LinkedVerifyResult; import org.sufficientlysecure.keychain.operations.results.LinkedVerifyResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
@@ -41,68 +43,57 @@ import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel; import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.ui.base.CryptoOperationFragment; import org.sufficientlysecure.keychain.ui.base.CryptoOperationFragment;
import org.sufficientlysecure.keychain.ui.keyview.UnifiedKeyInfoViewModel;
import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.ui.util.Notify;
public abstract class LinkedIdCreateFinalFragment extends CryptoOperationFragment { public abstract class LinkedIdCreateFinalFragment extends CryptoOperationFragment {
protected LinkedIdWizard mLinkedIdWizard;
private ImageView mVerifyImage; private ImageView mVerifyImage;
private TextView mVerifyStatus; private TextView mVerifyStatus;
private ViewAnimator mVerifyAnimator; private ViewAnimator mVerifyAnimator;
private long masterKeyId;
byte[] fingerprint;
// This is a resource, set AFTER it has been verified // This is a resource, set AFTER it has been verified
LinkedTokenResource mVerifiedResource = null; LinkedTokenResource mVerifiedResource = null;
private ViewAnimator mVerifyButtonAnimator; private ViewAnimator mVerifyButtonAnimator;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mLinkedIdWizard = (LinkedIdWizard) getActivity();
}
protected abstract View newView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState); protected abstract View newView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState);
@Override @NonNull @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
UnifiedKeyInfoViewModel viewModel = ViewModelProviders.of(requireActivity()).get(UnifiedKeyInfoViewModel.class);
viewModel.getUnifiedKeyInfoLiveData(requireContext()).observe(this, this::onLoadUnifiedKeyInfo);
}
private void onLoadUnifiedKeyInfo(UnifiedKeyInfo unifiedKeyInfo) {
this.masterKeyId = unifiedKeyInfo.master_key_id();
this.fingerprint = unifiedKeyInfo.fingerprint();
}
@NonNull
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View view = newView(inflater, container, savedInstanceState); final View view = newView(inflater, container, savedInstanceState);
View nextButton = view.findViewById(R.id.next_button); View nextButton = view.findViewById(R.id.next_button);
if (nextButton != null) { if (nextButton != null) {
nextButton.setOnClickListener(new OnClickListener() { nextButton.setOnClickListener(v -> cryptoOperation());
@Override
public void onClick(View v) {
cryptoOperation();
}
});
} }
view.findViewById(R.id.back_button).setOnClickListener(new View.OnClickListener() { view.findViewById(R.id.back_button).setOnClickListener(
@Override v -> ((LinkedIdWizard) requireActivity()).loadFragment(null, LinkedIdWizard.FRAG_ACTION_TO_LEFT));
public void onClick(View v) {
mLinkedIdWizard.loadFragment(null, null, LinkedIdWizard.FRAG_ACTION_TO_LEFT);
}
});
mVerifyAnimator = view.findViewById(R.id.verify_progress); mVerifyAnimator = view.findViewById(R.id.verify_progress);
mVerifyImage = view.findViewById(R.id.verify_image); mVerifyImage = view.findViewById(R.id.verify_image);
mVerifyStatus = view.findViewById(R.id.verify_status); mVerifyStatus = view.findViewById(R.id.verify_status);
mVerifyButtonAnimator = view.findViewById(R.id.verify_buttons); mVerifyButtonAnimator = view.findViewById(R.id.verify_buttons);
view.findViewById(R.id.button_verify).setOnClickListener(new OnClickListener() { view.findViewById(R.id.button_verify).setOnClickListener(v -> proofVerify());
@Override
public void onClick(View v) {
proofVerify();
}
});
view.findViewById(R.id.button_retry).setOnClickListener(new OnClickListener() { view.findViewById(R.id.button_retry).setOnClickListener(v -> proofVerify());
@Override
public void onClick(View v) {
proofVerify();
}
});
setVerifyProgress(false, null); setVerifyProgress(false, null);
mVerifyStatus.setText(R.string.linked_verify_pending); mVerifyStatus.setText(R.string.linked_verify_pending);
@@ -154,7 +145,7 @@ public abstract class LinkedIdCreateFinalFragment extends CryptoOperationFragmen
return new LinkedVerifyResult(LinkedVerifyResult.RESULT_ERROR, log); return new LinkedVerifyResult(LinkedVerifyResult.RESULT_ERROR, log);
} }
LinkedVerifyResult result = resource.verify(getActivity(), mLinkedIdWizard.mFingerprint); LinkedVerifyResult result = resource.verify(getActivity(), fingerprint);
// ux flow: this operation should take at last a second // ux flow: this operation should take at last a second
timer = System.currentTimeMillis() -timer; timer = System.currentTimeMillis() -timer;
@@ -211,7 +202,7 @@ public abstract class LinkedIdCreateFinalFragment extends CryptoOperationFragmen
@Override @Override
public Parcelable createOperationInput() { public Parcelable createOperationInput() {
SaveKeyringParcel.Builder builder= SaveKeyringParcel.Builder builder=
SaveKeyringParcel.buildChangeKeyringParcel(mLinkedIdWizard.mMasterKeyId, mLinkedIdWizard.mFingerprint); SaveKeyringParcel.buildChangeKeyringParcel(masterKeyId, fingerprint);
WrappedUserAttribute ua = LinkedAttribute.fromResource(mVerifiedResource).toUserAttribute(); WrappedUserAttribute ua = LinkedAttribute.fromResource(mVerifiedResource).toUserAttribute();
builder.addUserAttribute(ua); builder.addUserAttribute(ua);
return builder.build(); return builder.build();
@@ -219,7 +210,7 @@ public abstract class LinkedIdCreateFinalFragment extends CryptoOperationFragmen
@Override @Override
public void onCryptoOperationSuccess(OperationResult result) { public void onCryptoOperationSuccess(OperationResult result) {
getActivity().finish(); requireActivity().finish();
} }
@Override @Override

View File

@@ -33,13 +33,11 @@ import java.util.Random;
import android.app.Activity; import android.app.Activity;
import android.app.Dialog; import android.app.Dialog;
import android.arch.lifecycle.ViewModelProviders;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnDismissListener;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Build;
import android.os.Build.VERSION; import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES; import android.os.Build.VERSION_CODES;
import android.os.Bundle; import android.os.Bundle;
@@ -47,11 +45,9 @@ import android.os.Handler;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.v4.app.ActivityOptionsCompat; import android.support.v4.app.ActivityOptionsCompat;
import android.support.v4.app.FragmentActivity;
import android.util.Base64; import android.util.Base64;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.webkit.CookieManager; import android.webkit.CookieManager;
import android.webkit.WebView; import android.webkit.WebView;
@@ -69,10 +65,12 @@ import org.sufficientlysecure.keychain.BuildConfig;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.linked.LinkedAttribute; import org.sufficientlysecure.keychain.linked.LinkedAttribute;
import org.sufficientlysecure.keychain.linked.resources.GithubResource; import org.sufficientlysecure.keychain.linked.resources.GithubResource;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.operations.results.EditKeyResult; import org.sufficientlysecure.keychain.operations.results.EditKeyResult;
import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute; import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel; import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
import org.sufficientlysecure.keychain.ui.base.CryptoOperationFragment; import org.sufficientlysecure.keychain.ui.base.CryptoOperationFragment;
import org.sufficientlysecure.keychain.ui.keyview.UnifiedKeyInfoViewModel;
import org.sufficientlysecure.keychain.ui.keyview.ViewKeyActivity; import org.sufficientlysecure.keychain.ui.keyview.ViewKeyActivity;
import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.ui.util.Notify;
import org.sufficientlysecure.keychain.ui.util.Notify.Style; import org.sufficientlysecure.keychain.ui.util.Notify.Style;
@@ -109,7 +107,7 @@ public class LinkedIdCreateGithubFragment extends CryptoOperationFragment<SaveKe
} }
@Override @NonNull @Override @NonNull
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.linked_create_github_fragment, container, false); View view = inflater.inflate(R.layout.linked_create_github_fragment, container, false);
mButtonContainer = view.findViewById(R.id.button_container); mButtonContainer = view.findViewById(R.id.button_container);
@@ -125,24 +123,15 @@ public class LinkedIdCreateGithubFragment extends CryptoOperationFragment<SaveKe
mLinkedIdTitle = view.findViewById(R.id.linked_id_title); mLinkedIdTitle = view.findViewById(R.id.linked_id_title);
mLinkedIdComment = view.findViewById(R.id.linked_id_comment); mLinkedIdComment = view.findViewById(R.id.linked_id_comment);
view.findViewById(R.id.back_button).setOnClickListener(new View.OnClickListener() { view.findViewById(R.id.back_button).setOnClickListener(v -> {
@Override LinkedIdWizard activity = (LinkedIdWizard) requireActivity();
public void onClick(View v) { activity.loadFragment(null, LinkedIdWizard.FRAG_ACTION_TO_LEFT);
LinkedIdWizard activity = (LinkedIdWizard) getActivity();
if (activity == null) {
return;
}
activity.loadFragment(null, null, LinkedIdWizard.FRAG_ACTION_TO_LEFT);
}
}); });
view.findViewById(R.id.button_send).setOnClickListener(new OnClickListener() { view.findViewById(R.id.button_send).setOnClickListener(v -> {
@Override step1GetOAuthCode();
public void onClick(View v) { // for animation testing
step1GetOAuthCode(); // onCryptoOperationSuccess(null);
// for animation testing
// onCryptoOperationSuccess(null);
}
}); });
return view; return view;
@@ -152,34 +141,29 @@ public class LinkedIdCreateGithubFragment extends CryptoOperationFragment<SaveKe
public void onActivityCreated(@Nullable Bundle savedInstanceState) { public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState); super.onActivityCreated(savedInstanceState);
LinkedIdWizard wizard = (LinkedIdWizard) getActivity(); UnifiedKeyInfoViewModel viewModel = ViewModelProviders.of(requireActivity()).get(UnifiedKeyInfoViewModel.class);
mFingerprint = wizard.mFingerprint; viewModel.getUnifiedKeyInfoLiveData(requireContext()).observe(this, this::onLoadUnifiedKeyInfo);
mMasterKeyId = wizard.mMasterKeyId; }
private void onLoadUnifiedKeyInfo(UnifiedKeyInfo unifiedKeyInfo) {
this.mMasterKeyId = unifiedKeyInfo.master_key_id();
this.mFingerprint = unifiedKeyInfo.fingerprint();
} }
private void step1GetOAuthCode() { private void step1GetOAuthCode() {
setState(State.AUTH_PROCESS); setState(State.AUTH_PROCESS);
mButtonContainer.setDisplayedChild(1); mButtonContainer.setDisplayedChild(1);
new Handler().postDelayed(new Runnable() { new Handler().postDelayed(
@Override () -> oAuthRequest("github.com/login/oauth/authorize", BuildConfig.GITHUB_CLIENT_ID, "gist"), 300);
public void run() {
oAuthRequest("github.com/login/oauth/authorize", BuildConfig.GITHUB_CLIENT_ID, "gist");
}
}, 300);
} }
private void showRetryForOAuth() { private void showRetryForOAuth() {
mRetryButton.setOnClickListener(v -> {
mRetryButton.setOnClickListener(new OnClickListener() { v.setOnClickListener(null);
@Override step1GetOAuthCode();
public void onClick(View v) {
v.setOnClickListener(null);
step1GetOAuthCode();
}
}); });
mButtonContainer.setDisplayedChild(3); mButtonContainer.setDisplayedChild(3);
@@ -402,14 +386,11 @@ public class LinkedIdCreateGithubFragment extends CryptoOperationFragment<SaveKe
setState(State.LID_PROCESS); setState(State.LID_PROCESS);
new Handler().postDelayed(new Runnable() { new Handler().postDelayed(() -> {
@Override WrappedUserAttribute ua = LinkedAttribute.fromResource(resource).toUserAttribute();
public void run() { mSkpBuilder = SaveKeyringParcel.buildChangeKeyringParcel(mMasterKeyId, mFingerprint);
WrappedUserAttribute ua = LinkedAttribute.fromResource(resource).toUserAttribute(); mSkpBuilder.addUserAttribute(ua);
mSkpBuilder = SaveKeyringParcel.buildChangeKeyringParcel(mMasterKeyId, mFingerprint); cryptoOperation();
mSkpBuilder.addUserAttribute(ua);
cryptoOperation();
}
}, 250); }, 250);
} }
@@ -429,31 +410,28 @@ public class LinkedIdCreateGithubFragment extends CryptoOperationFragment<SaveKe
mButtonContainer.getInAnimation().setDuration(750); mButtonContainer.getInAnimation().setDuration(750);
mButtonContainer.setDisplayedChild(2); mButtonContainer.setDisplayedChild(2);
new Handler().postDelayed(new Runnable() { new Handler().postDelayed(() -> {
@Override Activity activity = requireActivity();
public void run() { Intent intent = ViewKeyActivity.getViewKeyActivityIntent(requireActivity(), mMasterKeyId);
FragmentActivity activity = getActivity(); // intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
Intent intent = ViewKeyActivity.getViewKeyActivityIntent(requireActivity(), mMasterKeyId);
// intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
intent.putExtra(ViewKeyActivity.EXTRA_LINKED_TRANSITION, true); intent.putExtra(ViewKeyActivity.EXTRA_LINKED_TRANSITION, true);
View linkedItem = mButtonContainer.getChildAt(2); View linkedItem = mButtonContainer.getChildAt(2);
Bundle options = ActivityOptionsCompat.makeSceneTransitionAnimation( Bundle options = ActivityOptionsCompat.makeSceneTransitionAnimation(
activity, linkedItem, linkedItem.getTransitionName()).toBundle(); activity, linkedItem, linkedItem.getTransitionName()).toBundle();
activity.startActivity(intent, options); activity.startActivity(intent, options);
mFinishOnStop = true; mFinishOnStop = true;
} else { } else {
activity.startActivity(intent); activity.startActivity(intent);
activity.finish(); activity.finish();
}
} }
}, 1000); }, 1000);
} }
@Override @Override
public void onSaveInstanceState(Bundle outState) { public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState); super.onSaveInstanceState(outState);
// cookies are automatically saved, we don't want that // cookies are automatically saved, we don't want that
@@ -463,7 +441,7 @@ public class LinkedIdCreateGithubFragment extends CryptoOperationFragment<SaveKe
} }
@Override @Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState); super.onViewCreated(view, savedInstanceState);
if (savedInstanceState != null) { if (savedInstanceState != null) {
@@ -491,7 +469,7 @@ public class LinkedIdCreateGithubFragment extends CryptoOperationFragment<SaveKe
super.onStop(); super.onStop();
if (mFinishOnStop) { if (mFinishOnStop) {
Activity activity = getActivity(); Activity activity = requireActivity();
activity.setResult(Activity.RESULT_OK); activity.setResult(Activity.RESULT_OK);
activity.finish(); activity.finish();
} }
@@ -505,14 +483,11 @@ public class LinkedIdCreateGithubFragment extends CryptoOperationFragment<SaveKe
@Override @Override
public void onCryptoOperationCancelled() { public void onCryptoOperationCancelled() {
mRetryButton.setOnClickListener(new OnClickListener() { mRetryButton.setOnClickListener(v -> {
@Override v.setOnClickListener(null);
public void onClick(View v) { mButtonContainer.setDisplayedChild(1);
v.setOnClickListener(null); setState(State.LID_PROCESS);
mButtonContainer.setDisplayedChild(1); cryptoOperation();
setState(State.LID_PROCESS);
cryptoOperation();
}
}); });
mButtonContainer.setDisplayedChild(3); mButtonContainer.setDisplayedChild(3);
setState(State.LID_ERROR); setState(State.LID_ERROR);
@@ -573,12 +548,7 @@ public class LinkedIdCreateGithubFragment extends CryptoOperationFragment<SaveKe
auth_dialog.setTitle(R.string.linked_webview_title_github); auth_dialog.setTitle(R.string.linked_webview_title_github);
auth_dialog.setCancelable(true); auth_dialog.setCancelable(true);
auth_dialog.setOnDismissListener(new OnDismissListener() { auth_dialog.setOnDismissListener(dialog -> step1GetOAuthToken());
@Override
public void onDismiss(DialogInterface dialog) {
step1GetOAuthToken();
}
});
auth_dialog.show(); auth_dialog.show();
web.loadUrl("https://" + hostAndPath + web.loadUrl("https://" + hostAndPath +

View File

@@ -17,24 +17,22 @@
package org.sufficientlysecure.keychain.ui.linked; package org.sufficientlysecure.keychain.ui.linked;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.text.Editable; import android.text.Editable;
import android.text.TextWatcher; import android.text.TextWatcher;
import android.util.Patterns; import android.util.Patterns;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.EditText; import android.widget.EditText;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.linked.resources.GenericHttpsResource;
public class LinkedIdCreateHttpsStep1Fragment extends Fragment { public class LinkedIdCreateHttpsStep1Fragment extends Fragment {
LinkedIdWizard mLinkedIdWizard;
EditText mEditUri; EditText mEditUri;
public static LinkedIdCreateHttpsStep1Fragment newInstance() { public static LinkedIdCreateHttpsStep1Fragment newInstance() {
@@ -47,44 +45,23 @@ public class LinkedIdCreateHttpsStep1Fragment extends Fragment {
} }
@Override @Override
public void onActivityCreated(Bundle savedInstanceState) { public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mLinkedIdWizard = (LinkedIdWizard) getActivity();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.linked_create_https_fragment_step1, container, false); final View view = inflater.inflate(R.layout.linked_create_https_fragment_step1, container, false);
view.findViewById(R.id.next_button).setOnClickListener(new OnClickListener() { view.findViewById(R.id.next_button).setOnClickListener(v -> {
@Override String uri = "https://" + mEditUri.getText();
public void onClick(View v) {
String uri = "https://" + mEditUri.getText();
if (!checkUri(uri)) {
return;
}
String proofText = GenericHttpsResource.generateText(getActivity(),
mLinkedIdWizard.mFingerprint);
LinkedIdCreateHttpsStep2Fragment frag =
LinkedIdCreateHttpsStep2Fragment.newInstance(uri, proofText);
mLinkedIdWizard.loadFragment(null, frag, LinkedIdWizard.FRAG_ACTION_TO_RIGHT);
if (!checkUri(uri)) {
return;
} }
LinkedIdCreateHttpsStep2Fragment frag = LinkedIdCreateHttpsStep2Fragment.newInstance(uri);
((LinkedIdWizard) requireActivity()).loadFragment(frag, LinkedIdWizard.FRAG_ACTION_TO_RIGHT);
}); });
view.findViewById(R.id.back_button).setOnClickListener(new View.OnClickListener() { view.findViewById(R.id.back_button).setOnClickListener(
@Override v -> ((LinkedIdWizard) requireActivity()).loadFragment(null, LinkedIdWizard.FRAG_ACTION_TO_LEFT));
public void onClick(View v) {
mLinkedIdWizard.loadFragment(null, null, LinkedIdWizard.FRAG_ACTION_TO_LEFT);
}
});
mEditUri = view.findViewById(R.id.linked_create_https_uri); mEditUri = view.findViewById(R.id.linked_create_https_uri);

View File

@@ -17,47 +17,46 @@
package org.sufficientlysecure.keychain.ui.linked; package org.sufficientlysecure.keychain.ui.linked;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.EditText;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
import org.sufficientlysecure.keychain.linked.resources.GenericHttpsResource;
import org.sufficientlysecure.keychain.ui.util.Notify;
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
import org.sufficientlysecure.keychain.util.FileHelper;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
public class LinkedIdCreateHttpsStep2Fragment extends LinkedIdCreateFinalFragment { import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.support.annotation.NonNull;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.linked.resources.GenericHttpsResource;
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
import org.sufficientlysecure.keychain.ui.util.Notify;
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
import org.sufficientlysecure.keychain.util.FileHelper;
import timber.log.Timber;
public class LinkedIdCreateHttpsStep2Fragment extends LinkedIdCreateFinalFragment {
private static final int REQUEST_CODE_OUTPUT = 0x00007007; private static final int REQUEST_CODE_OUTPUT = 0x00007007;
public static final String ARG_URI = "uri", ARG_TEXT = "text"; public static final String ARG_URI = "uri";
EditText mEditUri; EditText mEditUri;
URI mResourceUri; URI mResourceUri;
String mResourceString; String mResourceString;
public static LinkedIdCreateHttpsStep2Fragment newInstance public static LinkedIdCreateHttpsStep2Fragment newInstance(String uri) {
(String uri, String proofText) {
LinkedIdCreateHttpsStep2Fragment frag = new LinkedIdCreateHttpsStep2Fragment(); LinkedIdCreateHttpsStep2Fragment frag = new LinkedIdCreateHttpsStep2Fragment();
Bundle args = new Bundle(); Bundle args = new Bundle();
args.putString(ARG_URI, uri); args.putString(ARG_URI, uri);
args.putString(ARG_TEXT, proofText);
frag.setArguments(args); frag.setArguments(args);
return frag; return frag;
@@ -75,47 +74,33 @@ public class LinkedIdCreateHttpsStep2Fragment extends LinkedIdCreateFinalFragmen
try { try {
mResourceUri = new URI(getArguments().getString(ARG_URI)); mResourceUri = new URI(getArguments().getString(ARG_URI));
} catch (URISyntaxException e) { } catch (URISyntaxException e) {
e.printStackTrace(); Timber.e(e);
getActivity().finish(); requireActivity().finish();
} }
mResourceString = getArguments().getString(ARG_TEXT); mResourceString = GenericHttpsResource.generateText(requireActivity(), fingerprint);
}
protected View newView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.linked_create_https_fragment_step2, container, false);
} }
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { protected View newView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.linked_create_https_fragment_step2, container, false);
}
@NonNull
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = super.onCreateView(inflater, container, savedInstanceState); View view = super.onCreateView(inflater, container, savedInstanceState);
if (view != null) { view.findViewById(R.id.button_send).setOnClickListener(v -> proofSend());
view.findViewById(R.id.button_save).setOnClickListener(v -> proofSave());
view.findViewById(R.id.button_send).setOnClickListener(new OnClickListener() { mEditUri = view.findViewById(R.id.linked_create_https_uri);
@Override mEditUri.setText(mResourceUri.toString());
public void onClick(View v) {
proofSend();
}
});
view.findViewById(R.id.button_save).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
proofSave();
}
});
mEditUri = view.findViewById(R.id.linked_create_https_uri);
mEditUri.setText(mResourceUri.toString());
}
return view; return view;
} }
private void proofSend () { private void proofSend() {
Intent sendIntent = new Intent(); Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND); sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, mResourceString); sendIntent.putExtra(Intent.EXTRA_TEXT, mResourceString);
@@ -123,7 +108,7 @@ public class LinkedIdCreateHttpsStep2Fragment extends LinkedIdCreateFinalFragmen
startActivity(sendIntent); startActivity(sendIntent);
} }
private void proofSave () { private void proofSave() {
String state = Environment.getExternalStorageState(); String state = Environment.getExternalStorageState();
if (!Environment.MEDIA_MOUNTED.equals(state)) { if (!Environment.MEDIA_MOUNTED.equals(state)) {
Notify.create(getActivity(), "External storage not available!", Style.ERROR).show(); Notify.create(getActivity(), "External storage not available!", Style.ERROR).show();
@@ -138,8 +123,7 @@ public class LinkedIdCreateHttpsStep2Fragment extends LinkedIdCreateFinalFragmen
private void saveFile(Uri uri) { private void saveFile(Uri uri) {
try { try {
PrintWriter out = PrintWriter out = new PrintWriter(requireActivity().getContentResolver().openOutputStream(uri));
new PrintWriter(getActivity().getContentResolver().openOutputStream(uri));
out.print(mResourceString); out.print(mResourceString);
if (out.checkError()) { if (out.checkError()) {
Notify.create(getActivity(), "Error writing file!", Style.ERROR).show(); Notify.create(getActivity(), "Error writing file!", Style.ERROR).show();

View File

@@ -19,6 +19,7 @@ package org.sufficientlysecure.keychain.ui.linked;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
@@ -30,30 +31,14 @@ import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.ui.util.Notify;
public class LinkedIdCreateTwitterStep1Fragment extends Fragment { public class LinkedIdCreateTwitterStep1Fragment extends Fragment {
LinkedIdWizard mLinkedIdWizard;
EditText mEditHandle; EditText mEditHandle;
public static LinkedIdCreateTwitterStep1Fragment newInstance() { public static LinkedIdCreateTwitterStep1Fragment newInstance() {
LinkedIdCreateTwitterStep1Fragment frag = new LinkedIdCreateTwitterStep1Fragment(); return new LinkedIdCreateTwitterStep1Fragment();
Bundle args = new Bundle();
frag.setArguments(args);
return frag;
} }
@Override @Override
public void onActivityCreated(Bundle savedInstanceState) { public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mLinkedIdWizard = (LinkedIdWizard) getActivity();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.linked_create_twitter_fragment_step1, container, false); final View view = inflater.inflate(R.layout.linked_create_twitter_fragment_step1, container, false);
view.findViewById(R.id.next_button).setOnClickListener(new OnClickListener() { view.findViewById(R.id.next_button).setOnClickListener(new OnClickListener() {
@@ -96,19 +81,15 @@ public class LinkedIdCreateTwitterStep1Fragment extends Fragment {
LinkedIdCreateTwitterStep2Fragment frag = LinkedIdCreateTwitterStep2Fragment frag =
LinkedIdCreateTwitterStep2Fragment.newInstance(handle); LinkedIdCreateTwitterStep2Fragment.newInstance(handle);
mLinkedIdWizard.loadFragment(null, frag, LinkedIdWizard.FRAG_ACTION_TO_RIGHT); ((LinkedIdWizard) requireActivity()).loadFragment(frag, LinkedIdWizard.FRAG_ACTION_TO_RIGHT);
} }
}.execute(); }.execute();
} }
}); });
view.findViewById(R.id.back_button).setOnClickListener(new View.OnClickListener() { view.findViewById(R.id.back_button).setOnClickListener(
@Override v -> ((LinkedIdWizard) requireActivity()).loadFragment(null, LinkedIdWizard.FRAG_ACTION_TO_LEFT));
public void onClick(View v) {
mLinkedIdWizard.loadFragment(null, null, LinkedIdWizard.FRAG_ACTION_TO_LEFT);
}
});
mEditHandle = view.findViewById(R.id.linked_create_twitter_handle); mEditHandle = view.findViewById(R.id.linked_create_twitter_handle);

View File

@@ -17,20 +17,23 @@
package org.sufficientlysecure.keychain.ui.linked; package org.sufficientlysecure.keychain.ui.linked;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.Html; import android.text.Html;
import android.text.Spanned;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.TextView; import android.widget.TextView;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
import org.sufficientlysecure.keychain.linked.LinkedTokenResource; import org.sufficientlysecure.keychain.linked.LinkedTokenResource;
import org.sufficientlysecure.keychain.linked.resources.TwitterResource; import org.sufficientlysecure.keychain.linked.resources.TwitterResource;
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
public class LinkedIdCreateTwitterStep2Fragment extends LinkedIdCreateFinalFragment { public class LinkedIdCreateTwitterStep2Fragment extends LinkedIdCreateFinalFragment {
@@ -39,9 +42,7 @@ public class LinkedIdCreateTwitterStep2Fragment extends LinkedIdCreateFinalFragm
String mResourceHandle; String mResourceHandle;
String mResourceString; String mResourceString;
public static LinkedIdCreateTwitterStep2Fragment newInstance public static LinkedIdCreateTwitterStep2Fragment newInstance(String handle) {
(String handle) {
LinkedIdCreateTwitterStep2Fragment frag = new LinkedIdCreateTwitterStep2Fragment(); LinkedIdCreateTwitterStep2Fragment frag = new LinkedIdCreateTwitterStep2Fragment();
Bundle args = new Bundle(); Bundle args = new Bundle();
@@ -52,39 +53,23 @@ public class LinkedIdCreateTwitterStep2Fragment extends LinkedIdCreateFinalFragm
} }
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onActivityCreated(savedInstanceState);
mResourceString =
TwitterResource.generate(mLinkedIdWizard.mFingerprint);
mResourceString = TwitterResource.generate(fingerprint);
mResourceHandle = getArguments().getString(ARG_HANDLE); mResourceHandle = getArguments().getString(ARG_HANDLE);
} }
@NonNull
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = super.onCreateView(inflater, container, savedInstanceState); View view = super.onCreateView(inflater, container, savedInstanceState);
if (view != null) { view.findViewById(R.id.button_send).setOnClickListener(v -> proofSend());
view.findViewById(R.id.button_send).setOnClickListener(new OnClickListener() { view.findViewById(R.id.button_share).setOnClickListener(v -> proofShare());
@Override
public void onClick(View v) {
proofSend();
}
});
view.findViewById(R.id.button_share).setOnClickListener(new OnClickListener() { Spanned tweetText = Html.fromHtml(getString(R.string.linked_create_twitter_2_3, mResourceHandle));
@Override ((TextView) view.findViewById(R.id.linked_tweet_published)).setText(tweetText);
public void onClick(View v) {
proofShare();
}
});
((TextView) view.findViewById(R.id.linked_tweet_published)).setText(
Html.fromHtml(getString(R.string.linked_create_twitter_2_3, mResourceHandle))
);
}
return view; return view;
} }
@@ -109,13 +94,12 @@ public class LinkedIdCreateTwitterStep2Fragment extends LinkedIdCreateFinalFragm
} }
private void proofSend() { private void proofSend() {
Uri.Builder builder = Uri.parse("https://twitter.com/intent/tweet").buildUpon(); Uri.Builder builder = Uri.parse("https://twitter.com/intent/tweet").buildUpon();
builder.appendQueryParameter("text", mResourceString); builder.appendQueryParameter("text", mResourceString);
Uri uri = builder.build(); Uri uri = builder.build();
Intent intent = new Intent(Intent.ACTION_VIEW, uri); Intent intent = new Intent(Intent.ACTION_VIEW, uri);
getActivity().startActivity(intent); startActivity(intent);
} }
} }

View File

@@ -17,7 +17,9 @@
package org.sufficientlysecure.keychain.ui.linked; package org.sufficientlysecure.keychain.ui.linked;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
@@ -25,81 +27,33 @@ import android.view.ViewGroup;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
public class LinkedIdSelectFragment extends Fragment { public class LinkedIdSelectFragment extends Fragment {
LinkedIdWizard mLinkedIdWizard;
/**
* Creates new instance of this fragment
*/
public static LinkedIdSelectFragment newInstance() { public static LinkedIdSelectFragment newInstance() {
LinkedIdSelectFragment frag = new LinkedIdSelectFragment(); return new LinkedIdSelectFragment();
Bundle args = new Bundle();
frag.setArguments(args);
return frag;
} }
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.linked_select_fragment, container, false); View view = inflater.inflate(R.layout.linked_select_fragment, container, false);
view.findViewById(R.id.linked_create_https_button) view.findViewById(R.id.linked_create_https_button).setOnClickListener(v -> {
.setOnClickListener(new View.OnClickListener() { LinkedIdCreateHttpsStep1Fragment frag = LinkedIdCreateHttpsStep1Fragment.newInstance();
@Override ((LinkedIdWizard) requireActivity()).loadFragment(frag, LinkedIdWizard.FRAG_ACTION_TO_RIGHT);
public void onClick(View v) { });
LinkedIdCreateHttpsStep1Fragment frag =
LinkedIdCreateHttpsStep1Fragment.newInstance();
mLinkedIdWizard.loadFragment(null, frag, LinkedIdWizard.FRAG_ACTION_TO_RIGHT); view.findViewById(R.id.linked_create_twitter_button).setOnClickListener(v -> {
} LinkedIdCreateTwitterStep1Fragment frag = LinkedIdCreateTwitterStep1Fragment.newInstance();
}); ((LinkedIdWizard) requireActivity()).loadFragment(frag, LinkedIdWizard.FRAG_ACTION_TO_RIGHT);
});
/* view.findViewById(R.id.linked_create_github_button).setOnClickListener(v -> {
view.findViewById(R.id.linked_create_dns_button) LinkedIdCreateGithubFragment frag = LinkedIdCreateGithubFragment.newInstance();
.setOnClickListener(new View.OnClickListener() { ((LinkedIdWizard) requireActivity()).loadFragment(frag, LinkedIdWizard.FRAG_ACTION_TO_RIGHT);
@Override });
public void onClick(View v) {
LinkedIdCreateDnsStep1Fragment frag =
LinkedIdCreateDnsStep1Fragment.newInstance();
mLinkedIdWizard.loadFragment(null, frag, LinkedIdWizard.FRAG_ACTION_TO_RIGHT);
}
});
*/
view.findViewById(R.id.linked_create_twitter_button)
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
LinkedIdCreateTwitterStep1Fragment frag =
LinkedIdCreateTwitterStep1Fragment.newInstance();
mLinkedIdWizard.loadFragment(null, frag, LinkedIdWizard.FRAG_ACTION_TO_RIGHT);
}
});
view.findViewById(R.id.linked_create_github_button)
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
LinkedIdCreateGithubFragment frag =
LinkedIdCreateGithubFragment.newInstance();
mLinkedIdWizard.loadFragment(null, frag, LinkedIdWizard.FRAG_ACTION_TO_RIGHT);
}
});
return view; return view;
} }
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mLinkedIdWizard = (LinkedIdWizard) getActivity();
}
} }

View File

@@ -18,64 +18,60 @@
package org.sufficientlysecure.keychain.ui.linked; package org.sufficientlysecure.keychain.ui.linked;
import android.arch.lifecycle.ViewModelProviders;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction; import android.support.v4.app.FragmentTransaction;
import android.support.v4.app.NavUtils;
import android.support.v4.app.TaskStackBuilder;
import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodManager;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
import org.sufficientlysecure.keychain.provider.KeyRepository;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.ui.base.BaseActivity; import org.sufficientlysecure.keychain.ui.base.BaseActivity;
import org.sufficientlysecure.keychain.ui.keyview.UnifiedKeyInfoViewModel;
import timber.log.Timber; import timber.log.Timber;
public class LinkedIdWizard extends BaseActivity { public class LinkedIdWizard extends BaseActivity {
public static final String EXTRA_MASTER_KEY_ID = "master_key_id";
public static final int FRAG_ACTION_START = 0; public static final int FRAG_ACTION_START = 0;
public static final int FRAG_ACTION_TO_RIGHT = 1; public static final int FRAG_ACTION_TO_RIGHT = 1;
public static final int FRAG_ACTION_TO_LEFT = 2; public static final int FRAG_ACTION_TO_LEFT = 2;
long mMasterKeyId;
byte[] mFingerprint;
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setTitle(getString(R.string.title_linked_id_create)); setTitle(getString(R.string.title_linked_id_create));
try { Bundle extras = getIntent().getExtras();
Uri uri = getIntent().getData(); if (extras == null || !extras.containsKey(EXTRA_MASTER_KEY_ID)) {
uri = KeychainContract.KeyRings.buildUnifiedKeyRingUri(uri); Timber.e("Missing required extra master_key_id!");
CachedPublicKeyRing ring = KeyRepository.create(this).getCachedPublicKeyRing(uri);
if (!ring.hasAnySecret()) {
Timber.e("Linked Identities can only be added to secret keys!");
finish();
return;
}
mMasterKeyId = ring.extractOrGetMasterKeyId();
mFingerprint = ring.getFingerprint();
} catch (PgpKeyNotFoundException e) {
Timber.e("Invalid uri given, key does not exist!");
finish(); finish();
return; return;
} }
long masterKeyId = extras.getLong(EXTRA_MASTER_KEY_ID);
UnifiedKeyInfoViewModel viewModel = ViewModelProviders.of(this).get(UnifiedKeyInfoViewModel.class);
viewModel.setMasterKeyId(masterKeyId);
viewModel.getUnifiedKeyInfoLiveData(this).observe(this, this::onLoadUnifiedKeyInfo);
hideKeyboard();
// pass extras into fragment // pass extras into fragment
LinkedIdSelectFragment frag = LinkedIdSelectFragment.newInstance(); if (savedInstanceState == null) {
loadFragment(null, frag, FRAG_ACTION_START); LinkedIdSelectFragment frag = LinkedIdSelectFragment.newInstance();
loadFragment(frag, FRAG_ACTION_START);
}
}
private void onLoadUnifiedKeyInfo(UnifiedKeyInfo unifiedKeyInfo) {
if (!unifiedKeyInfo.has_any_secret()) {
Timber.e("Linked Identities can only be added to secret keys!");
finish();
}
} }
@Override @Override
@@ -83,16 +79,7 @@ public class LinkedIdWizard extends BaseActivity {
setContentView(R.layout.create_key_activity); setContentView(R.layout.create_key_activity);
} }
public void loadFragment(Bundle savedInstanceState, Fragment fragment, int action) { public void loadFragment(Fragment fragment, int action) {
// However, if we're being restored from a previous state,
// then we don't need to do anything and should return or else
// we could end up with overlapping fragments.
if (savedInstanceState != null) {
return;
}
hideKeyboard();
// Add the fragment to the 'fragment_container' FrameLayout // Add the fragment to the 'fragment_container' FrameLayout
// NOTE: We use commitAllowingStateLoss() to prevent weird crashes! // NOTE: We use commitAllowingStateLoss() to prevent weird crashes!
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
@@ -115,50 +102,17 @@ public class LinkedIdWizard extends BaseActivity {
break; break;
} }
// do it immediately!
getSupportFragmentManager().executePendingTransactions(); getSupportFragmentManager().executePendingTransactions();
} }
private void hideKeyboard() { private void hideKeyboard() {
InputMethodManager inputManager = (InputMethodManager) InputMethodManager inputManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
getSystemService(Context.INPUT_METHOD_SERVICE);
// check if no view has focus
View v = getCurrentFocus(); View v = getCurrentFocus();
if (v == null) if (v == null || inputManager == null) {
return; return;
}
inputManager.hideSoftInputFromWindow(v.getWindowToken(), 0); inputManager.hideSoftInputFromWindow(v.getWindowToken(), 0);
} }
@Override
public void onBackPressed() {
if (!getFragmentManager().popBackStackImmediate()) {
navigateBack();
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
// Respond to the action bar's Up/Home button
case android.R.id.home:
navigateBack();
return true;
}
return super.onOptionsItemSelected(item);
}
private void navigateBack() {
Intent upIntent = NavUtils.getParentActivityIntent(this);
upIntent.setData(KeyRings.buildGenericKeyRingUri(mMasterKeyId));
// This activity is NOT part of this app's task, so create a new task
// when navigating up, with a synthesized back stack.
TaskStackBuilder.create(this)
// Add all of this activity's parents to the back stack
.addNextIntentWithParentStack(upIntent)
// Navigate up to the closest parent
.startActivities();
}
} }