Work on new Import activity

This commit is contained in:
Dominik Schürmann 2013-09-19 02:02:51 +02:00
parent 4c461c1b44
commit 3c4cb1c2d3
20 changed files with 655 additions and 234 deletions

View File

@ -31,13 +31,20 @@
android:id="@+id/input" android:id="@+id/input"
android:layout_width="0dip" android:layout_width="0dip"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" /> android:layout_weight="1"
android:gravity="top|left"
android:inputType="textMultiLine|textUri"
android:lines="2"
android:maxLines="6"
android:minLines="2"
android:scrollbars="vertical" />
<ImageButton <ImageButton
android:id="@+id/btn_browse" android:id="@+id/btn_browse"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
android:contentDescription="@string/filemanager_titleOpen"
android:src="@drawable/ic_menu_filebrowser" /> android:src="@drawable/ic_menu_filebrowser" />
</LinearLayout> </LinearLayout>

View File

@ -4,8 +4,17 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_centerHorizontal="true" > android:layout_centerHorizontal="true" >
<FrameLayout
android:id="@+id/import_navigation_fragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:orientation="vertical"
android:paddingLeft="4dp"
android:paddingRight="4dp" />
<LinearLayout <LinearLayout
android:id="@+id/import_from_qr_code_footer" android:id="@+id/import_footer"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentBottom="true" android:layout_alignParentBottom="true"
@ -14,50 +23,29 @@
android:paddingRight="10dp" > android:paddingRight="10dp" >
<Button <Button
android:id="@+id/import_from_qr_code_import" android:id="@+id/import_import"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:onClick="importOnClick" android:onClick="importOnClick"
android:text="@string/import_from_qr_code_import" /> android:text="@string/import_import" />
<Button <Button
android:id="@+id/import_from_qr_code_import_sign_and_upload" android:id="@+id/import_sign_and_upload"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:onClick="signAndUploadOnClick" android:onClick="signAndUploadOnClick"
android:text="@string/import_from_qr_code_import_sign_and_upload" /> android:text="@string/import_sign_and_upload" />
<Button
android:id="@+id/import_from_qr_code_finish"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="finishOnClick"
android:text="@string/import_from_qr_code_finish" />
</LinearLayout> </LinearLayout>
<ScrollView <FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@id/import_from_qr_code_footer"
android:fillViewport="true" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="12dp"
android:paddingRight="12dp" >
<LinearLayout
android:id="@+id/import_keys_list_container" android:id="@+id/import_keys_list_container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="match_parent"
android:layout_marginTop="16dp" android:layout_above="@+id/import_footer"
android:layout_alignParentLeft="true"
android:layout_below="@+id/import_navigation_fragment"
android:orientation="vertical" android:orientation="vertical"
android:paddingLeft="4dp" android:paddingLeft="4dp"
android:paddingRight="4dp" > android:paddingRight="4dp" />
</LinearLayout>
</LinearLayout>
</ScrollView>
</RelativeLayout> </RelativeLayout>

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<EditText
android:id="@+id/import_keys_file_input"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="top|left"
android:inputType="textMultiLine|textUri"
android:lines="2"
android:maxLines="6"
android:minLines="2"
android:scrollbars="vertical" />
<ImageButton
android:id="@+id/import_keys_file_browse"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:contentDescription="@string/filemanager_titleOpen"
android:src="@drawable/ic_menu_filebrowser" />
</LinearLayout>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
</LinearLayout>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<Button
android:id="@+id/import_nfc_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/menu_importFromNfc" />
</LinearLayout>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<Button
android:id="@+id/import_qrcode_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/menu_importFromQrCode" />
</LinearLayout>

View File

@ -49,4 +49,11 @@
<item>@string/key_size_2048</item> <item>@string/key_size_2048</item>
<item>@string/key_size_4096</item> <item>@string/key_size_4096</item>
</string-array> </string-array>
<string-array name="import_action_list">
<item>@string/menu_importFromFile</item>
<item>@string/menu_keyServer</item>
<item>@string/menu_importFromQrCode</item>
<item>@string/menu_importFromNfc</item>
</string-array>
</resources> </resources>

View File

@ -346,10 +346,10 @@
<string name="help_tab_about">About</string> <string name="help_tab_about">About</string>
<string name="help_about_version">Version:</string> <string name="help_about_version">Version:</string>
<!-- Import from QR Code --> <!-- Import -->
<string name="import_from_qr_code_import">Import key(s) (only locally)</string> <string name="import_import">Import key(s) (only locally)</string>
<string name="import_from_qr_code_import_sign_and_upload">Import, Sign, and upload key(s)</string> <string name="import_sign_and_upload">Import, Sign, and upload key(s)</string>
<string name="import_from_qr_code_finish">Finish</string> <string name="import_finish">Finish</string>
<!-- Intent labels --> <!-- Intent labels -->
<string name="intent_decrypt_file">OpenPGP: Decrypt File</string> <string name="intent_decrypt_file">OpenPGP: Decrypt File</string>

View File

@ -28,6 +28,7 @@ import android.content.Intent;
import android.database.Cursor; import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
import android.os.Environment; import android.os.Environment;
import android.support.v4.app.Fragment;
import android.widget.Toast; import android.widget.Toast;
public class FileHelper { public class FileHelper {
@ -55,18 +56,14 @@ public class FileHelper {
* @param activity * @param activity
* @param filename * @param filename
* default selected file, not supported by all file managers * default selected file, not supported by all file managers
* @param type * @param mimeType
* can be text/plain for example * can be text/plain for example
* @param requestCode * @param requestCode
* requestCode used to identify the result coming back from file manager to * requestCode used to identify the result coming back from file manager to
* onActivityResult() in your activity * onActivityResult() in your activity
*/ */
public static void openFile(Activity activity, String filename, String type, int requestCode) { public static void openFile(Activity activity, String filename, String mimeType, int requestCode) {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT); Intent intent = buildFileIntent(filename, mimeType);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setData(Uri.parse("file://" + filename));
intent.setType(type);
try { try {
activity.startActivityForResult(intent, requestCode); activity.startActivityForResult(intent, requestCode);
@ -76,6 +73,28 @@ public class FileHelper {
} }
} }
public static void openFile(Fragment fragment, String filename, String mimeType, int requestCode) {
Intent intent = buildFileIntent(filename, mimeType);
try {
fragment.startActivityForResult(intent, requestCode);
} catch (ActivityNotFoundException e) {
// No compatible file manager was found.
Toast.makeText(fragment.getActivity(), R.string.noFilemanagerInstalled,
Toast.LENGTH_SHORT).show();
}
}
private static Intent buildFileIntent(String filename, String mimeType) {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setData(Uri.parse("file://" + filename));
intent.setType(mimeType);
return intent;
}
/** /**
* Get a file path from a Uri. * Get a file path from a Uri.
* *

View File

@ -0,0 +1,122 @@
/*
* Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.sufficientlysecure.keychain.ui;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.FileHelper;
import org.sufficientlysecure.keychain.util.Log;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.ImageButton;
public class ImportFileFragment extends Fragment {
public static final String ARG_PATH = "path";
private ImportKeysActivity mImportActivity;
private EditText mFilename;
private ImageButton mBrowse;
/**
* Creates new instance of this fragment
*/
public static ImportFileFragment newInstance(String path) {
ImportFileFragment frag = new ImportFileFragment();
Bundle args = new Bundle();
args.putString(ARG_PATH, path);
frag.setArguments(args);
return frag;
}
/**
* Inflate the layout for this fragment
*/
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.import_keys_file_fragment, container, false);
mFilename = (EditText) view.findViewById(R.id.import_keys_file_input);
mBrowse = (ImageButton) view.findViewById(R.id.import_keys_file_browse);
mBrowse.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// open .asc or .gpg files
// setting it to text/plain prevents Cynaogenmod's file manager from selecting asc
// or gpg types!
FileHelper.openFile(ImportFileFragment.this, mFilename.getText().toString(), "*/*",
Id.request.filename);
}
});
return view;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mImportActivity = (ImportKeysActivity) getActivity();
// set default path
String path = Constants.path.APP_DIR + "/";
if (getArguments() != null) {
path = getArguments().getString(ARG_PATH);
}
mFilename.setText(path);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case Id.request.filename: {
if (resultCode == Activity.RESULT_OK && data != null) {
try {
String path = data.getData().getPath();
Log.d(Constants.TAG, "path=" + path);
// set filename to edittext
mFilename.setText(path);
// load data
mImportActivity.loadCallback(null, path);
} catch (NullPointerException e) {
Log.e(Constants.TAG, "Nullpointer while retrieving path!", e);
}
}
break;
}
default:
super.onActivityResult(requestCode, resultCode, data);
break;
}
}
}

View File

@ -0,0 +1,51 @@
/*
* Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.sufficientlysecure.keychain.ui;
import org.sufficientlysecure.keychain.R;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class ImportKeyServerFragment extends Fragment {
/**
* Creates new instance of this fragment
*/
public static ImportKeyServerFragment newInstance() {
ImportKeyServerFragment frag = new ImportKeyServerFragment();
Bundle args = new Bundle();
frag.setArguments(args);
return frag;
}
/**
* Inflate the layout for this fragment
*/
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.import_keys_keyserver_fragment, container, false);
}
}

View File

@ -20,7 +20,6 @@ package org.sufficientlysecure.keychain.ui;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id; import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround;
import org.sufficientlysecure.keychain.helper.ActionBarHelper; import org.sufficientlysecure.keychain.helper.ActionBarHelper;
import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
@ -30,30 +29,31 @@ import org.sufficientlysecure.keychain.util.Log;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.ProgressDialog; import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler;
import android.os.Message; import android.os.Message;
import android.os.Messenger; import android.os.Messenger;
import android.support.v4.app.FragmentManager; import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction; import android.support.v4.app.FragmentTransaction;
import android.view.View; import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Toast; import android.widget.Toast;
import com.actionbarsherlock.app.ActionBar;
import com.actionbarsherlock.app.ActionBar.OnNavigationListener;
import com.actionbarsherlock.app.SherlockFragmentActivity; import com.actionbarsherlock.app.SherlockFragmentActivity;
import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem; import com.actionbarsherlock.view.MenuItem;
import com.google.zxing.integration.android.IntentIntegrator;
import com.google.zxing.integration.android.IntentResult;
public class ImportKeysActivity extends SherlockFragmentActivity { public class ImportKeysActivity extends SherlockFragmentActivity implements OnNavigationListener {
public static final String ACTION_IMPORT_KEY = Constants.INTENT_PREFIX + "IMPORT_KEY"; public static final String ACTION_IMPORT_KEY = Constants.INTENT_PREFIX + "IMPORT_KEY";
public static final String ACTION_IMPORT_KEY_FROM_QR_CODE = Constants.INTENT_PREFIX public static final String ACTION_IMPORT_KEY_FROM_QR_CODE = Constants.INTENT_PREFIX
+ "IMPORT_KEY_FROM_QR_CODE"; + "IMPORT_KEY_FROM_QR_CODE";
// Actions for internal use only: // Actions for internal use only:
public static final String ACTION_IMPOR_KEY_FROM_FILE = Constants.INTENT_PREFIX public static final String ACTION_IMPORT_KEY_FROM_FILE = Constants.INTENT_PREFIX
+ "IMPORT_KEY_FROM_FILE"; + "IMPORT_KEY_FROM_FILE";
public static final String ACTION_IMPORT_KEY_FROM_NFC = Constants.INTENT_PREFIX public static final String ACTION_IMPORT_KEY_FROM_NFC = Constants.INTENT_PREFIX
+ "IMPORT_KEY_FROM_NFC"; + "IMPORT_KEY_FROM_NFC";
@ -64,12 +64,12 @@ public class ImportKeysActivity extends SherlockFragmentActivity {
// TODO: import keys from server // TODO: import keys from server
// public static final String EXTRA_KEY_ID = "keyId"; // public static final String EXTRA_KEY_ID = "keyId";
protected String mImportFilename;
protected byte[] mImportData;
protected boolean mDeleteAfterImport = false; protected boolean mDeleteAfterImport = false;
FileDialogFragment mFileDialog; FileDialogFragment mFileDialog;
ImportKeysListFragment mListFragment;
OnNavigationListener mOnNavigationListener;
String[] mNavigationStrings;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
@ -80,9 +80,78 @@ public class ImportKeysActivity extends SherlockFragmentActivity {
// set actionbar without home button if called from another app // set actionbar without home button if called from another app
ActionBarHelper.setBackButton(this); ActionBarHelper.setBackButton(this);
// set drop down navigation
mNavigationStrings = getResources().getStringArray(R.array.import_action_list);
Context context = getSupportActionBar().getThemedContext();
ArrayAdapter<CharSequence> list = ArrayAdapter.createFromResource(context,
R.array.import_action_list, R.layout.sherlock_spinner_item);
list.setDropDownViewResource(R.layout.sherlock_spinner_dropdown_item);
getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
getSupportActionBar().setListNavigationCallbacks(list, this);
getSupportActionBar().setDisplayShowTitleEnabled(false);
// Check that the activity is using the layout version with
// the fragment_container FrameLayout
if (findViewById(R.id.import_keys_list_container) != null) {
// 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;
}
// Create an instance of the fragment
mListFragment = ImportKeysListFragment.newInstance();
// Add the fragment to the 'fragment_container' FrameLayout
getSupportFragmentManager().beginTransaction()
.replace(R.id.import_keys_list_container, mListFragment).commit();
// do it immediately!
getSupportFragmentManager().executePendingTransactions();
}
handleActions(getIntent()); handleActions(getIntent());
} }
@Override
public boolean onNavigationItemSelected(int itemPosition, long itemId) {
// Create new fragment from our own Fragment class
switch (itemPosition) {
case 0:
loadFragment(ImportFileFragment.class, null, mNavigationStrings[itemPosition]);
break;
case 1:
loadFragment(ImportKeyServerFragment.class, null, mNavigationStrings[itemPosition]);
break;
case 2:
loadFragment(ImportQrCodeFragment.class, null, mNavigationStrings[itemPosition]);
break;
case 3:
loadFragment(ImportNFCFragment.class, null, mNavigationStrings[itemPosition]);
break;
default:
break;
}
return true;
}
private void loadFragment(Class<?> clss, Bundle args, String tag) {
Fragment fragment = Fragment.instantiate(this, clss.getName(), args);
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
// Replace whatever is in the fragment container with this fragment
// and give the fragment a tag name equal to the string at the position selected
ft.replace(R.id.import_navigation_fragment, fragment, tag);
// Apply changes
ft.commit();
}
public void loadCallback(byte[] importData, String importFilename) {
mListFragment.load(importData, importFilename);
}
/** /**
* ActionBar menu is created based on class variables to change it at runtime * ActionBar menu is created based on class variables to change it at runtime
* *
@ -120,17 +189,17 @@ public class ImportKeysActivity extends SherlockFragmentActivity {
return true; return true;
case Id.menu.option.import_from_file: // case Id.menu.option.import_from_file:
showImportFromFileDialog(); // showImportFromFileDialog();
return true; // return true;
case Id.menu.option.import_from_qr_code: // case Id.menu.option.import_from_qr_code:
importFromQrCode(); // importFromQrCode();
return true; // return true;
//
case Id.menu.option.import_from_nfc: // case Id.menu.option.import_from_nfc:
importFromNfc(); // importFromNfc();
return true; // return true;
default: default:
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
@ -151,97 +220,40 @@ public class ImportKeysActivity extends SherlockFragmentActivity {
*/ */
if (Intent.ACTION_VIEW.equals(action)) { if (Intent.ACTION_VIEW.equals(action)) {
// Android's Action when opening file associated to Keychain (see AndroidManifest.xml) // Android's Action when opening file associated to Keychain (see AndroidManifest.xml)
// override action to delegate it to Keychains ACTION_IMPORT // override action to delegate it to Keychain's ACTION_IMPORT_KEY
action = ACTION_IMPORT_KEY; action = ACTION_IMPORT_KEY;
} }
/** /**
* APG's own Actions * Keychain's own Actions
*/ */
if (ACTION_IMPORT_KEY.equals(action)) { if (ACTION_IMPORT_KEY.equals(action)) {
if ("file".equals(intent.getScheme()) && intent.getDataString() != null) { if ("file".equals(intent.getScheme()) && intent.getDataString() != null) {
mImportFilename = intent.getData().getPath(); String importFilename = intent.getData().getPath();
mImportData = null;
} else if (extras.containsKey(EXTRA_KEY_BYTES)) {
mImportData = intent.getByteArrayExtra(EXTRA_KEY_BYTES);
mImportFilename = null;
}
loadKeyListFragment();
} else if (ACTION_IMPOR_KEY_FROM_FILE.equals(action)) {
if ("file".equals(intent.getScheme()) && intent.getDataString() != null) {
mImportFilename = intent.getData().getPath();
mImportData = null;
}
showImportFromFileDialog();
} else if (ACTION_IMPORT_KEY_FROM_QR_CODE.equals(action)) {
importFromQrCode();
} else if (ACTION_IMPORT_KEY_FROM_NFC.equals(action)) {
importFromNfc();
}
}
public void loadKeyListFragment() { // display selected filename
if (mImportData != null || mImportFilename != null) { getSupportActionBar().setSelectedNavigationItem(0);
// generate list of keyrings
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
ImportKeysListFragment listFragment = new ImportKeysListFragment();
Bundle args = new Bundle(); Bundle args = new Bundle();
args.putByteArray(ImportKeysListFragment.ARG_KEYRING_BYTES, mImportData); args.putString(ImportFileFragment.ARG_PATH, importFilename);
args.putString(ImportKeysListFragment.ARG_IMPORT_FILENAME, mImportFilename); loadFragment(ImportFileFragment.class, args, mNavigationStrings[0]);
listFragment.setArguments(args);
// replace container in view with fragment // directly load data
fragmentTransaction.replace(R.id.import_keys_list_container, listFragment); loadCallback(null, importFilename);
fragmentTransaction.commit(); } else if (extras.containsKey(EXTRA_KEY_BYTES)) {
byte[] importData = intent.getByteArrayExtra(EXTRA_KEY_BYTES);
loadCallback(importData, null);
} }
// Internal actions:
} else if (ACTION_IMPORT_KEY_FROM_FILE.equals(action)) {
getSupportActionBar().setSelectedNavigationItem(0);
loadFragment(ImportFileFragment.class, null, mNavigationStrings[0]);
} else if (ACTION_IMPORT_KEY_FROM_QR_CODE.equals(action)) {
getSupportActionBar().setSelectedNavigationItem(2);
loadFragment(ImportQrCodeFragment.class, null, mNavigationStrings[2]);
} else if (ACTION_IMPORT_KEY_FROM_NFC.equals(action)) {
getSupportActionBar().setSelectedNavigationItem(3);
loadFragment(ImportNFCFragment.class, null, mNavigationStrings[3]);
} }
private void importFromQrCode() {
new IntentIntegrator(this).initiateScan();
}
private void importFromNfc() {
// show nfc help
Intent intent = new Intent(this, HelpActivity.class);
intent.putExtra(HelpActivity.EXTRA_SELECTED_TAB, 1);
startActivityForResult(intent, 0);
}
/**
* Show to dialog from where to import keys
*/
public void showImportFromFileDialog() {
// Message is received after file is selected
Handler returnHandler = new Handler() {
@Override
public void handleMessage(Message message) {
if (message.what == FileDialogFragment.MESSAGE_OKAY) {
Bundle data = message.getData();
mImportFilename = data.getString(FileDialogFragment.MESSAGE_DATA_FILENAME);
mDeleteAfterImport = data.getBoolean(FileDialogFragment.MESSAGE_DATA_CHECKED);
Log.d(Constants.TAG, "mImportFilename: " + mImportFilename);
Log.d(Constants.TAG, "mDeleteAfterImport: " + mDeleteAfterImport);
loadKeyListFragment();
}
}
};
// Create a new Messenger for the communication back
final Messenger messenger = new Messenger(returnHandler);
DialogFragmentWorkaround.INTERFACE.runnableRunDelayed(new Runnable() {
public void run() {
mFileDialog = FileDialogFragment.newInstance(messenger,
getString(R.string.title_importKeys),
getString(R.string.specifyFileToImportFrom), Constants.path.APP_DIR + "/",
null, Id.request.filename);
mFileDialog.show(getSupportFragmentManager(), "fileDialog");
}
});
} }
// private void importAndSignOld(final long keyId, final String expectedFingerprint) { // private void importAndSignOld(final long keyId, final String expectedFingerprint) {
@ -302,25 +314,11 @@ public class ImportKeysActivity extends SherlockFragmentActivity {
// } // }
// } // }
public void scanAgainOnClick(View view) {
new IntentIntegrator(this).initiateScan();
}
public void finishOnClick(View view) {
finish();
}
public void importOnClick(View view) {
Log.d(Constants.TAG, "Import key button clicked!");
importKeys();
}
/** /**
* Import keys with mImportData * Import keys with mImportData
*/ */
public void importKeys() { public void importKeys() {
if (mImportData != null || mImportFilename != null) { if (mListFragment.getKeyBytes() != null || mListFragment.getImportFilename() != null) {
Log.d(Constants.TAG, "importKeys started"); Log.d(Constants.TAG, "importKeys started");
// Send all information needed to service to import key in other thread // Send all information needed to service to import key in other thread
@ -334,12 +332,13 @@ public class ImportKeysActivity extends SherlockFragmentActivity {
// TODO: check for key type? // TODO: check for key type?
// data.putInt(KeychainIntentService.IMPORT_KEY_TYPE, Id.type.secret_key); // data.putInt(KeychainIntentService.IMPORT_KEY_TYPE, Id.type.secret_key);
if (mImportData != null) { if (mListFragment.getKeyBytes() != null) {
data.putInt(KeychainIntentService.TARGET, KeychainIntentService.TARGET_BYTES); data.putInt(KeychainIntentService.TARGET, KeychainIntentService.TARGET_BYTES);
data.putByteArray(KeychainIntentService.IMPORT_BYTES, mImportData); data.putByteArray(KeychainIntentService.IMPORT_BYTES, mListFragment.getKeyBytes());
} else { } else {
data.putInt(KeychainIntentService.TARGET, KeychainIntentService.TARGET_FILE); data.putInt(KeychainIntentService.TARGET, KeychainIntentService.TARGET_FILE);
data.putString(KeychainIntentService.IMPORT_FILENAME, mImportFilename); data.putString(KeychainIntentService.IMPORT_FILENAME,
mListFragment.getImportFilename());
} }
intent.putExtra(KeychainIntentService.EXTRA_DATA, data); intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
@ -391,7 +390,7 @@ public class ImportKeysActivity extends SherlockFragmentActivity {
} else if (mDeleteAfterImport) { } else if (mDeleteAfterImport) {
// everything went well, so now delete, if that was turned on // everything went well, so now delete, if that was turned on
DeleteFileDialogFragment deleteFileDialog = DeleteFileDialogFragment DeleteFileDialogFragment deleteFileDialog = DeleteFileDialogFragment
.newInstance(mImportFilename); .newInstance(mListFragment.getImportFilename());
deleteFileDialog.show(getSupportFragmentManager(), "deleteDialog"); deleteFileDialog.show(getSupportFragmentManager(), "deleteDialog");
} }
} }
@ -412,68 +411,17 @@ public class ImportKeysActivity extends SherlockFragmentActivity {
} }
} }
public void importOnClick(View view) {
importKeys();
}
public void signAndUploadOnClick(View view) { public void signAndUploadOnClick(View view) {
// first, import! // first, import!
importOnClick(view); // importOnClick(view);
// TODO: implement sign and upload! // TODO: implement sign and upload!
Toast.makeText(ImportKeysActivity.this, "Not implemented right now!", Toast.LENGTH_SHORT) Toast.makeText(ImportKeysActivity.this, "Not implemented right now!", Toast.LENGTH_SHORT)
.show(); .show();
} }
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case Id.request.filename: {
if (resultCode == RESULT_OK && data != null) {
try {
String path = data.getData().getPath();
Log.d(Constants.TAG, "path=" + path);
// set filename used in export/import dialogs
mFileDialog.setFilename(path);
} catch (NullPointerException e) {
Log.e(Constants.TAG, "Nullpointer while retrieving path!", e);
}
}
return;
}
case IntentIntegrator.REQUEST_CODE: {
IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode,
data);
if (scanResult != null && scanResult.getFormatName() != null) {
// mScannedContent = scanResult.getContents();
mImportData = scanResult.getContents().getBytes();
mImportFilename = null;
// mContentView.setText(mScannedContent);
// String[] bits = scanResult.getContents().split(",");
// if (bits.length != 2) {
// return; // dont know how to handle this. Not a valid code
// }
//
// long keyId = Long.parseLong(bits[0]);
// String expectedFingerprint = bits[1];
// importAndSign(keyId, expectedFingerprint);
}
break;
}
default: {
super.onActivityResult(requestCode, resultCode, data);
}
}
}
@Override
protected void onResume() {
super.onResume();
loadKeyListFragment();
}
} }

View File

@ -38,15 +38,37 @@ import android.widget.SimpleAdapter;
public class ImportKeysListFragment extends SherlockListFragment implements public class ImportKeysListFragment extends SherlockListFragment implements
LoaderManager.LoaderCallbacks<List<Map<String, String>>> { LoaderManager.LoaderCallbacks<List<Map<String, String>>> {
public static String ARG_KEYRING_BYTES = "bytes"; // public static final String ARG_IMPORT_DATA = "bytes";
public static String ARG_IMPORT_FILENAME = "filename"; // public static final String ARG_IMPORT_FILENAME = "filename";
byte[] mKeyringBytes;
String mImportFilename;
private Activity mActivity; private Activity mActivity;
private SimpleAdapter mAdapter; private SimpleAdapter mAdapter;
private byte[] mKeyBytes;
private String mImportFilename;
public byte[] getKeyBytes() {
return mKeyBytes;
}
public String getImportFilename() {
return mImportFilename;
}
/**
* Creates new instance of this fragment
*/
public static ImportKeysListFragment newInstance() {
ImportKeysListFragment frag = new ImportKeysListFragment();
Bundle args = new Bundle();
frag.setArguments(args);
return frag;
}
@Override @Override
public void onListItemClick(ListView listView, View view, int position, long id) { public void onListItemClick(ListView listView, View view, int position, long id) {
// Map<String, String> item = (Map<String, String>) listView.getItemAtPosition(position); // Map<String, String> item = (Map<String, String>) listView.getItemAtPosition(position);
@ -76,8 +98,8 @@ public class ImportKeysListFragment extends SherlockListFragment implements
mActivity = this.getActivity(); mActivity = this.getActivity();
mKeyringBytes = getArguments().getByteArray(ARG_KEYRING_BYTES); // mKeyBytes = getArguments().getByteArray(ARG_IMPORT_DATA);
mImportFilename = getArguments().getString(ARG_IMPORT_FILENAME); // mImportFilename = getArguments().getString(ARG_IMPORT_FILENAME);
// register long press context menu // register long press context menu
registerForContextMenu(getListView()); registerForContextMenu(getListView());
@ -102,9 +124,16 @@ public class ImportKeysListFragment extends SherlockListFragment implements
getLoaderManager().initLoader(0, null, this); getLoaderManager().initLoader(0, null, this);
} }
public void load(byte[] importData, String importFilename) {
mKeyBytes = importData;
mImportFilename = importFilename;
getLoaderManager().initLoader(0, null, this);
}
@Override @Override
public Loader<List<Map<String, String>>> onCreateLoader(int id, Bundle args) { public Loader<List<Map<String, String>>> onCreateLoader(int id, Bundle args) {
return new ImportKeysListLoader(mActivity, mKeyringBytes, mImportFilename); return new ImportKeysListLoader(mActivity, mKeyBytes, mImportFilename);
} }
@Override @Override

View File

@ -0,0 +1,69 @@
/*
* Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.sufficientlysecure.keychain.ui;
import org.sufficientlysecure.keychain.R;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
public class ImportNFCFragment extends Fragment {
private Button mButton;
/**
* Creates new instance of this fragment
*/
public static ImportNFCFragment newInstance() {
ImportNFCFragment frag = new ImportNFCFragment();
Bundle args = new Bundle();
frag.setArguments(args);
return frag;
}
/**
* Inflate the layout for this fragment
*/
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.import_keys_nfc_fragment, container, false);
mButton = (Button) view.findViewById(R.id.import_nfc_button);
mButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// show nfc help
Intent intent = new Intent(getActivity(), HelpActivity.class);
intent.putExtra(HelpActivity.EXTRA_SELECTED_TAB, 1);
startActivityForResult(intent, 0);
}
});
return view;
}
}

View File

@ -0,0 +1,116 @@
/*
* Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.sufficientlysecure.keychain.ui;
import org.sufficientlysecure.keychain.R;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import com.google.zxing.integration.android.IntentIntegrator;
import com.google.zxing.integration.android.IntentIntegratorSupportV4;
import com.google.zxing.integration.android.IntentResult;
public class ImportQrCodeFragment extends Fragment {
private ImportKeysActivity mImportActivity;
private Button mButton;
/**
* Creates new instance of this fragment
*/
public static ImportQrCodeFragment newInstance() {
ImportQrCodeFragment frag = new ImportQrCodeFragment();
Bundle args = new Bundle();
frag.setArguments(args);
return frag;
}
/**
* Inflate the layout for this fragment
*/
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.import_keys_qr_code_fragment, container, false);
mButton = (Button) view.findViewById(R.id.import_qrcode_button);
mButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// scan using xzing's Barcode Scanner
new IntentIntegratorSupportV4(ImportQrCodeFragment.this).initiateScan();
}
});
return view;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mImportActivity = (ImportKeysActivity) getActivity();
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case IntentIntegrator.REQUEST_CODE: {
IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode,
data);
if (scanResult != null && scanResult.getFormatName() != null) {
// mScannedContent = scanResult.getContents();
mImportActivity.loadCallback(scanResult.getContents().getBytes(), null);
// mImportData = scanResult.getContents().getBytes();
// mImportFilename = null;
// mContentView.setText(mScannedContent);
// String[] bits = scanResult.getContents().split(",");
// if (bits.length != 2) {
// return; // dont know how to handle this. Not a valid code
// }
//
// long keyId = Long.parseLong(bits[0]);
// String expectedFingerprint = bits[1];
// importAndSign(keyId, expectedFingerprint);
}
break;
}
default:
super.onActivityResult(requestCode, resultCode, data);
break;
}
}
}

View File

@ -154,7 +154,7 @@ public class KeyListActivity extends SherlockFragmentActivity {
case Id.menu.option.import_from_file: { case Id.menu.option.import_from_file: {
Intent intentImportFromFile = new Intent(this, ImportKeysActivity.class); Intent intentImportFromFile = new Intent(this, ImportKeysActivity.class);
intentImportFromFile.setAction(ImportKeysActivity.ACTION_IMPOR_KEY_FROM_FILE); intentImportFromFile.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_FILE);
startActivityForResult(intentImportFromFile, 0); startActivityForResult(intentImportFromFile, 0);
return true; return true;
} }

View File

@ -67,7 +67,7 @@ public class KeyListPublicActivity extends KeyListActivity {
} }
case Id.menu.option.import_from_file: { case Id.menu.option.import_from_file: {
Intent intentImportFromFile = new Intent(this, ImportKeysActivity.class); Intent intentImportFromFile = new Intent(this, ImportKeysActivity.class);
intentImportFromFile.setAction(ImportKeysActivity.ACTION_IMPOR_KEY_FROM_FILE); intentImportFromFile.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_FILE);
startActivityForResult(intentImportFromFile, 0); startActivityForResult(intentImportFromFile, 0);
return true; return true;

View File

@ -42,6 +42,7 @@ import android.widget.ListView;
public class SelectPublicKeyFragment extends ListFragmentWorkaround implements public class SelectPublicKeyFragment extends ListFragmentWorkaround implements
LoaderManager.LoaderCallbacks<Cursor> { LoaderManager.LoaderCallbacks<Cursor> {
public static final String ARG_PRESELECTED_KEY_IDS = "preselected_key_ids";
private Activity mActivity; private Activity mActivity;
private SelectKeyCursorAdapter mAdapter; private SelectKeyCursorAdapter mAdapter;
@ -49,8 +50,6 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements
private long mSelectedMasterKeyIds[]; private long mSelectedMasterKeyIds[];
private static final String ARG_PRESELECTED_KEY_IDS = "preselected_key_ids";
/** /**
* Creates new instance of this fragment * Creates new instance of this fragment
*/ */

View File

@ -38,6 +38,8 @@ import android.widget.CheckBox;
import android.widget.EditText; import android.widget.EditText;
import android.widget.ImageButton; import android.widget.ImageButton;
// TODO: return result from file manager activity to this dialog! not the activity!
// do it like in ImportFileFragment!
public class FileDialogFragment extends DialogFragment { public class FileDialogFragment extends DialogFragment {
private static final String ARG_MESSENGER = "messenger"; private static final String ARG_MESSENGER = "messenger";
private static final String ARG_TITLE = "title"; private static final String ARG_TITLE = "title";
@ -107,7 +109,8 @@ public class FileDialogFragment extends DialogFragment {
mBrowse.setOnClickListener(new View.OnClickListener() { mBrowse.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) { public void onClick(View v) {
// only .asc or .gpg files // only .asc or .gpg files
FileHelper.openFile(activity, mFilename.getText().toString(), "text/plain", // setting it to text/plain prevents Cynaogenmod's file manager from selecting asc or gpg types!
FileHelper.openFile(activity, mFilename.getText().toString(), "*/*",
requestCode); requestCode);
} }
}); });

View File

@ -65,13 +65,15 @@ public class ImportKeysListLoader extends AsyncTaskLoader<List<Map<String, Strin
InputData inputData = null; InputData inputData = null;
if (mKeyringBytes != null) { if (mKeyringBytes != null) {
inputData = new InputData(new ByteArrayInputStream(mKeyringBytes), mKeyringBytes.length); inputData = new InputData(new ByteArrayInputStream(mKeyringBytes), mKeyringBytes.length);
} else { } else if (mImportFilename != null) {
try { try {
inputData = new InputData(new FileInputStream(mImportFilename), inputData = new InputData(new FileInputStream(mImportFilename),
mImportFilename.length()); mImportFilename.length());
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
Log.e(Constants.TAG, "Failed to init FileInputStream!", e); Log.e(Constants.TAG, "Failed to init FileInputStream!", e);
} }
} else {
return data;
} }
generateListOfKeyrings(inputData); generateListOfKeyrings(inputData);