import: simplify ImportKeysActivity, don't display search bar for fixed input

This commit is contained in:
Vincent Breitmoser 2015-09-30 03:11:54 +02:00
parent 4025acd13a
commit 43e661790d
2 changed files with 109 additions and 168 deletions

View file

@ -21,8 +21,8 @@ import android.app.Activity;
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.os.Message;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
import android.view.ViewGroup; import android.view.ViewGroup;
@ -33,10 +33,8 @@ import org.sufficientlysecure.keychain.intents.OpenKeychainIntents;
import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry; import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry;
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.service.ImportKeyringParcel; import org.sufficientlysecure.keychain.service.ImportKeyringParcel;
import org.sufficientlysecure.keychain.ui.base.BaseNfcActivity; import org.sufficientlysecure.keychain.ui.base.BaseNfcActivity;
import org.sufficientlysecure.keychain.service.ServiceProgressHandler;
import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper; import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.ui.util.Notify;
@ -78,10 +76,8 @@ public class ImportKeysActivity extends BaseNfcActivity
public static final String EXTRA_PENDING_INTENT_DATA = "data"; public static final String EXTRA_PENDING_INTENT_DATA = "data";
private Intent mPendingIntentData; private Intent mPendingIntentData;
// view public static final String TAG_FRAG_LIST = "frag_list";
private ImportKeysListFragment mListFragment; public static final String TAG_FRAG_TOP = "frag_top";
private Fragment mTopFragment;
private View mImportButton;
// for CryptoOperationHelper.Callback // for CryptoOperationHelper.Callback
private String mKeyserver; private String mKeyserver;
@ -94,15 +90,22 @@ public class ImportKeysActivity extends BaseNfcActivity
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setFullScreenDialogClose(Activity.RESULT_CANCELED, true); setFullScreenDialogClose(Activity.RESULT_CANCELED, true);
mImportButton = findViewById(R.id.import_import); findViewById(R.id.import_import).setOnClickListener(new OnClickListener() {
mImportButton.setOnClickListener(new OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
importKeys(); importSelectedKeys();
} }
}); });
handleActions(savedInstanceState, getIntent()); // only used for OpenPgpService
if (getIntent().hasExtra(EXTRA_PENDING_INTENT_DATA)) {
mPendingIntentData = getIntent().getParcelableExtra(EXTRA_PENDING_INTENT_DATA);
}
// if we aren't being restored, initialize fragments
if (savedInstanceState == null) {
handleActions(getIntent());
}
} }
@Override @Override
@ -110,7 +113,7 @@ public class ImportKeysActivity extends BaseNfcActivity
setContentView(R.layout.import_keys_activity); setContentView(R.layout.import_keys_activity);
} }
protected void handleActions(Bundle savedInstanceState, Intent intent) { protected void handleActions(Intent intent) {
String action = intent.getAction(); String action = intent.getAction();
Bundle extras = intent.getExtras(); Bundle extras = intent.getExtras();
Uri dataUri = intent.getData(); Uri dataUri = intent.getData();
@ -120,14 +123,8 @@ public class ImportKeysActivity extends BaseNfcActivity
extras = new Bundle(); extras = new Bundle();
} }
if (action == null) {
startCloudFragment(savedInstanceState, null, false, null);
startListFragment(savedInstanceState, null, null, null, null);
return;
}
if (Intent.ACTION_VIEW.equals(action)) { if (Intent.ACTION_VIEW.equals(action)) {
if (scheme.equals("http") || scheme.equals("https")) { if ("http".equals(scheme) || "https".equals(scheme)) {
action = ACTION_SEARCH_KEYSERVER_FROM_URL; action = ACTION_SEARCH_KEYSERVER_FROM_URL;
} else { } else {
// Android's Action when opening file associated to Keychain (see AndroidManifest.xml) // Android's Action when opening file associated to Keychain (see AndroidManifest.xml)
@ -135,20 +132,24 @@ public class ImportKeysActivity extends BaseNfcActivity
action = ACTION_IMPORT_KEY; action = ACTION_IMPORT_KEY;
} }
} }
if (action == null) {
// -> switch to default below
action = "";
}
switch (action) { switch (action) {
case ACTION_IMPORT_KEY: { case ACTION_IMPORT_KEY: {
/* Keychain's own Actions */
startFileFragment(savedInstanceState);
if (dataUri != null) { if (dataUri != null) {
// action: directly load data // action: directly load data
startListFragment(savedInstanceState, null, dataUri, null, null); startListFragment(null, dataUri, null, null);
} else if (extras.containsKey(EXTRA_KEY_BYTES)) { } else if (extras.containsKey(EXTRA_KEY_BYTES)) {
byte[] importData = extras.getByteArray(EXTRA_KEY_BYTES); byte[] importData = extras.getByteArray(EXTRA_KEY_BYTES);
// action: directly load data // action: directly load data
startListFragment(savedInstanceState, importData, null, null, null); startListFragment(importData, null, null, null);
} else {
startTopFileFragment();
startListFragment(null, null, null, null);
} }
break; break;
} }
@ -156,10 +157,6 @@ public class ImportKeysActivity extends BaseNfcActivity
case ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_TO_SERVICE: case ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_TO_SERVICE:
case ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_RESULT: { case ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_RESULT: {
// only used for OpenPgpService
if (extras.containsKey(EXTRA_PENDING_INTENT_DATA)) {
mPendingIntentData = extras.getParcelable(EXTRA_PENDING_INTENT_DATA);
}
if (extras.containsKey(EXTRA_QUERY) || extras.containsKey(EXTRA_KEY_ID)) { if (extras.containsKey(EXTRA_QUERY) || extras.containsKey(EXTRA_KEY_ID)) {
/* simple search based on query or key id */ /* simple search based on query or key id */
@ -175,10 +172,10 @@ public class ImportKeysActivity extends BaseNfcActivity
if (query != null && query.length() > 0) { if (query != null && query.length() > 0) {
// display keyserver fragment with query // display keyserver fragment with query
startCloudFragment(savedInstanceState, query, false, null); startTopCloudFragment(query, false, null);
// action: search immediately // action: search immediately
startListFragment(savedInstanceState, null, null, query, null); startListFragment(null, null, query, null);
} else { } else {
Log.e(Constants.TAG, "Query is empty!"); Log.e(Constants.TAG, "Query is empty!");
return; return;
@ -194,10 +191,10 @@ public class ImportKeysActivity extends BaseNfcActivity
String query = "0x" + fingerprint; String query = "0x" + fingerprint;
// display keyserver fragment with query // display keyserver fragment with query
startCloudFragment(savedInstanceState, query, true, null); startTopCloudFragment(query, true, null);
// action: search immediately // action: search immediately
startListFragment(savedInstanceState, null, null, query, null); startListFragment(null, null, query, null);
} }
} else { } else {
Log.e(Constants.TAG, Log.e(Constants.TAG,
@ -208,14 +205,6 @@ public class ImportKeysActivity extends BaseNfcActivity
} }
break; break;
} }
case ACTION_IMPORT_KEY_FROM_FILE: {
// NOTE: this only displays the appropriate fragment, no actions are taken
startFileFragment(savedInstanceState);
// no immediate actions!
startListFragment(savedInstanceState, null, null, null, null);
break;
}
case ACTION_SEARCH_KEYSERVER_FROM_URL: { case ACTION_SEARCH_KEYSERVER_FROM_URL: {
// need to process URL to get search query and keyserver authority // need to process URL to get search query and keyserver authority
String query = dataUri.getQueryParameter("search"); String query = dataUri.getQueryParameter("search");
@ -223,120 +212,88 @@ public class ImportKeysActivity extends BaseNfcActivity
// if query not specified, we still allow users to search the keyserver in the link // if query not specified, we still allow users to search the keyserver in the link
if (query == null) { if (query == null) {
Notify.create(this, R.string.import_url_warn_no_search_parameter, Notify.LENGTH_INDEFINITE, Notify.create(this, R.string.import_url_warn_no_search_parameter, Notify.LENGTH_INDEFINITE,
Notify.Style.WARN).show(mTopFragment); Notify.Style.WARN).show();
// we just set the keyserver // we just set the keyserver
startCloudFragment(savedInstanceState, null, false, keyserver); startTopCloudFragment(null, false, keyserver);
// we don't set the keyserver for ImportKeysListFragment since // we don't set the keyserver for ImportKeysListFragment since
// it'll be set in the cloudSearchPrefs of ImportKeysCloudFragment // it'll be set in the cloudSearchPrefs of ImportKeysCloudFragment
// which is used when the user clicks on the search button // which is used when the user clicks on the search button
startListFragment(savedInstanceState, null, null, null, null); startListFragment(null, null, null, null);
} else { } else {
// we allow our users to edit the query if they wish // we allow our users to edit the query if they wish
startCloudFragment(savedInstanceState, query, false, keyserver); startTopCloudFragment(query, false, keyserver);
// search immediately // search immediately
startListFragment(savedInstanceState, null, null, query, keyserver); startListFragment(null, null, query, keyserver);
} }
break; break;
} }
case ACTION_IMPORT_KEY_FROM_FILE:
case ACTION_IMPORT_KEY_FROM_FILE_AND_RETURN: { case ACTION_IMPORT_KEY_FROM_FILE_AND_RETURN: {
// NOTE: this only displays the appropriate fragment, no actions are taken // NOTE: this only displays the appropriate fragment, no actions are taken
startFileFragment(savedInstanceState); startTopFileFragment();
startListFragment(null, null, null, null);
// no immediate actions!
startListFragment(savedInstanceState, null, null, null, null);
break; break;
} }
default: { default: {
startCloudFragment(savedInstanceState, null, false, null); startTopCloudFragment(null, false, null);
startListFragment(savedInstanceState, null, null, null, null); startListFragment(null, null, null, null);
break; break;
} }
} }
} }
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
// the only thing we need to take care of for restoring state is
// that the top layout is shown iff it contains a fragment
Fragment topFragment = getSupportFragmentManager().findFragmentByTag(TAG_FRAG_TOP);
boolean hasTopFragment = topFragment != null;
findViewById(R.id.import_keys_top_layout).setVisibility(hasTopFragment ? View.VISIBLE : View.GONE);
}
/** /**
* if the fragment is started with non-null bytes/dataUri/serverQuery, it will immediately * if the fragment is started with non-null bytes/dataUri/serverQuery, it will immediately
* load content * load content
* *
* @param savedInstanceState
* @param bytes bytes containing list of keyrings to import * @param bytes bytes containing list of keyrings to import
* @param dataUri uri to file to import keyrings from * @param dataUri uri to file to import keyrings from
* @param serverQuery query to search for on the keyserver * @param serverQuery query to search for on the keyserver
* @param keyserver keyserver authority to search on. If null will use keyserver from * @param keyserver keyserver authority to search on. If null will use keyserver from
* user preferences * user preferences
*/ */
private void startListFragment(Bundle savedInstanceState, byte[] bytes, Uri dataUri, private void startListFragment(byte[] bytes, Uri dataUri, String serverQuery, String keyserver) {
String serverQuery, String keyserver) { Fragment listFragment =
// However, if we're being restored from a previous state, ImportKeysListFragment.newInstance(bytes, dataUri, serverQuery, false, keyserver);
// then we don't need to do anything and should return or else
// we could end up with overlapping fragments.
if (mListFragment != null) {
return;
}
mListFragment = ImportKeysListFragment.newInstance(bytes, dataUri, serverQuery, false,
keyserver);
// Add the fragment to the 'fragment_container' FrameLayout
// NOTE: We use commitAllowingStateLoss() to prevent weird crashes!
getSupportFragmentManager().beginTransaction() getSupportFragmentManager().beginTransaction()
.replace(R.id.import_keys_list_container, mListFragment) .replace(R.id.import_keys_list_container, listFragment, TAG_FRAG_LIST)
.commitAllowingStateLoss(); .commit();
// do it immediately!
getSupportFragmentManager().executePendingTransactions();
} }
private void startFileFragment(Bundle savedInstanceState) { private void startTopFileFragment() {
// However, if we're being restored from a previous state, findViewById(R.id.import_keys_top_layout).setVisibility(View.VISIBLE);
// then we don't need to do anything and should return or else Fragment importFileFragment = ImportKeysFileFragment.newInstance();
// we could end up with overlapping fragments.
if (mTopFragment != null) {
return;
}
// Create an instance of the fragment
mTopFragment = ImportKeysFileFragment.newInstance();
// Add the fragment to the 'fragment_container' FrameLayout
// NOTE: We use commitAllowingStateLoss() to prevent weird crashes!
getSupportFragmentManager().beginTransaction() getSupportFragmentManager().beginTransaction()
.replace(R.id.import_keys_top_container, mTopFragment) .replace(R.id.import_keys_top_container, importFileFragment, TAG_FRAG_TOP)
.commitAllowingStateLoss(); .commit();
// do it immediately!
getSupportFragmentManager().executePendingTransactions();
} }
/** /**
* loads the CloudFragment, which consists of the search bar, search button and settings icon * loads the CloudFragment, which consists of the search bar, search button and settings icon
* visually. * visually.
* *
* @param savedInstanceState
* @param query search query * @param query search query
* @param disableQueryEdit if true, user will not be able to edit the search query * @param disableQueryEdit if true, user will not be able to edit the search query
* @param keyserver keyserver authority to use for search, if null will use keyserver * @param keyserver keyserver authority to use for search, if null will use keyserver
* specified in user preferences * specified in user preferences
*/ */
private void startTopCloudFragment(String query, boolean disableQueryEdit, String keyserver) {
private void startCloudFragment(Bundle savedInstanceState, String query, boolean disableQueryEdit, String findViewById(R.id.import_keys_top_layout).setVisibility(View.VISIBLE);
keyserver) { Fragment importCloudFragment = ImportKeysCloudFragment.newInstance(query, disableQueryEdit, keyserver);
// 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 (mTopFragment != null) {
return;
}
// Create an instance of the fragment
mTopFragment = ImportKeysCloudFragment.newInstance(query, disableQueryEdit, keyserver);
// Add the fragment to the 'fragment_container' FrameLayout
// NOTE: We use commitAllowingStateLoss() to prevent weird crashes!
getSupportFragmentManager().beginTransaction() getSupportFragmentManager().beginTransaction()
.replace(R.id.import_keys_top_container, mTopFragment) .replace(R.id.import_keys_top_container, importCloudFragment, TAG_FRAG_TOP)
.commitAllowingStateLoss(); .commit();
// do it immediately!
getSupportFragmentManager().executePendingTransactions();
} }
private boolean isFingerprintValid(String fingerprint) { private boolean isFingerprintValid(String fingerprint) {
@ -350,63 +307,32 @@ public class ImportKeysActivity extends BaseNfcActivity
} }
public void loadCallback(final ImportKeysListFragment.LoaderState loaderState) { public void loadCallback(final ImportKeysListFragment.LoaderState loaderState) {
mListFragment.loadNew(loaderState); FragmentManager fragMan = getSupportFragmentManager();
ImportKeysListFragment keyListFragment = (ImportKeysListFragment) fragMan.findFragmentByTag(TAG_FRAG_LIST);
keyListFragment.loadNew(loaderState);
} }
private void handleMessage(Message message) { private void importSelectedKeys() {
if (message.arg1 == ServiceProgressHandler.MessageStatus.OKAY.ordinal()) {
// get returned data bundle
Bundle returnData = message.getData();
if (returnData == null) {
return;
}
final ImportKeyResult result =
returnData.getParcelable(OperationResult.EXTRA_RESULT);
if (result == null) {
Log.e(Constants.TAG, "result == null");
return;
}
if (ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_RESULT.equals(getIntent().getAction()) FragmentManager fragMan = getSupportFragmentManager();
|| ACTION_IMPORT_KEY_FROM_FILE_AND_RETURN.equals(getIntent().getAction())) { ImportKeysListFragment keyListFragment = (ImportKeysListFragment) fragMan.findFragmentByTag(TAG_FRAG_LIST);
Intent intent = new Intent();
intent.putExtra(ImportKeyResult.EXTRA_RESULT, result);
ImportKeysActivity.this.setResult(RESULT_OK, intent);
ImportKeysActivity.this.finish();
return;
}
if (ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_TO_SERVICE.equals(getIntent().getAction())) {
ImportKeysActivity.this.setResult(RESULT_OK, mPendingIntentData);
ImportKeysActivity.this.finish();
return;
}
result.createNotify(ImportKeysActivity.this) if (keyListFragment.getSelectedEntries().size() == 0) {
.show((ViewGroup) findViewById(R.id.import_snackbar));
}
}
/**
* Import keys with mImportData
*/
public void importKeys() {
if (mListFragment.getSelectedEntries().size() == 0) {
Notify.create(this, R.string.error_nothing_import_selected, Notify.Style.ERROR) Notify.create(this, R.string.error_nothing_import_selected, Notify.Style.ERROR)
.show((ViewGroup) findViewById(R.id.import_snackbar)); .show((ViewGroup) findViewById(R.id.import_snackbar));
return; return;
} }
mOperationHelper = new CryptoOperationHelper<ImportKeyringParcel, ImportKeyResult>( mOperationHelper = new CryptoOperationHelper<>(
1, this, this, R.string.progress_importing 1, this, this, R.string.progress_importing
); );
ImportKeysListFragment.LoaderState ls = mListFragment.getLoaderState(); ImportKeysListFragment.LoaderState ls = keyListFragment.getLoaderState();
if (ls instanceof ImportKeysListFragment.BytesLoaderState) { if (ls instanceof ImportKeysListFragment.BytesLoaderState) {
Log.d(Constants.TAG, "importKeys started"); Log.d(Constants.TAG, "importKeys started");
// get DATA from selected key entries // get DATA from selected key entries
IteratorWithSize<ParcelableKeyRing> selectedEntries = mListFragment.getSelectedData(); IteratorWithSize<ParcelableKeyRing> selectedEntries = keyListFragment.getSelectedData();
// instead of giving the entries by Intent extra, cache them into a // instead of giving the entries by Intent extra, cache them into a
// file to prevent Java Binder problems on heavy imports // file to prevent Java Binder problems on heavy imports
@ -435,7 +361,7 @@ public class ImportKeysActivity extends BaseNfcActivity
ArrayList<ParcelableKeyRing> keys = new ArrayList<>(); ArrayList<ParcelableKeyRing> keys = new ArrayList<>();
{ {
// change the format into ParcelableKeyRing // change the format into ParcelableKeyRing
ArrayList<ImportKeysListEntry> entries = mListFragment.getSelectedEntries(); ArrayList<ImportKeysListEntry> entries = keyListFragment.getSelectedEntries();
for (ImportKeysListEntry entry : entries) { for (ImportKeysListEntry entry : entries) {
keys.add(new ParcelableKeyRing( keys.add(new ParcelableKeyRing(
entry.getFingerprintHex(), entry.getKeyIdHex(), entry.getExtraData()) entry.getFingerprintHex(), entry.getKeyIdHex(), entry.getExtraData())
@ -458,24 +384,28 @@ public class ImportKeysActivity extends BaseNfcActivity
@Override @Override
public void onActivityResult(int requestCode, int resultCode, Intent data) { public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (mOperationHelper == null || if (mOperationHelper != null &&
!mOperationHelper.handleActivityResult(requestCode, resultCode, data)) { mOperationHelper.handleActivityResult(requestCode, resultCode, data)) {
super.onActivityResult(requestCode, resultCode, data); return;
} }
super.onActivityResult(requestCode, resultCode, data);
} }
public void handleResult(ImportKeyResult result) { public void handleResult(ImportKeyResult result) {
if (ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_RESULT.equals(getIntent().getAction()) String intentAction = getIntent().getAction();
|| ACTION_IMPORT_KEY_FROM_FILE_AND_RETURN.equals(getIntent().getAction())) {
if (ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_RESULT.equals(intentAction)
|| ACTION_IMPORT_KEY_FROM_FILE_AND_RETURN.equals(intentAction)) {
Intent intent = new Intent(); Intent intent = new Intent();
intent.putExtra(ImportKeyResult.EXTRA_RESULT, result); intent.putExtra(ImportKeyResult.EXTRA_RESULT, result);
ImportKeysActivity.this.setResult(RESULT_OK, intent); setResult(RESULT_OK, intent);
ImportKeysActivity.this.finish(); finish();
return; return;
} }
if (ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_TO_SERVICE.equals(getIntent().getAction())) {
ImportKeysActivity.this.setResult(RESULT_OK, mPendingIntentData); if (ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_TO_SERVICE.equals(intentAction)) {
ImportKeysActivity.this.finish(); setResult(RESULT_OK, mPendingIntentData);
finish();
return; return;
} }

View file

@ -1,7 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools">
<include <include
android:id="@+id/toolbar_include" android:id="@+id/toolbar_include"
@ -21,16 +22,26 @@
<include layout="@layout/notify_area" /> <include layout="@layout/notify_area" />
<FrameLayout <LinearLayout
android:id="@+id/import_keys_top_container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="64dp" android:layout_height="wrap_content"
android:orientation="vertical" /> android:orientation="vertical"
android:id="@+id/import_keys_top_layout"
android:visibility="gone"
tools:visibility="visible">
<View <FrameLayout
android:layout_width="match_parent" android:id="@+id/import_keys_top_container"
android:layout_height="1dip" android:layout_width="match_parent"
android:background="?android:attr/listDivider" /> android:layout_height="64dp"
android:orientation="vertical" />
<View
android:layout_width="match_parent"
android:layout_height="1dip"
android:background="?android:attr/listDivider" />
</LinearLayout>
<FrameLayout <FrameLayout
android:id="@+id/import_keys_list_container" android:id="@+id/import_keys_list_container"