Import keys with adapter, loader, and new design

This commit is contained in:
Dominik Schürmann 2013-09-22 19:58:33 +02:00
parent 7b2de96d15
commit 917c86b524
30 changed files with 702 additions and 797 deletions

View File

@ -267,9 +267,7 @@
android:label="@string/title_signKey" />
<activity
android:name=".ui.ImportKeysActivity"
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
android:label="@string/title_importKeys"
android:uiOptions="splitActionBarWhenNarrow"
android:windowSoftInputMode="stateHidden" >
<!-- Keychain's own Actions -->

View File

@ -3,28 +3,37 @@
android:layout_height="match_parent"
android:orientation="vertical" >
<Spinner
android:id="@+id/import_keys_server_key_server"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<EditText
android:id="@+id/import_keys_server_query"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:inputType="textPersonName|textEmailAddress" />
<Button
android:id="@+id/import_keys_server_search"
android:layout_width="wrap_content"
android:id="@+id/import_keyserver_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/btn_search" />
</LinearLayout>
android:text="@string/menu_keyServer" />
<!-- <Spinner -->
<!-- android:id="@+id/import_keys_server_key_server" -->
<!-- android:layout_width="fill_parent" -->
<!-- android:layout_height="wrap_content" /> -->
<!-- <LinearLayout -->
<!-- android:layout_width="fill_parent" -->
<!-- android:layout_height="wrap_content" -->
<!-- android:orientation="horizontal" > -->
<!-- <EditText -->
<!-- android:id="@+id/import_keys_server_query" -->
<!-- android:layout_width="0dip" -->
<!-- android:layout_height="wrap_content" -->
<!-- android:layout_weight="1" -->
<!-- android:inputType="textPersonName|textEmailAddress" /> -->
<!-- <Button -->
<!-- android:id="@+id/import_keys_server_search" -->
<!-- android:layout_width="wrap_content" -->
<!-- android:layout_height="wrap_content" -->
<!-- android:text="@string/btn_search" /> -->
<!-- </LinearLayout> -->
</LinearLayout>

View File

@ -0,0 +1,108 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="3dip"
android:paddingRight="?android:attr/scrollbarSize"
android:singleLine="true" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<CheckBox
android:id="@+id/selected"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="false"
android:focusable="false"
android:focusableInTouchMode="false" />
<!-- focusable and clickable MUST be false to handle click and longClick in ListView Activity -->
<LinearLayout
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:paddingLeft="5dip"
android:paddingRight="5dip" >
<TextView
android:id="@+id/mainUserId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Main User ID"
android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
android:id="@+id/fingerprint"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="fingerprint"
android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView
android:id="@+id/mainUserIdRest"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="&lt;user@somewhere.com>"
android:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="right"
android:minWidth="90dip"
android:orientation="vertical"
android:paddingLeft="3dip" >
<TextView
android:id="@+id/keyId"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:text="BBBBBBBB"
android:textAppearance="?android:attr/textAppearanceSmall"
android:typeface="monospace" />
<TextView
android:id="@+id/algorithm"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView
android:id="@+id/status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="#e00" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="30dip"
android:orientation="vertical" >
</LinearLayout>
</LinearLayout>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_marginRight="?android:attr/scrollbarSize"
android:singleLine="true"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:paddingRight="3dip">
</TextView>

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
<!--
Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -14,69 +15,66 @@
limitations under the License.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:singleLine="true"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="?android:attr/listPreferredItemHeight"
android:paddingLeft="3dip"
android:paddingRight="?android:attr/scrollbarSize"
android:layout_height="?android:attr/listPreferredItemHeight"
android:layout_width="fill_parent">
android:singleLine="true" >
<CheckBox
android:id="@+id/selected"
android:focusable="false"
android:focusableInTouchMode="false"
android:clickable="false"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
android:layout_height="wrap_content"
android:clickable="false"
android:focusable="false"
android:focusableInTouchMode="false" />
<LinearLayout
android:orientation="vertical"
android:paddingLeft="5dip"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1">
android:layout_weight="1"
android:orientation="vertical"
android:paddingLeft="5dip" >
<TextView
android:id="@+id/mainUserId"
android:text="Main User ID"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
android:layout_height="wrap_content"
android:text="Main User ID"
android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
android:id="@+id/mainUserIdRest"
android:text="&lt;user@example.com&gt;"
android:textAppearance="?android:attr/textAppearanceSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
android:layout_height="wrap_content"
android:text="&lt;user@example.com>"
android:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout>
<LinearLayout
android:orientation="vertical"
android:minWidth="90dip"
android:paddingLeft="3dip"
android:gravity="right"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
android:gravity="right"
android:minWidth="90dip"
android:orientation="vertical"
android:paddingLeft="3dip" >
<TextView
android:id="@+id/keyId"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:text="BBBBBBBB"
android:textAppearance="?android:attr/textAppearanceSmall"
android:typeface="monospace"
android:layout_width="wrap_content"
android:layout_height="fill_parent"/>
android:typeface="monospace" />
<TextView
android:id="@+id/status"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="expired"
android:textStyle="italic"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
android:layout_height="wrap_content"
android:text="expired"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textStyle="italic" />
</LinearLayout>
</LinearLayout>

View File

@ -157,7 +157,7 @@
<string name="notValid">not valid</string>
<string name="nKeyServers">%s key server(s)</string>
<string name="fingerprint">Fingerprint:</string>
<string name="secretKeyring">Secret Keyring:</string>
<string name="secretKey">Secret Key:</string>
<!-- choice_lowerCase: capitalized first word, no punctuation -->
<string name="choice_none">None</string>
@ -347,8 +347,8 @@
<string name="help_about_version">Version:</string>
<!-- Import -->
<string name="import_import">Import key(s) (only locally)</string>
<string name="import_sign_and_upload">Import, Sign, and upload key(s)</string>
<string name="import_import">Import selected keys</string>
<string name="import_sign_and_upload">Import, Sign, and upload selected keys</string>
<string name="import_finish">Finish</string>
<!-- Intent labels -->

View File

@ -24,10 +24,11 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import org.spongycastle.bcpg.ArmoredOutputStream;
import org.spongycastle.openpgp.operator.KeyFingerPrintCalculator;
import org.spongycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
import org.spongycastle.openpgp.PGPException;
import org.spongycastle.openpgp.PGPKeyRing;
import org.spongycastle.openpgp.PGPObjectFactory;
@ -36,6 +37,7 @@ import org.spongycastle.openpgp.PGPPublicKeyRing;
import org.spongycastle.openpgp.PGPSecretKey;
import org.spongycastle.openpgp.PGPSecretKeyRing;
import org.spongycastle.openpgp.PGPUtil;
import org.spongycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R;
@ -100,17 +102,23 @@ public class PgpImportExport {
}
}
public Bundle importKeyRings(InputData data) throws PgpGeneralException, FileNotFoundException,
PGPException, IOException {
/**
* Imports keys from given data. If keyIds is given only those are imported
*
* @param data
* @param keyIds
* @return
* @throws PgpGeneralException
* @throws FileNotFoundException
* @throws PGPException
* @throws IOException
*/
public Bundle importKeyRings(InputData data, ArrayList<Long> keyIds)
throws PgpGeneralException, FileNotFoundException, PGPException, IOException {
Bundle returnData = new Bundle();
updateProgress(R.string.progress_importingSecretKeys, 0, 100);
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
throw new PgpGeneralException(
mContext.getString(R.string.error_externalStorageNotReady));
}
PositionAwareInputStream progressIn = new PositionAwareInputStream(data.getInputStream());
// need to have access to the bufferedInput, so we can reuse it for the possible
@ -137,7 +145,16 @@ public class PgpImportExport {
int status = Integer.MIN_VALUE; // out of bounds value
if (keyIds != null) {
if (keyIds.contains(keyring.getPublicKey().getKeyID())) {
status = storeKeyRingInCache(keyring);
} else {
Log.d(Constants.TAG, "not selected! key id: "
+ keyring.getPublicKey().getKeyID());
}
} else {
status = storeKeyRingInCache(keyring);
}
if (status == Id.return_value.error) {
throw new PgpGeneralException(
@ -264,11 +281,14 @@ public class PgpImportExport {
if (save) {
ProviderHelper.saveKeyRing(mContext, secretKeyRing);
// TODO: preserve certifications (http://osdir.com/ml/encryption.bouncy-castle.devel/2007-01/msg00054.html ?)
// TODO: preserve certifications
// (http://osdir.com/ml/encryption.bouncy-castle.devel/2007-01/msg00054.html ?)
PGPPublicKeyRing newPubRing = null;
for (PGPPublicKey key : new IterableIterator<PGPPublicKey>(secretKeyRing.getPublicKeys())) {
for (PGPPublicKey key : new IterableIterator<PGPPublicKey>(
secretKeyRing.getPublicKeys())) {
if (newPubRing == null) {
newPubRing = new PGPPublicKeyRing(key.getEncoded(), new JcaKeyFingerprintCalculator());
newPubRing = new PGPPublicKeyRing(key.getEncoded(),
new JcaKeyFingerprintCalculator());
}
newPubRing = PGPPublicKeyRing.insertPublicKey(newPubRing, key);
}

View File

@ -488,7 +488,7 @@ public class PgpKeyHelper {
return isSecretKeyPrivateEmpty(secretKey);
}
public static String getSmallFingerPrint(long keyId) {
public static String convertKeyIdToHex(long keyId) {
String fingerPrint = Long.toHexString(keyId & 0xffffffffL).toUpperCase(Locale.US);
while (fingerPrint.length() < 8) {
fingerPrint = "0" + fingerPrint;
@ -496,11 +496,17 @@ public class PgpKeyHelper {
return fingerPrint;
}
public static String keyToHex(long keyId) {
return getSmallFingerPrint(keyId >> 32) + getSmallFingerPrint(keyId);
/**
* TODO: what is the difference to the other function?
*
* @param keyId
* @return
*/
public static String convertKeyToHex(long keyId) {
return convertKeyIdToHex(keyId >> 32) + convertKeyIdToHex(keyId);
}
public static long keyFromHex(String data) {
public static long convertHexToKeyId(String data) {
int len = data.length();
String s2 = data.substring(len - 8);
String s1 = data.substring(0, len - 8);

View File

@ -27,7 +27,9 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import org.spongycastle.openpgp.PGPKeyRing;
import org.spongycastle.openpgp.PGPPublicKeyRing;
import org.spongycastle.openpgp.PGPSecretKey;
import org.spongycastle.openpgp.PGPSecretKeyRing;
@ -45,6 +47,7 @@ import org.sufficientlysecure.keychain.pgp.PgpOperation;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.KeychainContract.DataStream;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry;
import org.sufficientlysecure.keychain.util.HkpKeyServer;
import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.KeyServer.KeyInfo;
@ -142,7 +145,7 @@ public class KeychainIntentService extends IntentService implements ProgressDial
public static final String IMPORT_INPUT_STREAM = "import_input_stream";
public static final String IMPORT_FILENAME = "import_filename";
public static final String IMPORT_BYTES = "import_bytes";
// public static final String IMPORT_KEY_TYPE = "importKeyType";
public static final String IMPORT_KEY_LIST = "import_key_list";
// export key
public static final String EXPORT_OUTPUT_STREAM = "export_output_stream";
@ -630,11 +633,6 @@ public class KeychainIntentService extends IntentService implements ProgressDial
/* Input */
int target = data.getInt(TARGET);
// int keyType = Id.type.public_key;
// if (data.containsKey(IMPORT_KEY_TYPE)) {
// keyType = data.getInt(IMPORT_KEY_TYPE);
// }
/* Operation */
InputStream inStream = null;
long inLength = -1;
@ -666,8 +664,10 @@ public class KeychainIntentService extends IntentService implements ProgressDial
Bundle resultData = new Bundle();
ArrayList<Long> keyIds = (ArrayList<Long>) data.getSerializable(IMPORT_KEY_LIST);
PgpImportExport pgpImportExport = new PgpImportExport(this, this);
resultData = pgpImportExport.importKeyRings(inputData);
resultData = pgpImportExport.importKeyRings(inputData, keyIds);
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData);
} catch (Exception e) {

View File

@ -17,10 +17,6 @@
package org.sufficientlysecure.keychain.service.remote;
import java.util.HashMap;
import org.spongycastle.bcpg.HashAlgorithmTags;
import org.spongycastle.openpgp.PGPEncryptedData;
import org.spongycastle.openpgp.PGPSecretKey;
import org.spongycastle.openpgp.PGPSecretKeyRing;
import org.sufficientlysecure.keychain.Constants;
@ -29,7 +25,8 @@ import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.ui.SelectSecretKeyActivity;
import org.sufficientlysecure.keychain.util.KeyValueSpinnerAdapter;
import org.sufficientlysecure.keychain.ui.adapter.KeyValueSpinnerAdapter;
import org.sufficientlysecure.keychain.util.AlgorithmNames;
import org.sufficientlysecure.keychain.util.Log;
import android.app.Activity;
@ -114,18 +111,10 @@ public class AppSettingsFragment extends Fragment {
mHashAlgorithm = (Spinner) view.findViewById(R.id.api_app_settings_hash_algorithm);
mCompression = (Spinner) view.findViewById(R.id.api_app_settings_compression);
HashMap<Integer, String> encryptionMap = new HashMap<Integer, String>();
encryptionMap.put(PGPEncryptedData.AES_128, "AES-128");
encryptionMap.put(PGPEncryptedData.AES_192, "AES-192");
encryptionMap.put(PGPEncryptedData.AES_256, "AES-256");
encryptionMap.put(PGPEncryptedData.BLOWFISH, "Blowfish");
encryptionMap.put(PGPEncryptedData.TWOFISH, "Twofish");
encryptionMap.put(PGPEncryptedData.CAST5, "CAST5");
encryptionMap.put(PGPEncryptedData.DES, "DES");
encryptionMap.put(PGPEncryptedData.TRIPLE_DES, "Triple DES");
encryptionMap.put(PGPEncryptedData.IDEA, "IDEA");
AlgorithmNames algorithmNames = new AlgorithmNames(getActivity());
encryptionAdapter = new KeyValueSpinnerAdapter(getActivity(), encryptionMap);
encryptionAdapter = new KeyValueSpinnerAdapter(getActivity(),
algorithmNames.getEncryptionNames());
mEncryptionAlgorithm.setAdapter(encryptionAdapter);
mEncryptionAlgorithm.setOnItemSelectedListener(new OnItemSelectedListener() {
@ -139,16 +128,7 @@ public class AppSettingsFragment extends Fragment {
}
});
HashMap<Integer, String> hashMap = new HashMap<Integer, String>();
hashMap.put(HashAlgorithmTags.MD5, "MD5");
hashMap.put(HashAlgorithmTags.RIPEMD160, "RIPEMD-160");
hashMap.put(HashAlgorithmTags.SHA1, "SHA-1");
hashMap.put(HashAlgorithmTags.SHA224, "SHA-224");
hashMap.put(HashAlgorithmTags.SHA256, "SHA-256");
hashMap.put(HashAlgorithmTags.SHA384, "SHA-384");
hashMap.put(HashAlgorithmTags.SHA512, "SHA-512");
hashAdapter = new KeyValueSpinnerAdapter(getActivity(), hashMap);
hashAdapter = new KeyValueSpinnerAdapter(getActivity(), algorithmNames.getHashNames());
mHashAlgorithm.setAdapter(hashAdapter);
mHashAlgorithm.setOnItemSelectedListener(new OnItemSelectedListener() {
@ -162,15 +142,8 @@ public class AppSettingsFragment extends Fragment {
}
});
HashMap<Integer, String> compressionMap = new HashMap<Integer, String>();
compressionMap.put(Id.choice.compression.none, getString(R.string.choice_none) + " ("
+ getString(R.string.fast) + ")");
compressionMap.put(Id.choice.compression.zip, "ZIP (" + getString(R.string.fast) + ")");
compressionMap.put(Id.choice.compression.zlib, "ZLIB (" + getString(R.string.fast) + ")");
compressionMap.put(Id.choice.compression.bzip2, "BZIP2 (" + getString(R.string.very_slow)
+ ")");
compressionAdapter = new KeyValueSpinnerAdapter(getActivity(), compressionMap);
compressionAdapter = new KeyValueSpinnerAdapter(getActivity(),
algorithmNames.getCompressionNames());
mCompression.setAdapter(compressionAdapter);
mCompression.setOnItemSelectedListener(new OnItemSelectedListener() {

View File

@ -773,7 +773,7 @@ public class DecryptActivity extends SherlockFragmentActivity {
mSignatureKeyId = returnData
.getLong(KeychainIntentService.RESULT_SIGNATURE_KEY_ID);
mUserIdRest.setText("id: "
+ PgpKeyHelper.getSmallFingerPrint(mSignatureKeyId));
+ PgpKeyHelper.convertKeyIdToHex(mSignatureKeyId));
if (userId == null) {
userId = getResources().getString(R.string.unknownUserId);
}

View File

@ -17,12 +17,15 @@
package org.sufficientlysecure.keychain.ui;
import java.util.ArrayList;
import java.util.List;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.ActionBarHelper;
import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry;
import org.sufficientlysecure.keychain.ui.dialog.DeleteFileDialogFragment;
import org.sufficientlysecure.keychain.ui.dialog.FileDialogFragment;
import org.sufficientlysecure.keychain.util.Log;
@ -44,7 +47,6 @@ import android.widget.Toast;
import com.actionbarsherlock.app.ActionBar;
import com.actionbarsherlock.app.ActionBar.OnNavigationListener;
import com.actionbarsherlock.app.SherlockFragmentActivity;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
public class ImportKeysActivity extends SherlockFragmentActivity implements OnNavigationListener {
@ -152,27 +154,6 @@ public class ImportKeysActivity extends SherlockFragmentActivity implements OnNa
mListFragment.load(importData, importFilename);
}
/**
* ActionBar menu is created based on class variables to change it at runtime
*
*/
@Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(1, Id.menu.option.key_server, 0, R.string.menu_keyServer).setShowAsAction(
MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
menu.add(1, Id.menu.option.import_from_file, 1, R.string.menu_importFromFile)
.setShowAsAction(
MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
menu.add(1, Id.menu.option.import_from_qr_code, 2, R.string.menu_importFromQrCode)
.setShowAsAction(
MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
menu.add(1, Id.menu.option.import_from_nfc, 3, R.string.menu_importFromNfc)
.setShowAsAction(
MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
@ -184,23 +165,6 @@ public class ImportKeysActivity extends SherlockFragmentActivity implements OnNa
startActivity(intent);
return true;
case Id.menu.option.key_server:
startActivityForResult(new Intent(this, KeyServerQueryActivity.class), 0);
return true;
// case Id.menu.option.import_from_file:
// showImportFromFileDialog();
// return true;
// case Id.menu.option.import_from_qr_code:
// importFromQrCode();
// return true;
//
// case Id.menu.option.import_from_nfc:
// importFromNfc();
// return true;
default:
return super.onOptionsItemSelected(item);
@ -329,8 +293,16 @@ public class ImportKeysActivity extends SherlockFragmentActivity implements OnNa
// fill values for this action
Bundle data = new Bundle();
// TODO: check for key type?
// data.putInt(KeychainIntentService.IMPORT_KEY_TYPE, Id.type.secret_key);
// get selected key ids
List<ImportKeysListEntry> listEntries = mListFragment.getData();
ArrayList<Long> selectedKeyIds = new ArrayList<Long>();
for (ImportKeysListEntry entry : listEntries) {
if (entry.isSelected()) {
selectedKeyIds.add(entry.keyId);
}
}
data.putSerializable(KeychainIntentService.IMPORT_KEY_LIST, selectedKeyIds);
if (mListFragment.getKeyBytes() != null) {
data.putInt(KeychainIntentService.TARGET, KeychainIntentService.TARGET_BYTES);

View File

@ -68,8 +68,8 @@ public class ImportKeysFileFragment extends Fragment {
// open .asc or .gpg files
// setting it to text/plain prevents Cynaogenmod's file manager from selecting asc
// or gpg types!
FileHelper.openFile(ImportKeysFileFragment.this, mFilename.getText().toString(), "*/*",
Id.request.filename);
FileHelper.openFile(ImportKeysFileFragment.this, mFilename.getText().toString(),
"*/*", Id.request.filename);
}
});
@ -84,7 +84,7 @@ public class ImportKeysFileFragment extends Fragment {
// set default path
String path = Constants.path.APP_DIR + "/";
if (getArguments() != null) {
if (getArguments() != null && getArguments().containsKey(ARG_PATH)) {
path = getArguments().getString(ARG_PATH);
}
mFilename.setText(path);

View File

@ -17,38 +17,33 @@
package org.sufficientlysecure.keychain.ui;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.ui.widget.ImportKeysListLoader;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.R;
import com.actionbarsherlock.app.SherlockListFragment;
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysAdapter;
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry;
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListLoader;
import org.sufficientlysecure.keychain.util.Log;
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.content.Loader;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader;
import android.view.View;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import com.actionbarsherlock.app.SherlockListFragment;
public class ImportKeysListFragment extends SherlockListFragment implements
LoaderManager.LoaderCallbacks<List<Map<String, String>>> {
// public static final String ARG_IMPORT_DATA = "bytes";
// public static final String ARG_IMPORT_FILENAME = "filename";
LoaderManager.LoaderCallbacks<List<ImportKeysListEntry>> {
private Activity mActivity;
private SimpleAdapter mAdapter;
private ImportKeysAdapter mAdapter;
private byte[] mKeyBytes;
private String mImportFilename;
public byte[] getKeyBytes() {
return mKeyBytes;
}
@ -57,38 +52,19 @@ public class ImportKeysListFragment extends SherlockListFragment implements
return mImportFilename;
}
public List<ImportKeysListEntry> getData() {
return mAdapter.getData();
}
/**
* Creates new instance of this fragment
*/
public static ImportKeysListFragment newInstance() {
ImportKeysListFragment frag = new ImportKeysListFragment();
Bundle args = new Bundle();
frag.setArguments(args);
return frag;
}
@Override
public void onListItemClick(ListView listView, View view, int position, long id) {
// Map<String, String> item = (Map<String, String>) listView.getItemAtPosition(position);
// String userId = item.get(ImportKeysListLoader.MAP_ATTR_USER_ID);
}
/**
* Resume is called after rotating
*/
@Override
public void onResume() {
super.onResume();
// Start out with a progress indicator.
setListShown(false);
// reload list
getLoaderManager().restartLoader(0, null, this);
}
/**
* Define Adapter and Loader on create of Activity
*/
@ -96,10 +72,7 @@ public class ImportKeysListFragment extends SherlockListFragment implements
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mActivity = this.getActivity();
// mKeyBytes = getArguments().getByteArray(ARG_IMPORT_DATA);
// mImportFilename = getArguments().getString(ARG_IMPORT_FILENAME);
mActivity = getActivity();
// register long press context menu
registerForContextMenu(getListView());
@ -109,11 +82,7 @@ public class ImportKeysListFragment extends SherlockListFragment implements
setEmptyText(mActivity.getString(R.string.error_nothingImport));
// Create an empty adapter we will use to display the loaded data.
String[] from = new String[] {};
int[] to = new int[] {};
List<Map<String, String>> data = new ArrayList<Map<String, String>>();
mAdapter = new SimpleAdapter(getActivity(), data, android.R.layout.two_line_list_item,
from, to);
mAdapter = new ImportKeysAdapter(getActivity());
setListAdapter(mAdapter);
// Start out with a progress indicator.
@ -124,39 +93,37 @@ public class ImportKeysListFragment extends SherlockListFragment implements
getLoaderManager().initLoader(0, null, this);
}
public void load(byte[] importData, String importFilename) {
mKeyBytes = importData;
mImportFilename = importFilename;
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
getLoaderManager().initLoader(0, null, this);
// Select checkbox!
// Update underlying data and notify adapter of change. The adapter will
// update the view automatically.
ImportKeysListEntry entry = mAdapter.getItem(position);
entry.setSelected(!entry.isSelected());
mAdapter.notifyDataSetChanged();
}
public void load(byte[] importData, String importFilename) {
this.mKeyBytes = importData;
this.mImportFilename = importFilename;
}
@Override
public Loader<List<Map<String, String>>> onCreateLoader(int id, Bundle args) {
public Loader<List<ImportKeysListEntry>> onCreateLoader(int id, Bundle args) {
return new ImportKeysListLoader(mActivity, mKeyBytes, mImportFilename);
}
@Override
public void onLoadFinished(Loader<List<Map<String, String>>> loader,
List<Map<String, String>> data) {
// Set the new data in the adapter.
// for (String item : data) {
// mAdapter.add(item);
// }
public void onLoadFinished(Loader<List<ImportKeysListEntry>> loader,
List<ImportKeysListEntry> data) {
Log.d(Constants.TAG, "data: " + data);
// TODO: real swapping the data to the already defined adapter doesn't work
// Workaround: recreate adapter!
// http://stackoverflow.com/questions/2356091/android-add-function-of-arrayadapter-not-working
// mAdapter = new ArrayAdapter<String>(mActivity, android.R.layout.two_line_list_item,
// data);
String[] from = new String[] { ImportKeysListLoader.MAP_ATTR_USER_ID,
ImportKeysListLoader.MAP_ATTR_FINGERPINT };
int[] to = new int[] { android.R.id.text1, android.R.id.text2 };
mAdapter = new SimpleAdapter(getActivity(), data, android.R.layout.two_line_list_item,
from, to);
// swap in the real data!
mAdapter.setData(data);
mAdapter.notifyDataSetChanged();
setListAdapter(mAdapter);
// The list should now be shown.
@ -168,10 +135,9 @@ public class ImportKeysListFragment extends SherlockListFragment implements
}
@Override
public void onLoaderReset(Loader<List<Map<String, String>>> loader) {
public void onLoaderReset(Loader<List<ImportKeysListEntry>> loader) {
// Clear the data in the adapter.
// Not available in SimpleAdapter!
// mAdapter.clear();
mAdapter.clear();
}
}

View File

@ -19,13 +19,17 @@ 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.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.Button;
public class ImportKeysServerFragment extends Fragment {
private Button mButton;
/**
* Creates new instance of this fragment
@ -44,8 +48,19 @@ public class ImportKeysServerFragment extends Fragment {
*/
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.import_keys_keyserver_fragment, container, false);
View view = inflater.inflate(R.layout.import_keys_keyserver_fragment, container, false);
mButton = (Button) view.findViewById(R.id.import_keyserver_button);
mButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO: use fragment instead of activity, handle onresult here!
startActivityForResult(new Intent(getActivity(), KeyServerQueryActivity.class), 0);
}
});
return view;
}
}

View File

@ -23,7 +23,7 @@ import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
import org.sufficientlysecure.keychain.ui.widget.KeyListAdapter;
import org.sufficientlysecure.keychain.ui.adapter.KeyListAdapter;
import org.sufficientlysecure.keychain.R;
import android.content.Intent;

View File

@ -22,7 +22,7 @@ import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.ui.widget.KeyListAdapter;
import org.sufficientlysecure.keychain.ui.adapter.KeyListAdapter;
import android.database.Cursor;
import android.net.Uri;

View File

@ -140,7 +140,7 @@ public class KeyServerQueryActivity extends SherlockFragmentActivity {
if (ACTION_LOOK_UP_KEY_ID.equals(action) || ACTION_LOOK_UP_KEY_ID_AND_RETURN.equals(action)) {
long keyId = intent.getLongExtra(EXTRA_KEY_ID, 0);
if (keyId != 0) {
String query = "0x" + PgpKeyHelper.keyToHex(keyId);
String query = "0x" + PgpKeyHelper.convertKeyToHex(keyId);
mQuery.setText(query);
search(query);
}
@ -308,7 +308,7 @@ public class KeyServerQueryActivity extends SherlockFragmentActivity {
mainUserId.setText(userId);
}
keyId.setText(PgpKeyHelper.getSmallFingerPrint(keyInfo.keyId));
keyId.setText(PgpKeyHelper.convertKeyIdToHex(keyInfo.keyId));
if (mainUserIdRest.getText().length() == 0) {
mainUserIdRest.setVisibility(View.GONE);

View File

@ -28,7 +28,7 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
import org.sufficientlysecure.keychain.provider.KeychainDatabase;
import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;
import org.sufficientlysecure.keychain.ui.widget.SelectKeyCursorAdapter;
import org.sufficientlysecure.keychain.ui.adapter.SelectKeyCursorAdapter;
import android.app.Activity;
import android.database.Cursor;

View File

@ -26,7 +26,7 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
import org.sufficientlysecure.keychain.provider.KeychainDatabase;
import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;
import org.sufficientlysecure.keychain.ui.widget.SelectKeyCursorAdapter;
import org.sufficientlysecure.keychain.ui.adapter.SelectKeyCursorAdapter;
import android.database.Cursor;
import android.net.Uri;

View File

@ -0,0 +1,151 @@
/*
* 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.adapter;
import java.util.List;
import org.sufficientlysecure.keychain.R;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.graphics.Color;
import android.os.Build;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.TextView;
public class ImportKeysAdapter extends ArrayAdapter<ImportKeysListEntry> {
protected LayoutInflater mInflater;
protected Activity mActivity;
protected List<ImportKeysListEntry> data;
public ImportKeysAdapter(Activity activity) {
super(activity, -1);
mActivity = activity;
mInflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@SuppressLint("NewApi")
public void setData(List<ImportKeysListEntry> data) {
clear();
if (data != null) {
if (Build.VERSION.SDK_INT >= 11) {
addAll(data);
} else {
for (ImportKeysListEntry entry : data) {
add(entry);
}
}
this.data = data;
}
}
public List<ImportKeysListEntry> getData() {
return data;
}
@Override
public boolean hasStableIds() {
return true;
}
public View getView(int position, View convertView, ViewGroup parent) {
ImportKeysListEntry entry = data.get(position);
View view = mInflater.inflate(R.layout.import_keys_list_entry, null);
TextView mainUserId = (TextView) view.findViewById(R.id.mainUserId);
mainUserId.setText(R.string.unknownUserId);
TextView mainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest);
mainUserIdRest.setText("");
TextView keyId = (TextView) view.findViewById(R.id.keyId);
keyId.setText(R.string.noKey);
TextView fingerprint = (TextView) view.findViewById(R.id.fingerprint);
TextView algorithm = (TextView) view.findViewById(R.id.algorithm);
algorithm.setText("");
TextView status = (TextView) view.findViewById(R.id.status);
status.setText("");
String userId = entry.userIds.get(0);
if (userId != null) {
String chunks[] = userId.split(" <", 2);
userId = chunks[0];
if (chunks.length > 1) {
mainUserIdRest.setText("<" + chunks[1]);
}
if (entry.secretKey) {
userId = mActivity.getString(R.string.secretKey) + " " + userId;
mainUserId.setTextColor(Color.RED);
}
mainUserId.setText(userId);
}
keyId.setText(entry.hexKeyId);
fingerprint.setText(mActivity.getString(R.string.fingerprint) + " " + entry.fingerPrint);
if (mainUserIdRest.getText().length() == 0) {
mainUserIdRest.setVisibility(View.GONE);
}
algorithm.setText("" + entry.bitStrength + "/" + entry.algorithm);
if (entry.revoked) {
status.setText("revoked");
} else {
status.setVisibility(View.GONE);
}
LinearLayout ll = (LinearLayout) view.findViewById(R.id.list);
if (entry.userIds.size() == 1) {
ll.setVisibility(View.GONE);
} else {
boolean first = true;
boolean second = true;
for (String uid : entry.userIds) {
if (first) {
first = false;
continue;
}
if (!second) {
View sep = new View(mActivity);
sep.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, 1));
sep.setBackgroundResource(android.R.drawable.divider_horizontal_dark);
ll.addView(sep);
}
TextView uidView = (TextView) mInflater.inflate(
R.layout.import_keys_list_entry_user_id, null);
uidView.setText(uid);
ll.addView(uidView);
second = false;
}
}
CheckBox cBox = (CheckBox) view.findViewById(R.id.selected);
cBox.setChecked(entry.isSelected());
return view;
}
}

View File

@ -0,0 +1,105 @@
/*
* 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.adapter;
import java.io.Serializable;
import java.util.ArrayList;
import org.spongycastle.openpgp.PGPKeyRing;
import org.spongycastle.openpgp.PGPPublicKey;
import org.spongycastle.openpgp.PGPSecretKeyRing;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.util.AlgorithmNames;
import org.sufficientlysecure.keychain.util.IterableIterator;
public class ImportKeysListEntry implements Serializable {
private static final long serialVersionUID = -7797972103284992662L;
public ArrayList<String> userIds;
public long keyId;
public boolean revoked;
// public Date date;
public String fingerPrint;
public String hexKeyId;
public int bitStrength;
public String algorithm;
public boolean secretKey;
AlgorithmNames algorithmNames;
private boolean selected;
/**
* Constructor for later querying from keyserver
*/
public ImportKeysListEntry() {
secretKey = false;
userIds = new ArrayList<String>();
}
public boolean isSelected() {
return selected;
}
public void setSelected(boolean selected) {
this.selected = selected;
}
/**
* Constructor based on key object, used for import from NFC, QR Codes, files
*
* @param pgpKey
*/
@SuppressWarnings("unchecked")
public ImportKeysListEntry(PGPKeyRing pgpKeyRing) {
// selected is default
this.selected = true;
if (pgpKeyRing instanceof PGPSecretKeyRing) {
secretKey = true;
} else {
secretKey = false;
}
userIds = new ArrayList<String>();
for (String userId : new IterableIterator<String>(pgpKeyRing.getPublicKey().getUserIDs())) {
userIds.add(userId);
}
this.keyId = pgpKeyRing.getPublicKey().getKeyID();
this.revoked = pgpKeyRing.getPublicKey().isRevoked();
this.fingerPrint = PgpKeyHelper.convertFingerprintToHex(pgpKeyRing.getPublicKey()
.getFingerprint());
this.hexKeyId = PgpKeyHelper.convertKeyIdToHex(keyId);
this.bitStrength = pgpKeyRing.getPublicKey().getBitStrength();
int algorithm = pgpKeyRing.getPublicKey().getAlgorithm();
if (algorithm == PGPPublicKey.RSA_ENCRYPT || algorithm == PGPPublicKey.RSA_GENERAL
|| algorithm == PGPPublicKey.RSA_SIGN) {
this.algorithm = "RSA";
} else if (algorithm == PGPPublicKey.DSA) {
this.algorithm = "DSA";
} else if (algorithm == PGPPublicKey.ELGAMAL_ENCRYPT
|| algorithm == PGPPublicKey.ELGAMAL_GENERAL) {
this.algorithm = "ElGamal";
} else if (algorithm == PGPPublicKey.EC || algorithm == PGPPublicKey.ECDSA) {
this.algorithm = "ECC";
} else {
// TODO: with resources
this.algorithm = "unknown";
}
}
}

View File

@ -15,7 +15,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.sufficientlysecure.keychain.ui.widget;
package org.sufficientlysecure.keychain.ui.adapter;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
@ -23,32 +23,23 @@ import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.spongycastle.openpgp.PGPKeyRing;
import org.spongycastle.openpgp.PGPObjectFactory;
import org.spongycastle.openpgp.PGPSecretKeyRing;
import org.spongycastle.openpgp.PGPUtil;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.PositionAwareInputStream;
import org.sufficientlysecure.keychain.R;
import android.content.Context;
import android.support.v4.content.AsyncTaskLoader;
public class ImportKeysListLoader extends AsyncTaskLoader<List<Map<String, String>>> {
public static final String MAP_ATTR_USER_ID = "user_id";
public static final String MAP_ATTR_FINGERPINT = "fingerprint";
ArrayList<Map<String, String>> data = new ArrayList<Map<String, String>>();
public class ImportKeysListLoader extends AsyncTaskLoader<List<ImportKeysListEntry>> {
Context mContext;
List<String> mItems;
ArrayList<ImportKeysListEntry> data = new ArrayList<ImportKeysListEntry>();
byte[] mKeyringBytes;
String mImportFilename;
@ -61,7 +52,7 @@ public class ImportKeysListLoader extends AsyncTaskLoader<List<Map<String, Strin
}
@Override
public List<Map<String, String>> loadInBackground() {
public List<ImportKeysListEntry> loadInBackground() {
InputData inputData = null;
if (mKeyringBytes != null) {
inputData = new InputData(new ByteArrayInputStream(mKeyringBytes), mKeyringBytes.length);
@ -76,6 +67,7 @@ public class ImportKeysListLoader extends AsyncTaskLoader<List<Map<String, Strin
return data;
}
if (inputData != null)
generateListOfKeyrings(inputData);
return data;
@ -100,12 +92,12 @@ public class ImportKeysListLoader extends AsyncTaskLoader<List<Map<String, Strin
}
@Override
public void deliverResult(List<Map<String, String>> data) {
public void deliverResult(List<ImportKeysListEntry> data) {
super.deliverResult(data);
}
/**
* Similar to PGPMain.importKeyRings
* Reads all PGPKeyRing objects from input
*
* @param keyringBytes
* @return
@ -144,20 +136,8 @@ public class ImportKeysListLoader extends AsyncTaskLoader<List<Map<String, Strin
}
private void addToData(PGPKeyRing keyring) {
String userId = PgpKeyHelper.getMainUserId(keyring.getPublicKey());
if (keyring instanceof PGPSecretKeyRing) {
userId = mContext.getString(R.string.secretKeyring) + " " + userId;
}
String fingerprint = PgpKeyHelper.convertFingerprintToHex(keyring.getPublicKey()
.getFingerprint());
Map<String, String> attrs = new HashMap<String, String>();
attrs.put(MAP_ATTR_USER_ID, userId);
attrs.put(MAP_ATTR_FINGERPINT, mContext.getString(R.string.fingerprint) + "\n"
+ fingerprint);
data.add(attrs);
ImportKeysListEntry item = new ImportKeysListEntry(keyring);
data.add(item);
}
}

View File

@ -79,7 +79,7 @@ public class LookupUnknownKeyDialogFragment extends DialogFragment {
alert.setIcon(android.R.drawable.ic_dialog_alert);
alert.setTitle(R.string.title_unknownSignatureKey);
alert.setMessage(getString(R.string.lookupUnknownKey,
PgpKeyHelper.getSmallFingerPrint(unknownKeyId)));
PgpKeyHelper.convertKeyIdToHex(unknownKeyId)));
alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {

View File

@ -152,8 +152,8 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener {
}
mAlgorithm.setText(PgpKeyHelper.getAlgorithmInfo(key));
String keyId1Str = PgpKeyHelper.getSmallFingerPrint(key.getKeyID());
String keyId2Str = PgpKeyHelper.getSmallFingerPrint(key.getKeyID() >> 32);
String keyId1Str = PgpKeyHelper.convertKeyIdToHex(key.getKeyID());
String keyId2Str = PgpKeyHelper.convertKeyIdToHex(key.getKeyID() >> 32);
mKeyId.setText(keyId1Str + " " + keyId2Str);
Vector<Choice> choices = new Vector<Choice>();

View File

@ -1,273 +0,0 @@
/*
* Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sufficientlysecure.keychain.ui.widget;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.helper.OtherHelper;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.R;
import android.content.Context;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.database.MergeCursor;
import android.net.Uri;
import android.provider.BaseColumns;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CursorTreeAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
public class KeyListAdapter extends CursorTreeAdapter {
private Context mContext;
private LayoutInflater mInflater;
protected int mKeyType;
private static final int CHILD_KEY = 0;
private static final int CHILD_USER_ID = 1;
private static final int CHILD_FINGERPRINT = 2;
public KeyListAdapter(Context context, Cursor groupCursor, int keyType) {
super(groupCursor, context);
mContext = context;
mInflater = LayoutInflater.from(context);
mKeyType = keyType;
}
/**
* Inflate new view for group items
*/
@Override
public View newGroupView(Context context, Cursor cursor, boolean isExpanded, ViewGroup parent) {
return mInflater.inflate(R.layout.key_list_group_item, null);
}
/**
* Binds TextViews from group view to results from database group cursor.
*/
@Override
protected void bindGroupView(View view, Context context, Cursor cursor, boolean isExpanded) {
int userIdIndex = cursor.getColumnIndex(UserIds.USER_ID);
TextView mainUserId = (TextView) view.findViewById(R.id.mainUserId);
mainUserId.setText(R.string.unknownUserId);
TextView mainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest);
mainUserIdRest.setText("");
String userId = cursor.getString(userIdIndex);
if (userId != null) {
String[] userIdSplit = OtherHelper.splitUserId(userId);
if (userIdSplit[1] != null) {
mainUserIdRest.setText(userIdSplit[1]);
}
mainUserId.setText(userIdSplit[0]);
}
if (mainUserId.getText().length() == 0) {
mainUserId.setText(R.string.unknownUserId);
}
if (mainUserIdRest.getText().length() == 0) {
mainUserIdRest.setVisibility(View.GONE);
} else {
mainUserIdRest.setVisibility(View.VISIBLE);
}
}
/**
* Inflate new view for child items
*/
@Override
public View newChildView(Context context, Cursor cursor, boolean isLastChild, ViewGroup parent) {
return mInflater.inflate(R.layout.key_list_child_item, null);
}
/**
* Bind TextViews from view of childs based on query results
*/
@Override
protected void bindChildView(View view, Context context, Cursor cursor, boolean isLastChild) {
LinearLayout keyLayout = (LinearLayout) view.findViewById(R.id.keyLayout);
LinearLayout userIdLayout = (LinearLayout) view.findViewById(R.id.userIdLayout);
// first entry is fingerprint
if (cursor.getPosition() == 0) {
// show only userId layout
keyLayout.setVisibility(View.GONE);
userIdLayout.setVisibility(View.VISIBLE);
String fingerprint = PgpKeyHelper.getFingerPrint(context,
cursor.getLong(cursor.getColumnIndex(Keys.KEY_ID)));
fingerprint = fingerprint.replace(" ", "\n");
TextView userId = (TextView) view.findViewById(R.id.userId);
if (userId == null) {
Log.d(Constants.TAG, "userId is null!");
}
userId.setText(context.getString(R.string.fingerprint) + "\n" + fingerprint);
} else {
// differentiate between keys and userIds in MergeCursor
if (cursor.getColumnIndex(Keys.KEY_ID) != -1) {
keyLayout.setVisibility(View.VISIBLE);
userIdLayout.setVisibility(View.GONE);
String keyIdStr = PgpKeyHelper.getSmallFingerPrint(cursor.getLong(cursor
.getColumnIndex(Keys.KEY_ID)));
String algorithmStr = PgpKeyHelper.getAlgorithmInfo(
cursor.getInt(cursor.getColumnIndex(Keys.ALGORITHM)),
cursor.getInt(cursor.getColumnIndex(Keys.KEY_SIZE)));
TextView keyId = (TextView) view.findViewById(R.id.keyId);
keyId.setText(keyIdStr);
TextView keyDetails = (TextView) view.findViewById(R.id.keyDetails);
keyDetails.setText("(" + algorithmStr + ")");
ImageView masterKeyIcon = (ImageView) view.findViewById(R.id.ic_masterKey);
if (cursor.getInt(cursor.getColumnIndex(Keys.IS_MASTER_KEY)) != 1) {
masterKeyIcon.setVisibility(View.INVISIBLE);
} else {
masterKeyIcon.setVisibility(View.VISIBLE);
}
ImageView certifyIcon = (ImageView) view.findViewById(R.id.ic_certifyKey);
if (cursor.getInt(cursor.getColumnIndex(Keys.CAN_CERTIFY)) != 1) {
certifyIcon.setVisibility(View.GONE);
} else {
certifyIcon.setVisibility(View.VISIBLE);
}
ImageView encryptIcon = (ImageView) view.findViewById(R.id.ic_encryptKey);
if (cursor.getInt(cursor.getColumnIndex(Keys.CAN_ENCRYPT)) != 1) {
encryptIcon.setVisibility(View.GONE);
} else {
encryptIcon.setVisibility(View.VISIBLE);
}
ImageView signIcon = (ImageView) view.findViewById(R.id.ic_signKey);
if (cursor.getInt(cursor.getColumnIndex(Keys.CAN_SIGN)) != 1) {
signIcon.setVisibility(View.GONE);
} else {
signIcon.setVisibility(View.VISIBLE);
}
} else {
keyLayout.setVisibility(View.GONE);
userIdLayout.setVisibility(View.VISIBLE);
String userIdStr = cursor.getString(cursor.getColumnIndex(UserIds.USER_ID));
TextView userId = (TextView) view.findViewById(R.id.userId);
userId.setText(userIdStr);
}
}
}
/**
* Given the group cursor, we start cursors for a fingerprint, keys, and userIds, which are
* merged together and build the child cursor
*/
@Override
protected Cursor getChildrenCursor(Cursor groupCursor) {
final long keyRingRowId = groupCursor.getLong(groupCursor.getColumnIndex(BaseColumns._ID));
Cursor fingerprintCursor = getChildCursor(keyRingRowId, CHILD_FINGERPRINT);
Cursor keyCursor = getChildCursor(keyRingRowId, CHILD_KEY);
Cursor userIdCursor = getChildCursor(keyRingRowId, CHILD_USER_ID);
MergeCursor mergeCursor = new MergeCursor(new Cursor[] { fingerprintCursor, keyCursor,
userIdCursor });
Log.d(Constants.TAG, "mergeCursor:" + DatabaseUtils.dumpCursorToString(mergeCursor));
return mergeCursor;
}
/**
* This builds a cursor for a specific type of children
*
* @param keyRingRowId
* foreign row id of the keyRing
* @param type
* @return
*/
private Cursor getChildCursor(long keyRingRowId, int type) {
Uri uri = null;
String[] projection = null;
String sortOrder = null;
String selection = null;
switch (type) {
case CHILD_FINGERPRINT:
projection = new String[] { Keys._ID, Keys.KEY_ID, Keys.IS_MASTER_KEY, Keys.ALGORITHM,
Keys.KEY_SIZE, Keys.CAN_CERTIFY, Keys.CAN_SIGN, Keys.CAN_ENCRYPT, };
sortOrder = Keys.RANK + " ASC";
// use only master key for fingerprint
selection = Keys.IS_MASTER_KEY + " = 1 ";
if (mKeyType == Id.type.public_key) {
uri = Keys.buildPublicKeysUri(String.valueOf(keyRingRowId));
} else {
uri = Keys.buildSecretKeysUri(String.valueOf(keyRingRowId));
}
break;
case CHILD_KEY:
projection = new String[] { Keys._ID, Keys.KEY_ID, Keys.IS_MASTER_KEY, Keys.ALGORITHM,
Keys.KEY_SIZE, Keys.CAN_CERTIFY, Keys.CAN_SIGN, Keys.CAN_ENCRYPT, };
sortOrder = Keys.RANK + " ASC";
if (mKeyType == Id.type.public_key) {
uri = Keys.buildPublicKeysUri(String.valueOf(keyRingRowId));
} else {
uri = Keys.buildSecretKeysUri(String.valueOf(keyRingRowId));
}
break;
case CHILD_USER_ID:
projection = new String[] { UserIds._ID, UserIds.USER_ID, UserIds.RANK, };
sortOrder = UserIds.RANK + " ASC";
// not the main user id
selection = UserIds.RANK + " > 0 ";
if (mKeyType == Id.type.public_key) {
uri = UserIds.buildPublicUserIdsUri(String.valueOf(keyRingRowId));
} else {
uri = UserIds.buildSecretUserIdsUri(String.valueOf(keyRingRowId));
}
break;
default:
return null;
}
return mContext.getContentResolver().query(uri, projection, selection, null, sortOrder);
}
}

View File

@ -1,140 +0,0 @@
/*
* Copyright (C) 2012-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.widget;
import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.helper.OtherHelper;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
import org.sufficientlysecure.keychain.R;
import android.content.Context;
import android.database.Cursor;
import android.support.v4.widget.CursorAdapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.ListView;
import android.widget.TextView;
public class SelectKeyCursorAdapter extends CursorAdapter {
protected int mKeyType;
private LayoutInflater mInflater;
private ListView mListView;
public final static String PROJECTION_ROW_AVAILABLE = "available";
public final static String PROJECTION_ROW_VALID = "valid";
public SelectKeyCursorAdapter(Context context, Cursor c, int flags, ListView listView,
int keyType) {
super(context, c, flags);
mInflater = LayoutInflater.from(context);
mListView = listView;
mKeyType = keyType;
}
public String getUserId(int position) {
mCursor.moveToPosition(position);
return mCursor.getString(mCursor.getColumnIndex(UserIds.USER_ID));
}
public long getMasterKeyId(int position) {
mCursor.moveToPosition(position);
return mCursor.getLong(mCursor.getColumnIndex(KeyRings.MASTER_KEY_ID));
}
@Override
public void bindView(View view, Context context, Cursor cursor) {
boolean valid = cursor.getInt(cursor.getColumnIndex(PROJECTION_ROW_VALID)) > 0;
TextView mainUserId = (TextView) view.findViewById(R.id.mainUserId);
mainUserId.setText(R.string.unknownUserId);
TextView mainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest);
mainUserIdRest.setText("");
TextView keyId = (TextView) view.findViewById(R.id.keyId);
keyId.setText(R.string.noKey);
TextView status = (TextView) view.findViewById(R.id.status);
status.setText(R.string.unknownStatus);
String userId = cursor.getString(cursor.getColumnIndex(UserIds.USER_ID));
if (userId != null) {
String[] userIdSplit = OtherHelper.splitUserId(userId);
if (userIdSplit[1] != null) {
mainUserIdRest.setText(userIdSplit[1]);
}
mainUserId.setText(userIdSplit[0]);
}
long masterKeyId = cursor.getLong(cursor.getColumnIndex(KeyRings.MASTER_KEY_ID));
keyId.setText(PgpKeyHelper.getSmallFingerPrint(masterKeyId));
if (mainUserIdRest.getText().length() == 0) {
mainUserIdRest.setVisibility(View.GONE);
}
if (valid) {
if (mKeyType == Id.type.public_key) {
status.setText(R.string.canEncrypt);
} else {
status.setText(R.string.canSign);
}
} else {
if (cursor.getInt(cursor.getColumnIndex(PROJECTION_ROW_AVAILABLE)) > 0) {
// has some CAN_ENCRYPT keys, but col(ROW_VALID) = 0, so must be revoked or
// expired
status.setText(R.string.expired);
} else {
status.setText(R.string.noKey);
}
}
CheckBox selected = (CheckBox) view.findViewById(R.id.selected);
if (mKeyType == Id.type.public_key) {
selected.setVisibility(View.VISIBLE);
if (!valid) {
mListView.setItemChecked(cursor.getPosition(), false);
}
selected.setChecked(mListView.isItemChecked(cursor.getPosition()));
selected.setEnabled(valid);
} else {
selected.setVisibility(View.GONE);
}
status.setText(status.getText() + " ");
view.setEnabled(valid);
mainUserId.setEnabled(valid);
mainUserIdRest.setEnabled(valid);
keyId.setEnabled(valid);
status.setEnabled(valid);
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return mInflater.inflate(R.layout.select_key_item, null);
}
}

View File

@ -0,0 +1,92 @@
/*
* 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.util;
import java.util.HashMap;
import org.spongycastle.bcpg.HashAlgorithmTags;
import org.spongycastle.openpgp.PGPEncryptedData;
import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R;
import android.annotation.SuppressLint;
import android.app.Activity;
@SuppressLint("UseSparseArrays")
public class AlgorithmNames {
Activity mActivity;
HashMap<Integer, String> mEncryptionNames = new HashMap<Integer, String>();
HashMap<Integer, String> mHashNames = new HashMap<Integer, String>();
HashMap<Integer, String> mCompressionNames = new HashMap<Integer, String>();
public AlgorithmNames(Activity context) {
super();
this.mActivity = context;
mEncryptionNames.put(PGPEncryptedData.AES_128, "AES-128");
mEncryptionNames.put(PGPEncryptedData.AES_192, "AES-192");
mEncryptionNames.put(PGPEncryptedData.AES_256, "AES-256");
mEncryptionNames.put(PGPEncryptedData.BLOWFISH, "Blowfish");
mEncryptionNames.put(PGPEncryptedData.TWOFISH, "Twofish");
mEncryptionNames.put(PGPEncryptedData.CAST5, "CAST5");
mEncryptionNames.put(PGPEncryptedData.DES, "DES");
mEncryptionNames.put(PGPEncryptedData.TRIPLE_DES, "Triple DES");
mEncryptionNames.put(PGPEncryptedData.IDEA, "IDEA");
mHashNames.put(HashAlgorithmTags.MD5, "MD5");
mHashNames.put(HashAlgorithmTags.RIPEMD160, "RIPEMD-160");
mHashNames.put(HashAlgorithmTags.SHA1, "SHA-1");
mHashNames.put(HashAlgorithmTags.SHA224, "SHA-224");
mHashNames.put(HashAlgorithmTags.SHA256, "SHA-256");
mHashNames.put(HashAlgorithmTags.SHA384, "SHA-384");
mHashNames.put(HashAlgorithmTags.SHA512, "SHA-512");
mCompressionNames.put(Id.choice.compression.none, mActivity.getString(R.string.choice_none)
+ " (" + mActivity.getString(R.string.fast) + ")");
mCompressionNames.put(Id.choice.compression.zip,
"ZIP (" + mActivity.getString(R.string.fast) + ")");
mCompressionNames.put(Id.choice.compression.zlib,
"ZLIB (" + mActivity.getString(R.string.fast) + ")");
mCompressionNames.put(Id.choice.compression.bzip2,
"BZIP2 (" + mActivity.getString(R.string.very_slow) + ")");
}
public HashMap<Integer, String> getEncryptionNames() {
return mEncryptionNames;
}
public void setEncryptionNames(HashMap<Integer, String> encryptionNames) {
this.mEncryptionNames = encryptionNames;
}
public HashMap<Integer, String> getHashNames() {
return mHashNames;
}
public void setHashNames(HashMap<Integer, String> hashNames) {
this.mHashNames = hashNames;
}
public HashMap<Integer, String> getCompressionNames() {
return mCompressionNames;
}
public void setCompressionNames(HashMap<Integer, String> compressionNames) {
this.mCompressionNames = compressionNames;
}
}

View File

@ -179,8 +179,8 @@ public class HkpKeyServer extends KeyServer {
KeyInfo info = new KeyInfo();
info.size = Integer.parseInt(matcher.group(1));
info.algorithm = matcher.group(2);
info.keyId = PgpKeyHelper.keyFromHex(matcher.group(3));
info.fingerPrint = PgpKeyHelper.getSmallFingerPrint(info.keyId);
info.keyId = PgpKeyHelper.convertHexToKeyId(matcher.group(3));
info.fingerPrint = PgpKeyHelper.convertKeyIdToHex(info.keyId);
String chunks[] = matcher.group(4).split("-");
info.date = new GregorianCalendar(Integer.parseInt(chunks[0]),
Integer.parseInt(chunks[1]), Integer.parseInt(chunks[2])).getTime();
@ -211,7 +211,7 @@ public class HkpKeyServer extends KeyServer {
HttpClient client = new DefaultHttpClient();
try {
HttpGet get = new HttpGet("http://" + mHost + ":" + mPort
+ "/pks/lookup?op=get&search=0x" + PgpKeyHelper.keyToHex(keyId));
+ "/pks/lookup?op=get&search=0x" + PgpKeyHelper.convertKeyToHex(keyId));
HttpResponse response = client.execute(get);
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
@ -235,13 +235,13 @@ public class HkpKeyServer extends KeyServer {
}
@Override
public void add(String armouredText) throws AddKeyException {
public void add(String armoredText) throws AddKeyException {
HttpClient client = new DefaultHttpClient();
try {
HttpPost post = new HttpPost("http://" + mHost + ":" + mPort + "/pks/add");
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
nameValuePairs.add(new BasicNameValuePair("keytext", armouredText));
nameValuePairs.add(new BasicNameValuePair("keytext", armoredText));
post.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse response = client.execute(post);

View File

@ -1,101 +0,0 @@
/*
* 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.util;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeSet;
import android.content.Context;
import android.widget.ArrayAdapter;
public class KeyValueSpinnerAdapter extends ArrayAdapter<String> {
private final HashMap<Integer, String> mData;
private final int[] mKeys;
private final String[] mValues;
static <K, V extends Comparable<? super V>> SortedSet<Map.Entry<K, V>> entriesSortedByValues(
Map<K, V> map) {
SortedSet<Map.Entry<K, V>> sortedEntries = new TreeSet<Map.Entry<K, V>>(
new Comparator<Map.Entry<K, V>>() {
@Override
public int compare(Map.Entry<K, V> e1, Map.Entry<K, V> e2) {
return e1.getValue().compareTo(e2.getValue());
}
});
sortedEntries.addAll(map.entrySet());
return sortedEntries;
}
public KeyValueSpinnerAdapter(Context context, HashMap<Integer, String> objects) {
// To make the drop down a simple text box
super(context, android.R.layout.simple_spinner_item);
mData = objects;
// To make the drop down view a radio button list
setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
SortedSet<Map.Entry<Integer, String>> sorted = entriesSortedByValues(objects);
// Assign hash keys with a position so that we can present and retrieve them
int i = 0;
mKeys = new int[mData.size()];
mValues = new String[mData.size()];
for (Map.Entry<Integer, String> entry : sorted) {
mKeys[i] = entry.getKey();
mValues[i] = entry.getValue();
i++;
}
}
public int getCount() {
return mData.size();
}
/**
* Returns the value
*/
@Override
public String getItem(int position) {
// return the value based on the position. This is displayed in the list.
return mValues[position];
}
/**
* Returns item key
*/
public long getItemId(int position) {
// Return an id to represent the item.
return mKeys[position];
}
/**
* Find position from key
*/
public int getPosition(long itemId) {
for (int i = 0; i < mKeys.length; i++) {
if ((int) itemId == mKeys[i]) {
return i;
}
}
return -1;
}
}