mirror of
https://github.com/moparisthebest/open-keychain
synced 2024-11-23 17:22:16 -05:00
set svn:eol-style to LF for all code/resource files
This commit is contained in:
parent
ec10329664
commit
f5efd73d33
@ -1,38 +1,38 @@
|
||||
<?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:paddingBottom="5dip"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/filterInfo"
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:ellipsize="end"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_clear"
|
||||
android:text="@string/btn_clearFilter"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</LinearLayout>
|
||||
<?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:paddingBottom="5dip"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/filterInfo"
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:ellipsize="end"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_clear"
|
||||
android:text="@string/btn_clearFilter"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
@ -1,80 +1,80 @@
|
||||
<?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:singleLine="true"
|
||||
android:paddingLeft="10dip"
|
||||
android:layout_marginRight="?android:attr/scrollbarSize"
|
||||
android:layout_height="?android:attr/listPreferredItemHeight"
|
||||
android:layout_width="fill_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="fill_parent"
|
||||
android:orientation="horizontal"
|
||||
android:paddingRight="3dip">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/ic_masterKey"
|
||||
android:src="@drawable/key_small"
|
||||
android:paddingRight="6dip"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/keyId"
|
||||
android:text="Key ID"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingRight="5dip"
|
||||
android:typeface="monospace"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/keyDetails"
|
||||
android:text="(RSA, 1024bit)"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<LinearLayout
|
||||
android:gravity="right"
|
||||
android:orientation="horizontal"
|
||||
android:paddingBottom="2dip"
|
||||
android:paddingTop="2dip"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_gravity="center_vertical">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/ic_encryptKey"
|
||||
android:src="@drawable/encrypted_small"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/ic_signKey"
|
||||
android:src="@drawable/signed_small"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
<?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:singleLine="true"
|
||||
android:paddingLeft="10dip"
|
||||
android:layout_marginRight="?android:attr/scrollbarSize"
|
||||
android:layout_height="?android:attr/listPreferredItemHeight"
|
||||
android:layout_width="fill_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="fill_parent"
|
||||
android:orientation="horizontal"
|
||||
android:paddingRight="3dip">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/ic_masterKey"
|
||||
android:src="@drawable/key_small"
|
||||
android:paddingRight="6dip"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/keyId"
|
||||
android:text="Key ID"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingRight="5dip"
|
||||
android:typeface="monospace"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/keyDetails"
|
||||
android:text="(RSA, 1024bit)"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<LinearLayout
|
||||
android:gravity="right"
|
||||
android:orientation="horizontal"
|
||||
android:paddingBottom="2dip"
|
||||
android:paddingTop="2dip"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_gravity="center_vertical">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/ic_encryptKey"
|
||||
android:src="@drawable/encrypted_small"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/ic_signKey"
|
||||
android:src="@drawable/signed_small"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
@ -1,33 +1,33 @@
|
||||
<?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:paddingLeft="40dip"
|
||||
android:layout_marginRight="?android:attr/scrollbarSize"
|
||||
android:singleLine="true"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="?android:attr/listPreferredItemHeight">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/userId"
|
||||
android:text="User ID"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingRight="3dip"/>
|
||||
|
||||
</LinearLayout>
|
||||
<?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:paddingLeft="40dip"
|
||||
android:layout_marginRight="?android:attr/scrollbarSize"
|
||||
android:singleLine="true"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="?android:attr/listPreferredItemHeight">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/userId"
|
||||
android:text="User ID"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingRight="3dip"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
@ -1,258 +1,258 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<string name="app_name">APG</string>
|
||||
|
||||
<!-- title_lowerCase: capitalized words, no punctuation -->
|
||||
<string name="title_mailInbox">Mail Inbox</string>
|
||||
<string name="title_managePublicKeys">Administrér Offentlige Nøgler</string>
|
||||
<string name="title_manageSecretKeys">Administrér Private Nøgler</string>
|
||||
<string name="title_selectRecipients">Vælg Modtagere</string>
|
||||
<string name="title_selectSignature">Vælg Signatur</string>
|
||||
<string name="title_encrypt">Kryptér</string>
|
||||
<string name="title_decrypt">Afkryptér</string>
|
||||
<string name="title_authentification">Autentificering</string>
|
||||
<string name="title_createKey">Opret Nøgle</string>
|
||||
<string name="title_editKey">Redigér Nøgle</string>
|
||||
<string name="title_preferences">Indstillinger</string>
|
||||
<string name="title_changePassPhrase">Skift Kodeord</string>
|
||||
<string name="title_setPassPhrase">Sæt Kodeord</string>
|
||||
<string name="title_sendEmail">"Send Mail..."</string>
|
||||
<string name="title_encryptToFile">Kryptér Til Fil</string>
|
||||
<string name="title_decryptToFile">Afkryptér Til Fil</string>
|
||||
<string name="title_addAccount">Tilføj Konto</string>
|
||||
<string name="title_importKeys">Importér Nøgle</string>
|
||||
<string name="title_exportKey">Eksportér Nøgle</string>
|
||||
<string name="title_exportKeys">Eksportér Nøgler</string>
|
||||
<string name="title_keyNotFound">Ingen Nøgle Matchede</string>
|
||||
|
||||
<!-- section_lowerCase: capitalized words, no punctuation -->
|
||||
<string name="section_userIds">Bruger ID</string>
|
||||
<string name="section_keys">Nøgler</string>
|
||||
<string name="section_general">Generelt</string>
|
||||
<string name="section_defaults">Standard Indstillinger</string>
|
||||
|
||||
<!-- btn_lowerCase: capitalized words, no punctuation -->
|
||||
<string name="btn_encryptToClipboard">Kryptér Til Clipboard</string>
|
||||
<string name="btn_send">Kryptér Og Mail</string>
|
||||
<string name="btn_encrypt">Kryptér</string>
|
||||
<string name="btn_decrypt">Afkryptér</string>
|
||||
<string name="btn_verify">Bekræft</string>
|
||||
<string name="btn_selectEncryptKeys">Vælg Modtagere</string>
|
||||
<string name="btn_reply">Svar</string>
|
||||
<string name="btn_encryptMessage">Kryptér Besked</string>
|
||||
<string name="btn_decryptMessage">Afkryptér Besked</string>
|
||||
<string name="btn_encryptFile">Kryptér Fil</string>
|
||||
<string name="btn_decryptFile">Afkryptér Fil</string>
|
||||
<string name="btn_save">Gem</string>
|
||||
<string name="btn_doNotSave">Fortryd</string>
|
||||
<string name="btn_delete">Slet</string>
|
||||
<string name="btn_noDate">Ingen</string>
|
||||
<string name="btn_clearFilter">Ryd Filter</string>
|
||||
|
||||
<!-- menu_lowerCase: capitalized words, no punctuation -->
|
||||
<string name="menu_about">Om APG</string>
|
||||
<string name="menu_addAccount">Tilføj GMail Konto</string>
|
||||
<string name="menu_deleteAccount">Slet Konto</string>
|
||||
<string name="menu_managePublicKeys">Administrér Offentlige Nøgler</string>
|
||||
<string name="menu_manageSecretKeys">Administrér Private Nøgler</string>
|
||||
<string name="menu_preferences">Indstillinger</string>
|
||||
<string name="menu_changePassPhrase">Skift Kodeord</string>
|
||||
<string name="menu_setPassPhrase">Sæt Kodeord</string>
|
||||
<string name="menu_importKeys">Importér Nøgler</string>
|
||||
<string name="menu_exportKeys">Eksportér Nøgler</string>
|
||||
<string name="menu_exportKey">Eksportér Nøgle</string>
|
||||
<string name="menu_deleteKey">Slet Nøgle</string>
|
||||
<string name="menu_createKey">Opret Nøgle</string>
|
||||
<string name="menu_editKey">Redigér Nøgle</string>
|
||||
<string name="menu_search">Søg</string>
|
||||
|
||||
<!-- label_lowerCase: capitalized words, no punctuation -->
|
||||
<string name="label_sign">Signér</string>
|
||||
<string name="label_message">Besked</string>
|
||||
<string name="label_file">Fil</string>
|
||||
<string name="label_passPhrase">Kodeord</string>
|
||||
<string name="label_passPhraseAgain">Igen</string>
|
||||
<string name="label_algorithm">Algoritme</string>
|
||||
<string name="label_asciiArmour">ASCII Rustning</string>
|
||||
<string name="label_selectPublicKeys">Offentlig(e) Nøgle(r)</string>
|
||||
<string name="label_deleteAfterEncryption">Slet Efter Kryptering</string>
|
||||
<string name="label_deleteAfterDecryption">Slet Efter Afkryptering</string>
|
||||
<string name="label_encryptionAlgorithm">Krypteringsalgoritme</string>
|
||||
<string name="label_hashAlgorithm">Hash-algoritme</string>
|
||||
<string name="label_asymmetric">Offentlig Nøgle</string>
|
||||
<string name="label_symmetric">Kodeord</string>
|
||||
<string name="label_passPhraseCacheTtl">Kodeords Cache</string>
|
||||
<string name="label_messageCompression">Besked Komprimering</string>
|
||||
<string name="label_fileCompression">Fil Komprimering</string>
|
||||
|
||||
<string name="noKeysSelected">Vælg</string>
|
||||
<string name="oneKeySelected">1 Valgt</string>
|
||||
<string name="nKeysSelected">Valgt</string>
|
||||
<string name="unknownUserId"><ukendt></string>
|
||||
<string name="none"><ingen></string>
|
||||
<string name="noKey"><ingen nøgle></string>
|
||||
<string name="noDate">-</string>
|
||||
<string name="noExpiry"><udløber ikke></string>
|
||||
<string name="unknownStatus"></string>
|
||||
<string name="canEncrypt">kan kryptere</string>
|
||||
<string name="canSign">kan signere</string>
|
||||
<string name="expired">udløbet</string>
|
||||
<string name="notValid">ugyldig</string>
|
||||
|
||||
<!-- choice_lowerCase: capitalized firwst word, no punctuation -->
|
||||
<string name="choice_none">Ingen</string>
|
||||
<string name="choice_signOnly">Kun signering</string>
|
||||
<string name="choice_encryptOnly">Kun kryptering</string>
|
||||
<string name="choice_signAndEncrypt">Signér og kryptér</string>
|
||||
<string name="choice_15secs">15 secs</string>
|
||||
<string name="choice_1min">1 min</string>
|
||||
<string name="choice_3mins">3 min</string>
|
||||
<string name="choice_5mins">5 min</string>
|
||||
<string name="choice_10mins">10 min</string>
|
||||
<string name="choice_untilQuit">Indtil slut</string>
|
||||
|
||||
<string name="dsa">DSA</string>
|
||||
<string name="elgamal">ElGamal</string>
|
||||
<string name="rsa">RSA</string>
|
||||
|
||||
<string name="filemanager_titleOpen">Åbn...</string>
|
||||
<string name="filemanager_titleSave">Gem Som...</string>
|
||||
<string name="filemanager_titleEncrypt">Vælg Fil Som Skal Krypteres...</string>
|
||||
<string name="filemanager_titleDecrypt">Vælg Fil Som Skal Afkrypteres...</string>
|
||||
<string name="filemanager_btnOpen">Åbn</string>
|
||||
<string name="filemanager_btnSave">Gem</string>
|
||||
|
||||
<string name="warning">Advarsel</string>
|
||||
<string name="error">Fejl</string>
|
||||
<string name="warningMessage">Advarsel: %s</string>
|
||||
<string name="errorMessage">Fejl: %s</string>
|
||||
|
||||
<!-- sentences -->
|
||||
<string name="wrongPassPhrase">Forkert kodeord.</string>
|
||||
<string name="usingClipboardContent">Bruger clipboardets indhold.</string>
|
||||
<string name="keySaved">Nøgle gemt.</string>
|
||||
<string name="setAPassPhrase">Sæt et kodeord via Indstillinger først.</string>
|
||||
<string name="noFilemanagerInstalled">Der er ikke installeret en kompatibel fil håndtering.</string>
|
||||
<string name="passPhrasesDoNotMatch">Kodeordet matchede ikke.</string>
|
||||
<string name="passPhraseMustNotBeEmpty">Et tomt kodeord er ikke tilladt.</string>
|
||||
<string name="passPhraseForSymmetricEncryption">Kodeord til symmetrisk kryptering:</string>
|
||||
<string name="passPhraseFor">Kodeord til %s:</string>
|
||||
<string name="fileDeleteConfirmation">Er du sikker på at du vil slette \n%s?</string>
|
||||
<string name="fileDeleteSuccessful">Filen er slettet.</string>
|
||||
<string name="noFileSelected">Vælg en fil først.</string>
|
||||
<string name="decryptionSuccessful">Afkryptering lykkedes.</string>
|
||||
<string name="encryptionSuccessful">Kryptering lykkedes.</string>
|
||||
<string name="encryptionToClipboardSuccessful">Kryptering til clipboard lykkedes.</string>
|
||||
<string name="enterPassPhraseTwice">Tast kodeordet to gange.</string>
|
||||
<string name="selectEncryptionKey">Vælg mindst én krypteringsnøgle.</string>
|
||||
<string name="selectEncryptionOrSignatureKey">Vælg mindst én krypteringsnøgle eller signaturnøgle.</string>
|
||||
<string name="specifyFileToEncryptTo">Angiv navnet på filen der skal krypteres til.\nADVARSEL! Filen vil blive overskrevet hvis den allerede eksisterer.</string>
|
||||
<string name="specifyFileToDecryptTo">Angiv navnet på filen der skal afkrypteres til.\nADVARSEL! Filen vil blive overskrevet hvis den allerede eksisterer.</string>
|
||||
<string name="specifyGoogleMailAccount">Angiv den Google Mail konto du ønsker at tilføje.</string>
|
||||
<string name="specifyFileToImportFrom">Angiv hvilken fil du ønsker at importere nøgler fra. (.asc eller .gpg)</string>
|
||||
<string name="specifyFileToExportTo">Angiv hvilken fil der skal eksporteres til.\nADVARSEL! Filen vil blive overskrevet hvis den allerede eksisterer.</string>
|
||||
<string name="specifyFileToExportSecretKeysTo">Angiv hvilken fil der skal eksporteres til.\nADVARSEL! Du er ved at eksportere PRIVATE nøgler.\nADVARSEL! Filen vil blive overskrevet hvis den allerede eksisterer.</string>
|
||||
<string name="keyDeletionConfirmation">Ønsker du at slette \'%s\'-nøglen?\nDu kan ikke fortryde denne handling!</string>
|
||||
<string name="secretKeyDeletionConfirmation">Ønsker du at slette den PRIVATE nøgle, \'%s\'?\nDu kan ikke fortryde denne handling!</string>
|
||||
<string name="keysAddedAndUpdated">Tilføjelse af %s nøgle(r) og opdatering af %s nøgle(r) lykkedes."</string>
|
||||
<string name="keysAdded">Tilføjelse af %s nøgle(r) lykkedes.</string>
|
||||
<string name="keysUpdated">Opdatring af %s nøgle(r) lykkedes.</string>
|
||||
<string name="noKeysAddedOrUpdated">Ingen nøgler blev tilføjet eller opdateret.</string>
|
||||
<string name="keyExported">Eksport af 1 nøgle lykkedes.</string>
|
||||
<string name="keysExported">Eksport af %s nøgler lykkedes.</string>
|
||||
<string name="noKeysExported">Ingen nøgler blev eksporteret.</string>
|
||||
<string name="keyCreationElGamalInfo">NB: Kun undernøgler understøtter ElGamal, og for ELGamal vil den nærmeste nøglestørrelse - 1536, 2048, 3072, 4096, eller 8192 - blive brugt.</string>
|
||||
<string name="keyNotFound">Kunne ikke finde %08X nøglen.</string>
|
||||
|
||||
<!-- error_lowerCase: phrases, no punctuation, all lowercase,
|
||||
they will be put after "errorMessage", e.g. "Error: file not found" -->
|
||||
<string name="error_fileDeleteFailed">\'%s\' kunne ikke slettes</string>
|
||||
<string name="error_fileNotFound">filen findes ikke</string>
|
||||
<string name="error_noSecretKeyFound">ingen egnet privat nøgle fundet</string>
|
||||
<string name="error_noKnownEncryptionFound">ingen kendt krypterings måde fundet</string>
|
||||
<string name="error_externalStorageNotReady">ekstern storage er ikke parat</string>
|
||||
<string name="error_accountNotFound">\'%s\'-kontoen blev ikke fundet</string>
|
||||
<string name="error_addingAccountFailed">\'%s\'-kontoen kunne ikke tilføjes</string>
|
||||
<string name="error_invalidEmail">ugyldig email \'%s\'</string>
|
||||
<string name="error_keySizeMinimum512bit">nøgle størrelsen skal være på mindst 512bit</string>
|
||||
<string name="error_masterKeyMustNotBeElGamal">hoved nøglen kan ikke være en ElGamal nøgle</string>
|
||||
<string name="error_unknownAlgorithmChoice">ukendt algoritme valg</string>
|
||||
<string name="error_userIdNeedsAName">angiv et navn</string>
|
||||
<string name="error_userIdNeedsAnEmailAddress">angiv en email adresse</string>
|
||||
<string name="error_keyNeedsAUserId">der skal bruges mindst ét bruger-id</string>
|
||||
<string name="error_mainUserIdMustNotBeEmpty">hovedbruger-id kan ikke være tomt</string>
|
||||
<string name="error_keyNeedsMasterKey">der skal mindst bruges en hovednøgle</string>
|
||||
<string name="error_expiryMustComeAfterCreation">udløbsdatoen skal være senere end oprettelsesdatoen</string>
|
||||
<string name="error_noEncryptionKeysOrPassPhrase">hverken krypteringsnøgler eller kodeord modtaget</string>
|
||||
<string name="error_signatureFailed">signering mislykkedes</string>
|
||||
<string name="error_noSignaturePassPhrase">intet kodeord modtaget</string>
|
||||
<string name="error_noSignatureKey">ingen signatur nøgle modtaget</string>
|
||||
<string name="error_invalidData">ikke gyldig krypteringsdata</string>
|
||||
<string name="error_corruptData">beskadiget data</string>
|
||||
<string name="error_noSymmetricEncryptionPacket">kunne ikke finde en pakke med symmetrisk kryptering</string>
|
||||
<string name="error_wrongPassPhrase">forkert kodeord</string>
|
||||
<string name="error_savingKeys">der opstod en fejl da nøglen eller nøglerne skulle gemmes</string>
|
||||
|
||||
<!-- progress_lowerCase: lowercase, phrases, usually ending in '...' -->
|
||||
<string name="progress_done">færdig.</string>
|
||||
<string name="progress_initializing">starter op...</string>
|
||||
<string name="progress_saving">gemmer...</string>
|
||||
<string name="progress_importing">importerer...</string>
|
||||
<string name="progress_exporting">eksporterer...</string>
|
||||
<string name="progress_generating">genererer nøgle, dette kan tage et stykke tid...</string>
|
||||
<string name="progress_buildingKey">opbygger nøgle...</string>
|
||||
<string name="progress_preparingMasterKey">forbereder hovednøgle...</string>
|
||||
<string name="progress_certifyingMasterKey">bekræfter hovednøgle...</string>
|
||||
<string name="progress_buildingMasterKeyRing">bygger hovednøglering...</string>
|
||||
<string name="progress_addingSubKeys">tilføjer undernøgler...</string>
|
||||
<string name="progress_savingKeyRing">gemmer nøglering...</string>
|
||||
<string name="progress_importingSecretKeys">importerer private nøgler...</string>
|
||||
<string name="progress_importingPublicKeys">importerer offentlige nøgler...</string>
|
||||
<string name="progress_reloadingKeys">genloader nøgler...</string>
|
||||
<string name="progress_exportingKey">eksporterer nøgle...</string>
|
||||
<string name="progress_exportingKeys">eksporterer nøgler...</string>
|
||||
<string name="progress_extractingSignatureKey">henter signatur nøgle...</string>
|
||||
<string name="progress_extractingKey">henter nøgle...</string>
|
||||
<string name="progress_preparingStreams">forbereder streams...</string>
|
||||
<string name="progress_encrypting">krypterer data...</string>
|
||||
<string name="progress_decrypting">afkrypterer data...</string>
|
||||
<string name="progress_preparingSignature">forbereder signatur...</string>
|
||||
<string name="progress_generatingSignature">skaber signatur...</string>
|
||||
<string name="progress_processingSignature">behandler signatur...</string>
|
||||
<string name="progress_verifyingSignature">bekræfter signatur...</string>
|
||||
<string name="progress_signing">signerer...</string>
|
||||
<string name="progress_readingData">læser data...</string>
|
||||
<string name="progress_findingKey">søger nøgle...</string>
|
||||
<string name="progress_decompressingData">afkomprimerer data...</string>
|
||||
<string name="progress_verifyingIntegrity">bekræfter integritet...</string>
|
||||
|
||||
<!-- permission strings -->
|
||||
<string name="permission_read_key_details_label">Læs nøgle detaljer fra APG.</string>
|
||||
<string name="permission_read_key_details_description">Læs om offentlige og private nøgler gemt i APG, f. eks. nøgle ID og bruger ID. Selve nøglerne kan IKKE læses.</string>
|
||||
|
||||
<!-- action strings -->
|
||||
<string name="action_encrypt">Kryptér</string>
|
||||
<string name="action_decrypt">Afkryptér</string>
|
||||
<string name="action_importPublic">Importér Offentlige Nøgler</string>
|
||||
<string name="action_importSecret">Importér Private Nøgler</string>
|
||||
|
||||
<string name="hint_publicKeys">Søg I Offentlige Nøgler</string>
|
||||
<string name="hint_secretKeys">Søg I Private Nøgler</string>
|
||||
<string name="filterInfo">Filter: \"%s\"</string>
|
||||
|
||||
</resources>
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<string name="app_name">APG</string>
|
||||
|
||||
<!-- title_lowerCase: capitalized words, no punctuation -->
|
||||
<string name="title_mailInbox">Mail Inbox</string>
|
||||
<string name="title_managePublicKeys">Administrér Offentlige Nøgler</string>
|
||||
<string name="title_manageSecretKeys">Administrér Private Nøgler</string>
|
||||
<string name="title_selectRecipients">Vælg Modtagere</string>
|
||||
<string name="title_selectSignature">Vælg Signatur</string>
|
||||
<string name="title_encrypt">Kryptér</string>
|
||||
<string name="title_decrypt">Afkryptér</string>
|
||||
<string name="title_authentification">Autentificering</string>
|
||||
<string name="title_createKey">Opret Nøgle</string>
|
||||
<string name="title_editKey">Redigér Nøgle</string>
|
||||
<string name="title_preferences">Indstillinger</string>
|
||||
<string name="title_changePassPhrase">Skift Kodeord</string>
|
||||
<string name="title_setPassPhrase">Sæt Kodeord</string>
|
||||
<string name="title_sendEmail">"Send Mail..."</string>
|
||||
<string name="title_encryptToFile">Kryptér Til Fil</string>
|
||||
<string name="title_decryptToFile">Afkryptér Til Fil</string>
|
||||
<string name="title_addAccount">Tilføj Konto</string>
|
||||
<string name="title_importKeys">Importér Nøgle</string>
|
||||
<string name="title_exportKey">Eksportér Nøgle</string>
|
||||
<string name="title_exportKeys">Eksportér Nøgler</string>
|
||||
<string name="title_keyNotFound">Ingen Nøgle Matchede</string>
|
||||
|
||||
<!-- section_lowerCase: capitalized words, no punctuation -->
|
||||
<string name="section_userIds">Bruger ID</string>
|
||||
<string name="section_keys">Nøgler</string>
|
||||
<string name="section_general">Generelt</string>
|
||||
<string name="section_defaults">Standard Indstillinger</string>
|
||||
|
||||
<!-- btn_lowerCase: capitalized words, no punctuation -->
|
||||
<string name="btn_encryptToClipboard">Kryptér Til Clipboard</string>
|
||||
<string name="btn_send">Kryptér Og Mail</string>
|
||||
<string name="btn_encrypt">Kryptér</string>
|
||||
<string name="btn_decrypt">Afkryptér</string>
|
||||
<string name="btn_verify">Bekræft</string>
|
||||
<string name="btn_selectEncryptKeys">Vælg Modtagere</string>
|
||||
<string name="btn_reply">Svar</string>
|
||||
<string name="btn_encryptMessage">Kryptér Besked</string>
|
||||
<string name="btn_decryptMessage">Afkryptér Besked</string>
|
||||
<string name="btn_encryptFile">Kryptér Fil</string>
|
||||
<string name="btn_decryptFile">Afkryptér Fil</string>
|
||||
<string name="btn_save">Gem</string>
|
||||
<string name="btn_doNotSave">Fortryd</string>
|
||||
<string name="btn_delete">Slet</string>
|
||||
<string name="btn_noDate">Ingen</string>
|
||||
<string name="btn_clearFilter">Ryd Filter</string>
|
||||
|
||||
<!-- menu_lowerCase: capitalized words, no punctuation -->
|
||||
<string name="menu_about">Om APG</string>
|
||||
<string name="menu_addAccount">Tilføj GMail Konto</string>
|
||||
<string name="menu_deleteAccount">Slet Konto</string>
|
||||
<string name="menu_managePublicKeys">Administrér Offentlige Nøgler</string>
|
||||
<string name="menu_manageSecretKeys">Administrér Private Nøgler</string>
|
||||
<string name="menu_preferences">Indstillinger</string>
|
||||
<string name="menu_changePassPhrase">Skift Kodeord</string>
|
||||
<string name="menu_setPassPhrase">Sæt Kodeord</string>
|
||||
<string name="menu_importKeys">Importér Nøgler</string>
|
||||
<string name="menu_exportKeys">Eksportér Nøgler</string>
|
||||
<string name="menu_exportKey">Eksportér Nøgle</string>
|
||||
<string name="menu_deleteKey">Slet Nøgle</string>
|
||||
<string name="menu_createKey">Opret Nøgle</string>
|
||||
<string name="menu_editKey">Redigér Nøgle</string>
|
||||
<string name="menu_search">Søg</string>
|
||||
|
||||
<!-- label_lowerCase: capitalized words, no punctuation -->
|
||||
<string name="label_sign">Signér</string>
|
||||
<string name="label_message">Besked</string>
|
||||
<string name="label_file">Fil</string>
|
||||
<string name="label_passPhrase">Kodeord</string>
|
||||
<string name="label_passPhraseAgain">Igen</string>
|
||||
<string name="label_algorithm">Algoritme</string>
|
||||
<string name="label_asciiArmour">ASCII Rustning</string>
|
||||
<string name="label_selectPublicKeys">Offentlig(e) Nøgle(r)</string>
|
||||
<string name="label_deleteAfterEncryption">Slet Efter Kryptering</string>
|
||||
<string name="label_deleteAfterDecryption">Slet Efter Afkryptering</string>
|
||||
<string name="label_encryptionAlgorithm">Krypteringsalgoritme</string>
|
||||
<string name="label_hashAlgorithm">Hash-algoritme</string>
|
||||
<string name="label_asymmetric">Offentlig Nøgle</string>
|
||||
<string name="label_symmetric">Kodeord</string>
|
||||
<string name="label_passPhraseCacheTtl">Kodeords Cache</string>
|
||||
<string name="label_messageCompression">Besked Komprimering</string>
|
||||
<string name="label_fileCompression">Fil Komprimering</string>
|
||||
|
||||
<string name="noKeysSelected">Vælg</string>
|
||||
<string name="oneKeySelected">1 Valgt</string>
|
||||
<string name="nKeysSelected">Valgt</string>
|
||||
<string name="unknownUserId"><ukendt></string>
|
||||
<string name="none"><ingen></string>
|
||||
<string name="noKey"><ingen nøgle></string>
|
||||
<string name="noDate">-</string>
|
||||
<string name="noExpiry"><udløber ikke></string>
|
||||
<string name="unknownStatus"></string>
|
||||
<string name="canEncrypt">kan kryptere</string>
|
||||
<string name="canSign">kan signere</string>
|
||||
<string name="expired">udløbet</string>
|
||||
<string name="notValid">ugyldig</string>
|
||||
|
||||
<!-- choice_lowerCase: capitalized firwst word, no punctuation -->
|
||||
<string name="choice_none">Ingen</string>
|
||||
<string name="choice_signOnly">Kun signering</string>
|
||||
<string name="choice_encryptOnly">Kun kryptering</string>
|
||||
<string name="choice_signAndEncrypt">Signér og kryptér</string>
|
||||
<string name="choice_15secs">15 secs</string>
|
||||
<string name="choice_1min">1 min</string>
|
||||
<string name="choice_3mins">3 min</string>
|
||||
<string name="choice_5mins">5 min</string>
|
||||
<string name="choice_10mins">10 min</string>
|
||||
<string name="choice_untilQuit">Indtil slut</string>
|
||||
|
||||
<string name="dsa">DSA</string>
|
||||
<string name="elgamal">ElGamal</string>
|
||||
<string name="rsa">RSA</string>
|
||||
|
||||
<string name="filemanager_titleOpen">Åbn...</string>
|
||||
<string name="filemanager_titleSave">Gem Som...</string>
|
||||
<string name="filemanager_titleEncrypt">Vælg Fil Som Skal Krypteres...</string>
|
||||
<string name="filemanager_titleDecrypt">Vælg Fil Som Skal Afkrypteres...</string>
|
||||
<string name="filemanager_btnOpen">Åbn</string>
|
||||
<string name="filemanager_btnSave">Gem</string>
|
||||
|
||||
<string name="warning">Advarsel</string>
|
||||
<string name="error">Fejl</string>
|
||||
<string name="warningMessage">Advarsel: %s</string>
|
||||
<string name="errorMessage">Fejl: %s</string>
|
||||
|
||||
<!-- sentences -->
|
||||
<string name="wrongPassPhrase">Forkert kodeord.</string>
|
||||
<string name="usingClipboardContent">Bruger clipboardets indhold.</string>
|
||||
<string name="keySaved">Nøgle gemt.</string>
|
||||
<string name="setAPassPhrase">Sæt et kodeord via Indstillinger først.</string>
|
||||
<string name="noFilemanagerInstalled">Der er ikke installeret en kompatibel fil håndtering.</string>
|
||||
<string name="passPhrasesDoNotMatch">Kodeordet matchede ikke.</string>
|
||||
<string name="passPhraseMustNotBeEmpty">Et tomt kodeord er ikke tilladt.</string>
|
||||
<string name="passPhraseForSymmetricEncryption">Kodeord til symmetrisk kryptering:</string>
|
||||
<string name="passPhraseFor">Kodeord til %s:</string>
|
||||
<string name="fileDeleteConfirmation">Er du sikker på at du vil slette \n%s?</string>
|
||||
<string name="fileDeleteSuccessful">Filen er slettet.</string>
|
||||
<string name="noFileSelected">Vælg en fil først.</string>
|
||||
<string name="decryptionSuccessful">Afkryptering lykkedes.</string>
|
||||
<string name="encryptionSuccessful">Kryptering lykkedes.</string>
|
||||
<string name="encryptionToClipboardSuccessful">Kryptering til clipboard lykkedes.</string>
|
||||
<string name="enterPassPhraseTwice">Tast kodeordet to gange.</string>
|
||||
<string name="selectEncryptionKey">Vælg mindst én krypteringsnøgle.</string>
|
||||
<string name="selectEncryptionOrSignatureKey">Vælg mindst én krypteringsnøgle eller signaturnøgle.</string>
|
||||
<string name="specifyFileToEncryptTo">Angiv navnet på filen der skal krypteres til.\nADVARSEL! Filen vil blive overskrevet hvis den allerede eksisterer.</string>
|
||||
<string name="specifyFileToDecryptTo">Angiv navnet på filen der skal afkrypteres til.\nADVARSEL! Filen vil blive overskrevet hvis den allerede eksisterer.</string>
|
||||
<string name="specifyGoogleMailAccount">Angiv den Google Mail konto du ønsker at tilføje.</string>
|
||||
<string name="specifyFileToImportFrom">Angiv hvilken fil du ønsker at importere nøgler fra. (.asc eller .gpg)</string>
|
||||
<string name="specifyFileToExportTo">Angiv hvilken fil der skal eksporteres til.\nADVARSEL! Filen vil blive overskrevet hvis den allerede eksisterer.</string>
|
||||
<string name="specifyFileToExportSecretKeysTo">Angiv hvilken fil der skal eksporteres til.\nADVARSEL! Du er ved at eksportere PRIVATE nøgler.\nADVARSEL! Filen vil blive overskrevet hvis den allerede eksisterer.</string>
|
||||
<string name="keyDeletionConfirmation">Ønsker du at slette \'%s\'-nøglen?\nDu kan ikke fortryde denne handling!</string>
|
||||
<string name="secretKeyDeletionConfirmation">Ønsker du at slette den PRIVATE nøgle, \'%s\'?\nDu kan ikke fortryde denne handling!</string>
|
||||
<string name="keysAddedAndUpdated">Tilføjelse af %s nøgle(r) og opdatering af %s nøgle(r) lykkedes."</string>
|
||||
<string name="keysAdded">Tilføjelse af %s nøgle(r) lykkedes.</string>
|
||||
<string name="keysUpdated">Opdatring af %s nøgle(r) lykkedes.</string>
|
||||
<string name="noKeysAddedOrUpdated">Ingen nøgler blev tilføjet eller opdateret.</string>
|
||||
<string name="keyExported">Eksport af 1 nøgle lykkedes.</string>
|
||||
<string name="keysExported">Eksport af %s nøgler lykkedes.</string>
|
||||
<string name="noKeysExported">Ingen nøgler blev eksporteret.</string>
|
||||
<string name="keyCreationElGamalInfo">NB: Kun undernøgler understøtter ElGamal, og for ELGamal vil den nærmeste nøglestørrelse - 1536, 2048, 3072, 4096, eller 8192 - blive brugt.</string>
|
||||
<string name="keyNotFound">Kunne ikke finde %08X nøglen.</string>
|
||||
|
||||
<!-- error_lowerCase: phrases, no punctuation, all lowercase,
|
||||
they will be put after "errorMessage", e.g. "Error: file not found" -->
|
||||
<string name="error_fileDeleteFailed">\'%s\' kunne ikke slettes</string>
|
||||
<string name="error_fileNotFound">filen findes ikke</string>
|
||||
<string name="error_noSecretKeyFound">ingen egnet privat nøgle fundet</string>
|
||||
<string name="error_noKnownEncryptionFound">ingen kendt krypterings måde fundet</string>
|
||||
<string name="error_externalStorageNotReady">ekstern storage er ikke parat</string>
|
||||
<string name="error_accountNotFound">\'%s\'-kontoen blev ikke fundet</string>
|
||||
<string name="error_addingAccountFailed">\'%s\'-kontoen kunne ikke tilføjes</string>
|
||||
<string name="error_invalidEmail">ugyldig email \'%s\'</string>
|
||||
<string name="error_keySizeMinimum512bit">nøgle størrelsen skal være på mindst 512bit</string>
|
||||
<string name="error_masterKeyMustNotBeElGamal">hoved nøglen kan ikke være en ElGamal nøgle</string>
|
||||
<string name="error_unknownAlgorithmChoice">ukendt algoritme valg</string>
|
||||
<string name="error_userIdNeedsAName">angiv et navn</string>
|
||||
<string name="error_userIdNeedsAnEmailAddress">angiv en email adresse</string>
|
||||
<string name="error_keyNeedsAUserId">der skal bruges mindst ét bruger-id</string>
|
||||
<string name="error_mainUserIdMustNotBeEmpty">hovedbruger-id kan ikke være tomt</string>
|
||||
<string name="error_keyNeedsMasterKey">der skal mindst bruges en hovednøgle</string>
|
||||
<string name="error_expiryMustComeAfterCreation">udløbsdatoen skal være senere end oprettelsesdatoen</string>
|
||||
<string name="error_noEncryptionKeysOrPassPhrase">hverken krypteringsnøgler eller kodeord modtaget</string>
|
||||
<string name="error_signatureFailed">signering mislykkedes</string>
|
||||
<string name="error_noSignaturePassPhrase">intet kodeord modtaget</string>
|
||||
<string name="error_noSignatureKey">ingen signatur nøgle modtaget</string>
|
||||
<string name="error_invalidData">ikke gyldig krypteringsdata</string>
|
||||
<string name="error_corruptData">beskadiget data</string>
|
||||
<string name="error_noSymmetricEncryptionPacket">kunne ikke finde en pakke med symmetrisk kryptering</string>
|
||||
<string name="error_wrongPassPhrase">forkert kodeord</string>
|
||||
<string name="error_savingKeys">der opstod en fejl da nøglen eller nøglerne skulle gemmes</string>
|
||||
|
||||
<!-- progress_lowerCase: lowercase, phrases, usually ending in '...' -->
|
||||
<string name="progress_done">færdig.</string>
|
||||
<string name="progress_initializing">starter op...</string>
|
||||
<string name="progress_saving">gemmer...</string>
|
||||
<string name="progress_importing">importerer...</string>
|
||||
<string name="progress_exporting">eksporterer...</string>
|
||||
<string name="progress_generating">genererer nøgle, dette kan tage et stykke tid...</string>
|
||||
<string name="progress_buildingKey">opbygger nøgle...</string>
|
||||
<string name="progress_preparingMasterKey">forbereder hovednøgle...</string>
|
||||
<string name="progress_certifyingMasterKey">bekræfter hovednøgle...</string>
|
||||
<string name="progress_buildingMasterKeyRing">bygger hovednøglering...</string>
|
||||
<string name="progress_addingSubKeys">tilføjer undernøgler...</string>
|
||||
<string name="progress_savingKeyRing">gemmer nøglering...</string>
|
||||
<string name="progress_importingSecretKeys">importerer private nøgler...</string>
|
||||
<string name="progress_importingPublicKeys">importerer offentlige nøgler...</string>
|
||||
<string name="progress_reloadingKeys">genloader nøgler...</string>
|
||||
<string name="progress_exportingKey">eksporterer nøgle...</string>
|
||||
<string name="progress_exportingKeys">eksporterer nøgler...</string>
|
||||
<string name="progress_extractingSignatureKey">henter signatur nøgle...</string>
|
||||
<string name="progress_extractingKey">henter nøgle...</string>
|
||||
<string name="progress_preparingStreams">forbereder streams...</string>
|
||||
<string name="progress_encrypting">krypterer data...</string>
|
||||
<string name="progress_decrypting">afkrypterer data...</string>
|
||||
<string name="progress_preparingSignature">forbereder signatur...</string>
|
||||
<string name="progress_generatingSignature">skaber signatur...</string>
|
||||
<string name="progress_processingSignature">behandler signatur...</string>
|
||||
<string name="progress_verifyingSignature">bekræfter signatur...</string>
|
||||
<string name="progress_signing">signerer...</string>
|
||||
<string name="progress_readingData">læser data...</string>
|
||||
<string name="progress_findingKey">søger nøgle...</string>
|
||||
<string name="progress_decompressingData">afkomprimerer data...</string>
|
||||
<string name="progress_verifyingIntegrity">bekræfter integritet...</string>
|
||||
|
||||
<!-- permission strings -->
|
||||
<string name="permission_read_key_details_label">Læs nøgle detaljer fra APG.</string>
|
||||
<string name="permission_read_key_details_description">Læs om offentlige og private nøgler gemt i APG, f. eks. nøgle ID og bruger ID. Selve nøglerne kan IKKE læses.</string>
|
||||
|
||||
<!-- action strings -->
|
||||
<string name="action_encrypt">Kryptér</string>
|
||||
<string name="action_decrypt">Afkryptér</string>
|
||||
<string name="action_importPublic">Importér Offentlige Nøgler</string>
|
||||
<string name="action_importSecret">Importér Private Nøgler</string>
|
||||
|
||||
<string name="hint_publicKeys">Søg I Offentlige Nøgler</string>
|
||||
<string name="hint_secretKeys">Søg I Private Nøgler</string>
|
||||
<string name="filterInfo">Filter: \"%s\"</string>
|
||||
|
||||
</resources>
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,112 +1,112 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.thialfihar.android.apg;
|
||||
|
||||
import org.bouncycastle2.jce.provider.BouncyCastleProvider;
|
||||
import org.bouncycastle2.openpgp.PGPException;
|
||||
import org.bouncycastle2.openpgp.PGPSecretKey;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.DialogInterface.OnClickListener;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.EditText;
|
||||
import android.widget.Toast;
|
||||
|
||||
public class AskForSecretKeyPassPhrase {
|
||||
public static interface PassPhraseCallbackInterface {
|
||||
void passPhraseCallback(long keyId, String passPhrase);
|
||||
}
|
||||
|
||||
public static Dialog createDialog(Activity context, long secretKeyId,
|
||||
PassPhraseCallbackInterface callback) {
|
||||
AlertDialog.Builder alert = new AlertDialog.Builder(context);
|
||||
|
||||
alert.setTitle(R.string.title_authentification);
|
||||
|
||||
final PGPSecretKey secretKey;
|
||||
final Activity activity = context;
|
||||
|
||||
if (secretKeyId == Id.key.symmetric || secretKeyId == Id.key.none) {
|
||||
secretKey = null;
|
||||
alert.setMessage(context.getString(R.string.passPhraseForSymmetricEncryption));
|
||||
} else {
|
||||
secretKey = Apg.getMasterKey(Apg.getSecretKeyRing(secretKeyId));
|
||||
if (secretKey == null) {
|
||||
alert.setTitle(R.string.title_keyNotFound);
|
||||
alert.setMessage(context.getString(R.string.keyNotFound, secretKeyId));
|
||||
alert.setPositiveButton(android.R.string.ok, new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
activity.removeDialog(Id.dialog.pass_phrase);
|
||||
}
|
||||
});
|
||||
alert.setCancelable(false);
|
||||
return alert.create();
|
||||
}
|
||||
String userId = Apg.getMainUserIdSafe(context, secretKey);
|
||||
alert.setMessage(context.getString(R.string.passPhraseFor, userId));
|
||||
}
|
||||
|
||||
LayoutInflater inflater =
|
||||
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
View view = inflater.inflate(R.layout.pass_phrase, null);
|
||||
final EditText input = (EditText) view.findViewById(R.id.passPhrase);
|
||||
final EditText inputNotUsed = (EditText) view.findViewById(R.id.passPhraseAgain);
|
||||
inputNotUsed.setVisibility(View.GONE);
|
||||
|
||||
alert.setView(view);
|
||||
|
||||
final PassPhraseCallbackInterface cb = callback;
|
||||
alert.setPositiveButton(android.R.string.ok,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
activity.removeDialog(Id.dialog.pass_phrase);
|
||||
String passPhrase = "" + input.getText();
|
||||
long keyId;
|
||||
if (secretKey != null) {
|
||||
try {
|
||||
secretKey.extractPrivateKey(passPhrase.toCharArray(),
|
||||
new BouncyCastleProvider());
|
||||
} catch (PGPException e) {
|
||||
Toast.makeText(activity,
|
||||
R.string.wrongPassPhrase,
|
||||
Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
keyId = secretKey.getKeyID();
|
||||
} else {
|
||||
keyId = Id.key.symmetric;
|
||||
}
|
||||
cb.passPhraseCallback(keyId, passPhrase);
|
||||
}
|
||||
});
|
||||
|
||||
alert.setNegativeButton(android.R.string.cancel,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
activity.removeDialog(Id.dialog.pass_phrase);
|
||||
}
|
||||
});
|
||||
|
||||
return alert.create();
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.thialfihar.android.apg;
|
||||
|
||||
import org.bouncycastle2.jce.provider.BouncyCastleProvider;
|
||||
import org.bouncycastle2.openpgp.PGPException;
|
||||
import org.bouncycastle2.openpgp.PGPSecretKey;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.DialogInterface.OnClickListener;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.EditText;
|
||||
import android.widget.Toast;
|
||||
|
||||
public class AskForSecretKeyPassPhrase {
|
||||
public static interface PassPhraseCallbackInterface {
|
||||
void passPhraseCallback(long keyId, String passPhrase);
|
||||
}
|
||||
|
||||
public static Dialog createDialog(Activity context, long secretKeyId,
|
||||
PassPhraseCallbackInterface callback) {
|
||||
AlertDialog.Builder alert = new AlertDialog.Builder(context);
|
||||
|
||||
alert.setTitle(R.string.title_authentification);
|
||||
|
||||
final PGPSecretKey secretKey;
|
||||
final Activity activity = context;
|
||||
|
||||
if (secretKeyId == Id.key.symmetric || secretKeyId == Id.key.none) {
|
||||
secretKey = null;
|
||||
alert.setMessage(context.getString(R.string.passPhraseForSymmetricEncryption));
|
||||
} else {
|
||||
secretKey = Apg.getMasterKey(Apg.getSecretKeyRing(secretKeyId));
|
||||
if (secretKey == null) {
|
||||
alert.setTitle(R.string.title_keyNotFound);
|
||||
alert.setMessage(context.getString(R.string.keyNotFound, secretKeyId));
|
||||
alert.setPositiveButton(android.R.string.ok, new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
activity.removeDialog(Id.dialog.pass_phrase);
|
||||
}
|
||||
});
|
||||
alert.setCancelable(false);
|
||||
return alert.create();
|
||||
}
|
||||
String userId = Apg.getMainUserIdSafe(context, secretKey);
|
||||
alert.setMessage(context.getString(R.string.passPhraseFor, userId));
|
||||
}
|
||||
|
||||
LayoutInflater inflater =
|
||||
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
View view = inflater.inflate(R.layout.pass_phrase, null);
|
||||
final EditText input = (EditText) view.findViewById(R.id.passPhrase);
|
||||
final EditText inputNotUsed = (EditText) view.findViewById(R.id.passPhraseAgain);
|
||||
inputNotUsed.setVisibility(View.GONE);
|
||||
|
||||
alert.setView(view);
|
||||
|
||||
final PassPhraseCallbackInterface cb = callback;
|
||||
alert.setPositiveButton(android.R.string.ok,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
activity.removeDialog(Id.dialog.pass_phrase);
|
||||
String passPhrase = "" + input.getText();
|
||||
long keyId;
|
||||
if (secretKey != null) {
|
||||
try {
|
||||
secretKey.extractPrivateKey(passPhrase.toCharArray(),
|
||||
new BouncyCastleProvider());
|
||||
} catch (PGPException e) {
|
||||
Toast.makeText(activity,
|
||||
R.string.wrongPassPhrase,
|
||||
Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
keyId = secretKey.getKeyID();
|
||||
} else {
|
||||
keyId = Id.key.symmetric;
|
||||
}
|
||||
cb.passPhraseCallback(keyId, passPhrase);
|
||||
}
|
||||
});
|
||||
|
||||
alert.setNegativeButton(android.R.string.cancel,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
activity.removeDialog(Id.dialog.pass_phrase);
|
||||
}
|
||||
});
|
||||
|
||||
return alert.create();
|
||||
}
|
||||
}
|
||||
|
@ -1,381 +1,381 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.thialfihar.android.apg;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
public class BaseActivity extends Activity
|
||||
implements Runnable, ProgressDialogUpdater,
|
||||
AskForSecretKeyPassPhrase.PassPhraseCallbackInterface {
|
||||
|
||||
private ProgressDialog mProgressDialog = null;
|
||||
private Thread mRunningThread = null;
|
||||
|
||||
private long mSecretKeyId = 0;
|
||||
private String mDeleteFile = null;
|
||||
|
||||
protected Preferences mPreferences;
|
||||
|
||||
private Handler mHandler = new Handler() {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
handlerCallback(msg);
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
mPreferences = Preferences.getPreferences(this);
|
||||
|
||||
Apg.initialize(this);
|
||||
|
||||
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
||||
File dir = new File(Constants.path.app_dir);
|
||||
if (!dir.exists() && !dir.mkdirs()) {
|
||||
// ignore this for now, it's not crucial
|
||||
// that the directory doesn't exist at this point
|
||||
}
|
||||
}
|
||||
|
||||
startCacheService(this, mPreferences);
|
||||
}
|
||||
|
||||
public static void startCacheService(Activity activity, Preferences preferences) {
|
||||
Intent intent = new Intent(activity, Service.class);
|
||||
intent.putExtra(Service.EXTRA_TTL, preferences.getPassPhraseCacheTtl());
|
||||
activity.startService(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
menu.add(0, Id.menu.option.preferences, 0, R.string.menu_preferences)
|
||||
.setIcon(android.R.drawable.ic_menu_preferences);
|
||||
menu.add(0, Id.menu.option.about, 1, R.string.menu_about)
|
||||
.setIcon(android.R.drawable.ic_menu_info_details);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case Id.menu.option.about: {
|
||||
showDialog(Id.dialog.about);
|
||||
return true;
|
||||
}
|
||||
|
||||
case Id.menu.option.preferences: {
|
||||
startActivity(new Intent(this, PreferencesActivity.class));
|
||||
return true;
|
||||
}
|
||||
|
||||
case Id.menu.option.search: {
|
||||
startSearch("", false, null, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Dialog onCreateDialog(int id) {
|
||||
// in case it is a progress dialog
|
||||
mProgressDialog = new ProgressDialog(this);
|
||||
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
|
||||
mProgressDialog.setCancelable(false);
|
||||
switch (id) {
|
||||
case Id.dialog.encrypting: {
|
||||
mProgressDialog.setMessage(this.getString(R.string.progress_initializing));
|
||||
return mProgressDialog;
|
||||
}
|
||||
|
||||
case Id.dialog.decrypting: {
|
||||
mProgressDialog.setMessage(this.getString(R.string.progress_initializing));
|
||||
return mProgressDialog;
|
||||
}
|
||||
|
||||
case Id.dialog.saving: {
|
||||
mProgressDialog.setMessage(this.getString(R.string.progress_saving));
|
||||
return mProgressDialog;
|
||||
}
|
||||
|
||||
case Id.dialog.importing: {
|
||||
mProgressDialog.setMessage(this.getString(R.string.progress_importing));
|
||||
return mProgressDialog;
|
||||
}
|
||||
|
||||
case Id.dialog.exporting: {
|
||||
mProgressDialog.setMessage(this.getString(R.string.progress_exporting));
|
||||
return mProgressDialog;
|
||||
}
|
||||
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
mProgressDialog = null;
|
||||
|
||||
switch (id) {
|
||||
case Id.dialog.about: {
|
||||
AlertDialog.Builder alert = new AlertDialog.Builder(this);
|
||||
|
||||
alert.setTitle("About " + Apg.getFullVersion(this));
|
||||
|
||||
LayoutInflater inflater =
|
||||
(LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
View layout = inflater.inflate(R.layout.info, null);
|
||||
TextView message = (TextView) layout.findViewById(R.id.message);
|
||||
message.setText("This is an attempt to bring OpenPGP to Android. " +
|
||||
"It is far from complete, but more features are planned (see website).\n\n" +
|
||||
"Feel free to send bug reports, suggestions, feature requests, feedback, " +
|
||||
"photographs.\n\n" +
|
||||
"mail: thi@thialfihar.org\n" +
|
||||
"site: http://apg.thialfihar.org\n\n" +
|
||||
"This software is provided \"as is\", without warranty of any kind.");
|
||||
alert.setView(layout);
|
||||
|
||||
alert.setPositiveButton(android.R.string.ok,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
BaseActivity.this.removeDialog(Id.dialog.about);
|
||||
}
|
||||
});
|
||||
|
||||
return alert.create();
|
||||
}
|
||||
|
||||
case Id.dialog.pass_phrase: {
|
||||
return AskForSecretKeyPassPhrase.createDialog(this, getSecretKeyId(), this);
|
||||
}
|
||||
|
||||
case Id.dialog.pass_phrases_do_not_match: {
|
||||
AlertDialog.Builder alert = new AlertDialog.Builder(this);
|
||||
|
||||
alert.setIcon(android.R.drawable.ic_dialog_alert);
|
||||
alert.setTitle(R.string.error);
|
||||
alert.setMessage(R.string.passPhrasesDoNotMatch);
|
||||
|
||||
alert.setPositiveButton(android.R.string.ok,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
removeDialog(Id.dialog.pass_phrases_do_not_match);
|
||||
}
|
||||
});
|
||||
alert.setCancelable(false);
|
||||
|
||||
return alert.create();
|
||||
}
|
||||
|
||||
case Id.dialog.no_pass_phrase: {
|
||||
AlertDialog.Builder alert = new AlertDialog.Builder(this);
|
||||
|
||||
alert.setIcon(android.R.drawable.ic_dialog_alert);
|
||||
alert.setTitle(R.string.error);
|
||||
alert.setMessage(R.string.passPhraseMustNotBeEmpty);
|
||||
|
||||
alert.setPositiveButton(android.R.string.ok,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
removeDialog(Id.dialog.no_pass_phrase);
|
||||
}
|
||||
});
|
||||
alert.setCancelable(false);
|
||||
|
||||
return alert.create();
|
||||
}
|
||||
|
||||
case Id.dialog.delete_file: {
|
||||
AlertDialog.Builder alert = new AlertDialog.Builder(this);
|
||||
|
||||
alert.setIcon(android.R.drawable.ic_dialog_alert);
|
||||
alert.setTitle(R.string.warning);
|
||||
alert.setMessage(this.getString(R.string.fileDeleteConfirmation, getDeleteFile()));
|
||||
|
||||
alert.setPositiveButton(android.R.string.ok,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
removeDialog(Id.dialog.delete_file);
|
||||
File file = new File(getDeleteFile());
|
||||
String msg = "";
|
||||
if (file.delete()) {
|
||||
msg = BaseActivity.this.getString(
|
||||
R.string.fileDeleteSuccessful);
|
||||
} else {
|
||||
msg = BaseActivity.this.getString(
|
||||
R.string.errorMessage,
|
||||
BaseActivity.this.getString(
|
||||
R.string.error_fileDeleteFailed, file));
|
||||
}
|
||||
Toast.makeText(BaseActivity.this,
|
||||
msg, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
alert.setNegativeButton(android.R.string.cancel,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
removeDialog(Id.dialog.delete_file);
|
||||
}
|
||||
});
|
||||
alert.setCancelable(true);
|
||||
|
||||
return alert.create();
|
||||
}
|
||||
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return super.onCreateDialog(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
switch (requestCode) {
|
||||
case Id.request.secret_keys: {
|
||||
if (resultCode == RESULT_OK) {
|
||||
Bundle bundle = data.getExtras();
|
||||
setSecretKeyId(bundle.getLong(Apg.EXTRA_KEY_ID));
|
||||
} else {
|
||||
setSecretKeyId(Id.key.none);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
|
||||
public void setProgress(int resourceId, int progress, int max) {
|
||||
setProgress(getString(resourceId), progress, max);
|
||||
}
|
||||
|
||||
public void setProgress(int progress, int max) {
|
||||
Message msg = new Message();
|
||||
Bundle data = new Bundle();
|
||||
data.putInt(Apg.EXTRA_STATUS, Id.message.progress_update);
|
||||
data.putInt(Apg.EXTRA_PROGRESS, progress);
|
||||
data.putInt(Apg.EXTRA_MAX, max);
|
||||
msg.setData(data);
|
||||
mHandler.sendMessage(msg);
|
||||
}
|
||||
|
||||
public void setProgress(String message, int progress, int max) {
|
||||
Message msg = new Message();
|
||||
Bundle data = new Bundle();
|
||||
data.putInt(Apg.EXTRA_STATUS, Id.message.progress_update);
|
||||
data.putString(Apg.EXTRA_MESSAGE, message);
|
||||
data.putInt(Apg.EXTRA_PROGRESS, progress);
|
||||
data.putInt(Apg.EXTRA_MAX, max);
|
||||
msg.setData(data);
|
||||
mHandler.sendMessage(msg);
|
||||
}
|
||||
|
||||
public void handlerCallback(Message msg) {
|
||||
Bundle data = msg.getData();
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
int type = data.getInt(Apg.EXTRA_STATUS);
|
||||
switch (type) {
|
||||
case Id.message.progress_update: {
|
||||
String message = data.getString(Apg.EXTRA_MESSAGE);
|
||||
if (mProgressDialog != null) {
|
||||
if (message != null) {
|
||||
mProgressDialog.setMessage(message);
|
||||
}
|
||||
mProgressDialog.setMax(data.getInt(Apg.EXTRA_MAX));
|
||||
mProgressDialog.setProgress(data.getInt(Apg.EXTRA_PROGRESS));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Id.message.import_done: // intentionall no break
|
||||
case Id.message.export_done: // intentionall no break
|
||||
case Id.message.done: {
|
||||
mProgressDialog = null;
|
||||
doneCallback(msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void doneCallback(Message msg) {
|
||||
|
||||
}
|
||||
|
||||
public void passPhraseCallback(long keyId, String passPhrase) {
|
||||
Apg.setCachedPassPhrase(keyId, passPhrase);
|
||||
}
|
||||
|
||||
public void sendMessage(Message msg) {
|
||||
mHandler.sendMessage(msg);
|
||||
}
|
||||
|
||||
public void startThread() {
|
||||
mRunningThread = new Thread(this);
|
||||
mRunningThread.start();
|
||||
}
|
||||
|
||||
public void run() {
|
||||
|
||||
}
|
||||
|
||||
public void setSecretKeyId(long id) {
|
||||
mSecretKeyId = id;
|
||||
}
|
||||
|
||||
public long getSecretKeyId() {
|
||||
return mSecretKeyId;
|
||||
}
|
||||
|
||||
protected void setDeleteFile(String deleteFile) {
|
||||
mDeleteFile = deleteFile;
|
||||
}
|
||||
|
||||
protected String getDeleteFile() {
|
||||
return mDeleteFile;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.thialfihar.android.apg;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
public class BaseActivity extends Activity
|
||||
implements Runnable, ProgressDialogUpdater,
|
||||
AskForSecretKeyPassPhrase.PassPhraseCallbackInterface {
|
||||
|
||||
private ProgressDialog mProgressDialog = null;
|
||||
private Thread mRunningThread = null;
|
||||
|
||||
private long mSecretKeyId = 0;
|
||||
private String mDeleteFile = null;
|
||||
|
||||
protected Preferences mPreferences;
|
||||
|
||||
private Handler mHandler = new Handler() {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
handlerCallback(msg);
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
mPreferences = Preferences.getPreferences(this);
|
||||
|
||||
Apg.initialize(this);
|
||||
|
||||
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
||||
File dir = new File(Constants.path.app_dir);
|
||||
if (!dir.exists() && !dir.mkdirs()) {
|
||||
// ignore this for now, it's not crucial
|
||||
// that the directory doesn't exist at this point
|
||||
}
|
||||
}
|
||||
|
||||
startCacheService(this, mPreferences);
|
||||
}
|
||||
|
||||
public static void startCacheService(Activity activity, Preferences preferences) {
|
||||
Intent intent = new Intent(activity, Service.class);
|
||||
intent.putExtra(Service.EXTRA_TTL, preferences.getPassPhraseCacheTtl());
|
||||
activity.startService(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
menu.add(0, Id.menu.option.preferences, 0, R.string.menu_preferences)
|
||||
.setIcon(android.R.drawable.ic_menu_preferences);
|
||||
menu.add(0, Id.menu.option.about, 1, R.string.menu_about)
|
||||
.setIcon(android.R.drawable.ic_menu_info_details);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case Id.menu.option.about: {
|
||||
showDialog(Id.dialog.about);
|
||||
return true;
|
||||
}
|
||||
|
||||
case Id.menu.option.preferences: {
|
||||
startActivity(new Intent(this, PreferencesActivity.class));
|
||||
return true;
|
||||
}
|
||||
|
||||
case Id.menu.option.search: {
|
||||
startSearch("", false, null, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Dialog onCreateDialog(int id) {
|
||||
// in case it is a progress dialog
|
||||
mProgressDialog = new ProgressDialog(this);
|
||||
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
|
||||
mProgressDialog.setCancelable(false);
|
||||
switch (id) {
|
||||
case Id.dialog.encrypting: {
|
||||
mProgressDialog.setMessage(this.getString(R.string.progress_initializing));
|
||||
return mProgressDialog;
|
||||
}
|
||||
|
||||
case Id.dialog.decrypting: {
|
||||
mProgressDialog.setMessage(this.getString(R.string.progress_initializing));
|
||||
return mProgressDialog;
|
||||
}
|
||||
|
||||
case Id.dialog.saving: {
|
||||
mProgressDialog.setMessage(this.getString(R.string.progress_saving));
|
||||
return mProgressDialog;
|
||||
}
|
||||
|
||||
case Id.dialog.importing: {
|
||||
mProgressDialog.setMessage(this.getString(R.string.progress_importing));
|
||||
return mProgressDialog;
|
||||
}
|
||||
|
||||
case Id.dialog.exporting: {
|
||||
mProgressDialog.setMessage(this.getString(R.string.progress_exporting));
|
||||
return mProgressDialog;
|
||||
}
|
||||
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
mProgressDialog = null;
|
||||
|
||||
switch (id) {
|
||||
case Id.dialog.about: {
|
||||
AlertDialog.Builder alert = new AlertDialog.Builder(this);
|
||||
|
||||
alert.setTitle("About " + Apg.getFullVersion(this));
|
||||
|
||||
LayoutInflater inflater =
|
||||
(LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
View layout = inflater.inflate(R.layout.info, null);
|
||||
TextView message = (TextView) layout.findViewById(R.id.message);
|
||||
message.setText("This is an attempt to bring OpenPGP to Android. " +
|
||||
"It is far from complete, but more features are planned (see website).\n\n" +
|
||||
"Feel free to send bug reports, suggestions, feature requests, feedback, " +
|
||||
"photographs.\n\n" +
|
||||
"mail: thi@thialfihar.org\n" +
|
||||
"site: http://apg.thialfihar.org\n\n" +
|
||||
"This software is provided \"as is\", without warranty of any kind.");
|
||||
alert.setView(layout);
|
||||
|
||||
alert.setPositiveButton(android.R.string.ok,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
BaseActivity.this.removeDialog(Id.dialog.about);
|
||||
}
|
||||
});
|
||||
|
||||
return alert.create();
|
||||
}
|
||||
|
||||
case Id.dialog.pass_phrase: {
|
||||
return AskForSecretKeyPassPhrase.createDialog(this, getSecretKeyId(), this);
|
||||
}
|
||||
|
||||
case Id.dialog.pass_phrases_do_not_match: {
|
||||
AlertDialog.Builder alert = new AlertDialog.Builder(this);
|
||||
|
||||
alert.setIcon(android.R.drawable.ic_dialog_alert);
|
||||
alert.setTitle(R.string.error);
|
||||
alert.setMessage(R.string.passPhrasesDoNotMatch);
|
||||
|
||||
alert.setPositiveButton(android.R.string.ok,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
removeDialog(Id.dialog.pass_phrases_do_not_match);
|
||||
}
|
||||
});
|
||||
alert.setCancelable(false);
|
||||
|
||||
return alert.create();
|
||||
}
|
||||
|
||||
case Id.dialog.no_pass_phrase: {
|
||||
AlertDialog.Builder alert = new AlertDialog.Builder(this);
|
||||
|
||||
alert.setIcon(android.R.drawable.ic_dialog_alert);
|
||||
alert.setTitle(R.string.error);
|
||||
alert.setMessage(R.string.passPhraseMustNotBeEmpty);
|
||||
|
||||
alert.setPositiveButton(android.R.string.ok,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
removeDialog(Id.dialog.no_pass_phrase);
|
||||
}
|
||||
});
|
||||
alert.setCancelable(false);
|
||||
|
||||
return alert.create();
|
||||
}
|
||||
|
||||
case Id.dialog.delete_file: {
|
||||
AlertDialog.Builder alert = new AlertDialog.Builder(this);
|
||||
|
||||
alert.setIcon(android.R.drawable.ic_dialog_alert);
|
||||
alert.setTitle(R.string.warning);
|
||||
alert.setMessage(this.getString(R.string.fileDeleteConfirmation, getDeleteFile()));
|
||||
|
||||
alert.setPositiveButton(android.R.string.ok,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
removeDialog(Id.dialog.delete_file);
|
||||
File file = new File(getDeleteFile());
|
||||
String msg = "";
|
||||
if (file.delete()) {
|
||||
msg = BaseActivity.this.getString(
|
||||
R.string.fileDeleteSuccessful);
|
||||
} else {
|
||||
msg = BaseActivity.this.getString(
|
||||
R.string.errorMessage,
|
||||
BaseActivity.this.getString(
|
||||
R.string.error_fileDeleteFailed, file));
|
||||
}
|
||||
Toast.makeText(BaseActivity.this,
|
||||
msg, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
alert.setNegativeButton(android.R.string.cancel,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
removeDialog(Id.dialog.delete_file);
|
||||
}
|
||||
});
|
||||
alert.setCancelable(true);
|
||||
|
||||
return alert.create();
|
||||
}
|
||||
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return super.onCreateDialog(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
switch (requestCode) {
|
||||
case Id.request.secret_keys: {
|
||||
if (resultCode == RESULT_OK) {
|
||||
Bundle bundle = data.getExtras();
|
||||
setSecretKeyId(bundle.getLong(Apg.EXTRA_KEY_ID));
|
||||
} else {
|
||||
setSecretKeyId(Id.key.none);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
|
||||
public void setProgress(int resourceId, int progress, int max) {
|
||||
setProgress(getString(resourceId), progress, max);
|
||||
}
|
||||
|
||||
public void setProgress(int progress, int max) {
|
||||
Message msg = new Message();
|
||||
Bundle data = new Bundle();
|
||||
data.putInt(Apg.EXTRA_STATUS, Id.message.progress_update);
|
||||
data.putInt(Apg.EXTRA_PROGRESS, progress);
|
||||
data.putInt(Apg.EXTRA_MAX, max);
|
||||
msg.setData(data);
|
||||
mHandler.sendMessage(msg);
|
||||
}
|
||||
|
||||
public void setProgress(String message, int progress, int max) {
|
||||
Message msg = new Message();
|
||||
Bundle data = new Bundle();
|
||||
data.putInt(Apg.EXTRA_STATUS, Id.message.progress_update);
|
||||
data.putString(Apg.EXTRA_MESSAGE, message);
|
||||
data.putInt(Apg.EXTRA_PROGRESS, progress);
|
||||
data.putInt(Apg.EXTRA_MAX, max);
|
||||
msg.setData(data);
|
||||
mHandler.sendMessage(msg);
|
||||
}
|
||||
|
||||
public void handlerCallback(Message msg) {
|
||||
Bundle data = msg.getData();
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
int type = data.getInt(Apg.EXTRA_STATUS);
|
||||
switch (type) {
|
||||
case Id.message.progress_update: {
|
||||
String message = data.getString(Apg.EXTRA_MESSAGE);
|
||||
if (mProgressDialog != null) {
|
||||
if (message != null) {
|
||||
mProgressDialog.setMessage(message);
|
||||
}
|
||||
mProgressDialog.setMax(data.getInt(Apg.EXTRA_MAX));
|
||||
mProgressDialog.setProgress(data.getInt(Apg.EXTRA_PROGRESS));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Id.message.import_done: // intentionall no break
|
||||
case Id.message.export_done: // intentionall no break
|
||||
case Id.message.done: {
|
||||
mProgressDialog = null;
|
||||
doneCallback(msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void doneCallback(Message msg) {
|
||||
|
||||
}
|
||||
|
||||
public void passPhraseCallback(long keyId, String passPhrase) {
|
||||
Apg.setCachedPassPhrase(keyId, passPhrase);
|
||||
}
|
||||
|
||||
public void sendMessage(Message msg) {
|
||||
mHandler.sendMessage(msg);
|
||||
}
|
||||
|
||||
public void startThread() {
|
||||
mRunningThread = new Thread(this);
|
||||
mRunningThread.start();
|
||||
}
|
||||
|
||||
public void run() {
|
||||
|
||||
}
|
||||
|
||||
public void setSecretKeyId(long id) {
|
||||
mSecretKeyId = id;
|
||||
}
|
||||
|
||||
public long getSecretKeyId() {
|
||||
return mSecretKeyId;
|
||||
}
|
||||
|
||||
protected void setDeleteFile(String deleteFile) {
|
||||
mDeleteFile = deleteFile;
|
||||
}
|
||||
|
||||
protected String getDeleteFile() {
|
||||
return mDeleteFile;
|
||||
}
|
||||
}
|
||||
|
@ -1,45 +1,45 @@
|
||||
package org.thialfihar.android.apg;
|
||||
|
||||
public class CachedPassPhrase {
|
||||
public final long timestamp;
|
||||
public final String passPhrase;
|
||||
|
||||
public CachedPassPhrase(long timestamp, String passPhrase) {
|
||||
super();
|
||||
this.timestamp = timestamp;
|
||||
this.passPhrase = passPhrase;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
int hc1 = (int)(this.timestamp & 0xffffffff);
|
||||
int hc2 = (this.passPhrase == null ? 0 : this.passPhrase.hashCode());
|
||||
return (hc1 + hc2) * hc2 + hc1;
|
||||
}
|
||||
|
||||
public boolean equals(Object other) {
|
||||
if (!(other instanceof CachedPassPhrase)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CachedPassPhrase o = (CachedPassPhrase) other;
|
||||
if (timestamp != o.timestamp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (passPhrase != o.passPhrase) {
|
||||
if (passPhrase == null || o.passPhrase == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!passPhrase.equals(o.passPhrase)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "(" + timestamp + ", *******)";
|
||||
}
|
||||
}
|
||||
package org.thialfihar.android.apg;
|
||||
|
||||
public class CachedPassPhrase {
|
||||
public final long timestamp;
|
||||
public final String passPhrase;
|
||||
|
||||
public CachedPassPhrase(long timestamp, String passPhrase) {
|
||||
super();
|
||||
this.timestamp = timestamp;
|
||||
this.passPhrase = passPhrase;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
int hc1 = (int)(this.timestamp & 0xffffffff);
|
||||
int hc2 = (this.passPhrase == null ? 0 : this.passPhrase.hashCode());
|
||||
return (hc1 + hc2) * hc2 + hc1;
|
||||
}
|
||||
|
||||
public boolean equals(Object other) {
|
||||
if (!(other instanceof CachedPassPhrase)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CachedPassPhrase o = (CachedPassPhrase) other;
|
||||
if (timestamp != o.timestamp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (passPhrase != o.passPhrase) {
|
||||
if (passPhrase == null || o.passPhrase == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!passPhrase.equals(o.passPhrase)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "(" + timestamp + ", *******)";
|
||||
}
|
||||
}
|
||||
|
@ -1,35 +1,35 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.thialfihar.android.apg;
|
||||
|
||||
import android.os.Environment;
|
||||
|
||||
public final class Constants {
|
||||
public static final class path {
|
||||
public static final String app_dir = Environment.getExternalStorageDirectory() + "/APG";
|
||||
}
|
||||
|
||||
public static final class pref {
|
||||
public static final String has_seen_change_log = "seenChangeLogDialog";
|
||||
public static final String default_encryption_algorithm = "defaultEncryptionAlgorithm";
|
||||
public static final String default_hash_algorithm = "defaultHashAlgorithm";
|
||||
public static final String default_ascii_armour = "defaultAsciiArmour";
|
||||
public static final String default_message_compression = "defaultMessageCompression";
|
||||
public static final String default_file_compression = "defaultFileCompression";
|
||||
public static final String pass_phrase_cache_ttl = "passPhraseCacheTtl";
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.thialfihar.android.apg;
|
||||
|
||||
import android.os.Environment;
|
||||
|
||||
public final class Constants {
|
||||
public static final class path {
|
||||
public static final String app_dir = Environment.getExternalStorageDirectory() + "/APG";
|
||||
}
|
||||
|
||||
public static final class pref {
|
||||
public static final String has_seen_change_log = "seenChangeLogDialog";
|
||||
public static final String default_encryption_algorithm = "defaultEncryptionAlgorithm";
|
||||
public static final String default_hash_algorithm = "defaultHashAlgorithm";
|
||||
public static final String default_ascii_armour = "defaultAsciiArmour";
|
||||
public static final String default_message_compression = "defaultMessageCompression";
|
||||
public static final String default_file_compression = "defaultFileCompression";
|
||||
public static final String pass_phrase_cache_ttl = "passPhraseCacheTtl";
|
||||
}
|
||||
}
|
||||
|
@ -1,79 +1,79 @@
|
||||
package org.thialfihar.android.apg;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.thialfihar.android.apg.Apg.GeneralException;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Environment;
|
||||
|
||||
public class DataDestination {
|
||||
private String mStreamFilename;
|
||||
private String mFilename;
|
||||
private int mMode = Id.mode.undefined;
|
||||
|
||||
public DataDestination() {
|
||||
|
||||
}
|
||||
|
||||
public void setMode(int mode) {
|
||||
mMode = mode;
|
||||
}
|
||||
|
||||
public void setFilename(String filename) {
|
||||
mFilename = filename;
|
||||
}
|
||||
|
||||
public String getStreamFilename() {
|
||||
return mStreamFilename;
|
||||
}
|
||||
|
||||
protected OutputStream getOutputStream(Context context)
|
||||
throws Apg.GeneralException, FileNotFoundException, IOException {
|
||||
OutputStream out = null;
|
||||
mStreamFilename = null;
|
||||
|
||||
switch (mMode) {
|
||||
case Id.mode.stream: {
|
||||
try {
|
||||
while (true) {
|
||||
mStreamFilename = Apg.generateRandomString(32);
|
||||
if (mStreamFilename == null) {
|
||||
throw new Apg.GeneralException("couldn't generate random file name");
|
||||
}
|
||||
context.openFileInput(mStreamFilename).close();
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
// found a name that isn't used yet
|
||||
}
|
||||
out = context.openFileOutput(mStreamFilename, Context.MODE_PRIVATE);
|
||||
break;
|
||||
}
|
||||
|
||||
case Id.mode.byte_array: {
|
||||
out = new ByteArrayOutputStream();
|
||||
break;
|
||||
}
|
||||
|
||||
case Id.mode.file: {
|
||||
if (mFilename.startsWith(Environment.getExternalStorageDirectory().getAbsolutePath())) {
|
||||
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
||||
throw new GeneralException(context.getString(R.string.error_externalStorageNotReady));
|
||||
}
|
||||
}
|
||||
out = new FileOutputStream(mFilename);
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
}
|
||||
package org.thialfihar.android.apg;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.thialfihar.android.apg.Apg.GeneralException;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Environment;
|
||||
|
||||
public class DataDestination {
|
||||
private String mStreamFilename;
|
||||
private String mFilename;
|
||||
private int mMode = Id.mode.undefined;
|
||||
|
||||
public DataDestination() {
|
||||
|
||||
}
|
||||
|
||||
public void setMode(int mode) {
|
||||
mMode = mode;
|
||||
}
|
||||
|
||||
public void setFilename(String filename) {
|
||||
mFilename = filename;
|
||||
}
|
||||
|
||||
public String getStreamFilename() {
|
||||
return mStreamFilename;
|
||||
}
|
||||
|
||||
protected OutputStream getOutputStream(Context context)
|
||||
throws Apg.GeneralException, FileNotFoundException, IOException {
|
||||
OutputStream out = null;
|
||||
mStreamFilename = null;
|
||||
|
||||
switch (mMode) {
|
||||
case Id.mode.stream: {
|
||||
try {
|
||||
while (true) {
|
||||
mStreamFilename = Apg.generateRandomString(32);
|
||||
if (mStreamFilename == null) {
|
||||
throw new Apg.GeneralException("couldn't generate random file name");
|
||||
}
|
||||
context.openFileInput(mStreamFilename).close();
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
// found a name that isn't used yet
|
||||
}
|
||||
out = context.openFileOutput(mStreamFilename, Context.MODE_PRIVATE);
|
||||
break;
|
||||
}
|
||||
|
||||
case Id.mode.byte_array: {
|
||||
out = new ByteArrayOutputStream();
|
||||
break;
|
||||
}
|
||||
|
||||
case Id.mode.file: {
|
||||
if (mFilename.startsWith(Environment.getExternalStorageDirectory().getAbsolutePath())) {
|
||||
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
||||
throw new GeneralException(context.getString(R.string.error_externalStorageNotReady));
|
||||
}
|
||||
}
|
||||
out = new FileOutputStream(mFilename);
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
@ -1,88 +1,88 @@
|
||||
package org.thialfihar.android.apg;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.thialfihar.android.apg.Apg.GeneralException;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.os.Environment;
|
||||
|
||||
public class DataSource {
|
||||
private Uri mContentUri = null;
|
||||
private String mText = null;
|
||||
private byte[] mData = null;
|
||||
|
||||
public DataSource() {
|
||||
|
||||
}
|
||||
|
||||
public void setUri(Uri uri) {
|
||||
mContentUri = uri;
|
||||
}
|
||||
|
||||
public void setUri(String uri) {
|
||||
if (uri.startsWith("/")) {
|
||||
setUri(Uri.parse("file://" + uri));
|
||||
} else {
|
||||
setUri(Uri.parse(uri));
|
||||
}
|
||||
}
|
||||
|
||||
public void setText(String text) {
|
||||
mText = text;
|
||||
}
|
||||
|
||||
public void setData(byte[] data) {
|
||||
mData = data;
|
||||
}
|
||||
|
||||
public InputData getInputData(Context context, boolean withSize)
|
||||
throws GeneralException, FileNotFoundException, IOException {
|
||||
InputStream in = null;
|
||||
long size = 0;
|
||||
|
||||
if (mContentUri != null) {
|
||||
if (mContentUri.getScheme().equals("file")) {
|
||||
// get the rest after "file://"
|
||||
String path = mContentUri.toString().substring(6);
|
||||
if (path.startsWith(Environment.getExternalStorageDirectory().getAbsolutePath())) {
|
||||
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
||||
throw new GeneralException(context.getString(R.string.error_externalStorageNotReady));
|
||||
}
|
||||
}
|
||||
in = new FileInputStream(path);
|
||||
File file = new File(path);
|
||||
if (withSize) {
|
||||
size = file.length();
|
||||
}
|
||||
} else {
|
||||
in = context.getContentResolver().openInputStream(mContentUri);
|
||||
if (withSize) {
|
||||
InputStream tmp = context.getContentResolver().openInputStream(mContentUri);
|
||||
size = Apg.getLengthOfStream(tmp);
|
||||
tmp.close();
|
||||
}
|
||||
}
|
||||
} else if (mText != null || mData != null) {
|
||||
byte[] bytes = null;
|
||||
if (mData != null) {
|
||||
bytes = mData;
|
||||
} else {
|
||||
bytes = mText.getBytes();
|
||||
}
|
||||
in = new ByteArrayInputStream(bytes);
|
||||
if (withSize) {
|
||||
size = bytes.length;
|
||||
}
|
||||
}
|
||||
|
||||
return new InputData(in, size);
|
||||
}
|
||||
|
||||
}
|
||||
package org.thialfihar.android.apg;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.thialfihar.android.apg.Apg.GeneralException;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.os.Environment;
|
||||
|
||||
public class DataSource {
|
||||
private Uri mContentUri = null;
|
||||
private String mText = null;
|
||||
private byte[] mData = null;
|
||||
|
||||
public DataSource() {
|
||||
|
||||
}
|
||||
|
||||
public void setUri(Uri uri) {
|
||||
mContentUri = uri;
|
||||
}
|
||||
|
||||
public void setUri(String uri) {
|
||||
if (uri.startsWith("/")) {
|
||||
setUri(Uri.parse("file://" + uri));
|
||||
} else {
|
||||
setUri(Uri.parse(uri));
|
||||
}
|
||||
}
|
||||
|
||||
public void setText(String text) {
|
||||
mText = text;
|
||||
}
|
||||
|
||||
public void setData(byte[] data) {
|
||||
mData = data;
|
||||
}
|
||||
|
||||
public InputData getInputData(Context context, boolean withSize)
|
||||
throws GeneralException, FileNotFoundException, IOException {
|
||||
InputStream in = null;
|
||||
long size = 0;
|
||||
|
||||
if (mContentUri != null) {
|
||||
if (mContentUri.getScheme().equals("file")) {
|
||||
// get the rest after "file://"
|
||||
String path = mContentUri.toString().substring(6);
|
||||
if (path.startsWith(Environment.getExternalStorageDirectory().getAbsolutePath())) {
|
||||
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
||||
throw new GeneralException(context.getString(R.string.error_externalStorageNotReady));
|
||||
}
|
||||
}
|
||||
in = new FileInputStream(path);
|
||||
File file = new File(path);
|
||||
if (withSize) {
|
||||
size = file.length();
|
||||
}
|
||||
} else {
|
||||
in = context.getContentResolver().openInputStream(mContentUri);
|
||||
if (withSize) {
|
||||
InputStream tmp = context.getContentResolver().openInputStream(mContentUri);
|
||||
size = Apg.getLengthOfStream(tmp);
|
||||
tmp.close();
|
||||
}
|
||||
}
|
||||
} else if (mText != null || mData != null) {
|
||||
byte[] bytes = null;
|
||||
if (mData != null) {
|
||||
bytes = mData;
|
||||
} else {
|
||||
bytes = mText.getBytes();
|
||||
}
|
||||
in = new ByteArrayInputStream(bytes);
|
||||
if (withSize) {
|
||||
size = bytes.length;
|
||||
}
|
||||
}
|
||||
|
||||
return new InputData(in, size);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,118 +1,118 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.thialfihar.android.apg;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.Toast;
|
||||
|
||||
public class FileDialog {
|
||||
private static EditText mFilename;
|
||||
private static ImageButton mBrowse;
|
||||
private static Activity mActivity;
|
||||
private static String mFileManagerTitle;
|
||||
private static String mFileManagerButton;
|
||||
private static int mRequestCode;
|
||||
|
||||
public static interface OnClickListener {
|
||||
public void onCancelClick();
|
||||
public void onOkClick(String filename);
|
||||
}
|
||||
|
||||
public static AlertDialog build(Activity activity, String title, String message,
|
||||
String defaultFile, OnClickListener onClickListener,
|
||||
String fileManagerTitle, String fileManagerButton,
|
||||
int requestCode) {
|
||||
// TODO: fileManagerTitle and fileManagerButton are deprecated, no use for them right now,
|
||||
// but maybe the Intent now used will someday support them again, so leaving them in
|
||||
LayoutInflater inflater =
|
||||
(LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
AlertDialog.Builder alert = new AlertDialog.Builder(activity);
|
||||
|
||||
alert.setTitle(title);
|
||||
alert.setMessage(message);
|
||||
|
||||
View view = (View) inflater.inflate(R.layout.file_dialog, null);
|
||||
|
||||
mActivity = activity;
|
||||
mFilename = (EditText) view.findViewById(R.id.input);
|
||||
mFilename.setText(defaultFile);
|
||||
mBrowse = (ImageButton) view.findViewById(R.id.btn_browse);
|
||||
mBrowse.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
openFile();
|
||||
}
|
||||
});
|
||||
mFileManagerTitle = fileManagerTitle;
|
||||
mFileManagerButton = fileManagerButton;
|
||||
mRequestCode = requestCode;
|
||||
|
||||
alert.setView(view);
|
||||
|
||||
final OnClickListener clickListener = onClickListener;
|
||||
|
||||
alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
clickListener.onOkClick(mFilename.getText().toString());
|
||||
}
|
||||
});
|
||||
|
||||
alert.setNegativeButton(android.R.string.cancel,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
clickListener.onCancelClick();
|
||||
}
|
||||
});
|
||||
return alert.create();
|
||||
}
|
||||
|
||||
public static void setFilename(String filename) {
|
||||
if (mFilename != null) {
|
||||
mFilename.setText(filename);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the file manager to select a file to open.
|
||||
*/
|
||||
private static void openFile() {
|
||||
String filename = mFilename.getText().toString();
|
||||
|
||||
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
|
||||
intent.setData(Uri.parse("file://" + filename));
|
||||
intent.setType("*/*");
|
||||
|
||||
try {
|
||||
mActivity.startActivityForResult(intent, mRequestCode);
|
||||
} catch (ActivityNotFoundException e) {
|
||||
// No compatible file manager was found.
|
||||
Toast.makeText(mActivity, R.string.noFilemanagerInstalled, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.thialfihar.android.apg;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.Toast;
|
||||
|
||||
public class FileDialog {
|
||||
private static EditText mFilename;
|
||||
private static ImageButton mBrowse;
|
||||
private static Activity mActivity;
|
||||
private static String mFileManagerTitle;
|
||||
private static String mFileManagerButton;
|
||||
private static int mRequestCode;
|
||||
|
||||
public static interface OnClickListener {
|
||||
public void onCancelClick();
|
||||
public void onOkClick(String filename);
|
||||
}
|
||||
|
||||
public static AlertDialog build(Activity activity, String title, String message,
|
||||
String defaultFile, OnClickListener onClickListener,
|
||||
String fileManagerTitle, String fileManagerButton,
|
||||
int requestCode) {
|
||||
// TODO: fileManagerTitle and fileManagerButton are deprecated, no use for them right now,
|
||||
// but maybe the Intent now used will someday support them again, so leaving them in
|
||||
LayoutInflater inflater =
|
||||
(LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
AlertDialog.Builder alert = new AlertDialog.Builder(activity);
|
||||
|
||||
alert.setTitle(title);
|
||||
alert.setMessage(message);
|
||||
|
||||
View view = (View) inflater.inflate(R.layout.file_dialog, null);
|
||||
|
||||
mActivity = activity;
|
||||
mFilename = (EditText) view.findViewById(R.id.input);
|
||||
mFilename.setText(defaultFile);
|
||||
mBrowse = (ImageButton) view.findViewById(R.id.btn_browse);
|
||||
mBrowse.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
openFile();
|
||||
}
|
||||
});
|
||||
mFileManagerTitle = fileManagerTitle;
|
||||
mFileManagerButton = fileManagerButton;
|
||||
mRequestCode = requestCode;
|
||||
|
||||
alert.setView(view);
|
||||
|
||||
final OnClickListener clickListener = onClickListener;
|
||||
|
||||
alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
clickListener.onOkClick(mFilename.getText().toString());
|
||||
}
|
||||
});
|
||||
|
||||
alert.setNegativeButton(android.R.string.cancel,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
clickListener.onCancelClick();
|
||||
}
|
||||
});
|
||||
return alert.create();
|
||||
}
|
||||
|
||||
public static void setFilename(String filename) {
|
||||
if (mFilename != null) {
|
||||
mFilename.setText(filename);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the file manager to select a file to open.
|
||||
*/
|
||||
private static void openFile() {
|
||||
String filename = mFilename.getText().toString();
|
||||
|
||||
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
|
||||
intent.setData(Uri.parse("file://" + filename));
|
||||
intent.setType("*/*");
|
||||
|
||||
try {
|
||||
mActivity.startActivityForResult(intent, mRequestCode);
|
||||
} catch (ActivityNotFoundException e) {
|
||||
// No compatible file manager was found.
|
||||
Toast.makeText(mActivity, R.string.noFilemanagerInstalled, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,177 +1,177 @@
|
||||
package org.thialfihar.android.apg;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Vector;
|
||||
|
||||
import org.thialfihar.android.apg.utils.Choice;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.AdapterView.OnItemClickListener;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.ListView;
|
||||
import android.widget.Toast;
|
||||
|
||||
public class GeneralActivity extends BaseActivity {
|
||||
private Intent mIntent;
|
||||
private ArrayAdapter<Choice> mAdapter;
|
||||
private ListView mList;
|
||||
private Button mCancelButton;
|
||||
private String mDataString;
|
||||
private Uri mDataUri;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.general);
|
||||
|
||||
mIntent = getIntent();
|
||||
|
||||
InputStream inStream = null;
|
||||
{
|
||||
String data = mIntent.getStringExtra(Intent.EXTRA_TEXT);
|
||||
if (data != null) {
|
||||
mDataString = data;
|
||||
inStream = new ByteArrayInputStream(data.getBytes());
|
||||
}
|
||||
}
|
||||
|
||||
if (inStream == null) {
|
||||
Uri data = mIntent.getData();
|
||||
if (data != null) {
|
||||
mDataUri = data;
|
||||
try {
|
||||
inStream = getContentResolver().openInputStream(data);
|
||||
} catch (FileNotFoundException e) {
|
||||
// didn't work
|
||||
Toast.makeText(this, "failed to open stream", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (inStream == null) {
|
||||
Toast.makeText(this, "no data found", Toast.LENGTH_SHORT).show();
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
int contentType = Id.content.unknown;
|
||||
try {
|
||||
contentType = Apg.getStreamContent(this, inStream);
|
||||
inStream.close();
|
||||
} catch (IOException e) {
|
||||
// just means that there's no PGP data in there
|
||||
}
|
||||
|
||||
mList = (ListView) findViewById(R.id.options);
|
||||
Vector<Choice> choices = new Vector<Choice>();
|
||||
|
||||
if (contentType == Id.content.keys) {
|
||||
choices.add(new Choice(Id.choice.action.import_public,
|
||||
getString(R.string.action_importPublic)));
|
||||
choices.add(new Choice(Id.choice.action.import_secret,
|
||||
getString(R.string.action_importSecret)));
|
||||
}
|
||||
|
||||
if (contentType == Id.content.encrypted_data) {
|
||||
choices.add(new Choice(Id.choice.action.decrypt, getString(R.string.action_decrypt)));
|
||||
}
|
||||
|
||||
if (contentType == Id.content.unknown) {
|
||||
choices.add(new Choice(Id.choice.action.encrypt, getString(R.string.action_encrypt)));
|
||||
}
|
||||
|
||||
mAdapter = new ArrayAdapter<Choice>(this, android.R.layout.simple_list_item_1, choices);
|
||||
mList.setAdapter(mAdapter);
|
||||
|
||||
mList.setOnItemClickListener(new OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
|
||||
clicked(mAdapter.getItem(arg2).getId());
|
||||
}
|
||||
});
|
||||
|
||||
mCancelButton = (Button) findViewById(R.id.btn_cancel);
|
||||
mCancelButton.setOnClickListener(new OnClickListener() {
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
GeneralActivity.this.finish();
|
||||
}
|
||||
});
|
||||
|
||||
if (choices.size() == 1) {
|
||||
clicked(choices.get(0).getId());
|
||||
}
|
||||
}
|
||||
|
||||
private void clicked(int id) {
|
||||
Intent intent = new Intent();
|
||||
switch (id) {
|
||||
case Id.choice.action.encrypt: {
|
||||
intent.setClass(this, EncryptActivity.class);
|
||||
if (mDataString != null) {
|
||||
intent.setAction(Apg.Intent.ENCRYPT);
|
||||
intent.putExtra(Apg.EXTRA_TEXT, mDataString);
|
||||
} else if (mDataUri != null) {
|
||||
intent.setAction(Apg.Intent.ENCRYPT_FILE);
|
||||
intent.setDataAndType(mDataUri, mIntent.getType());
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case Id.choice.action.decrypt: {
|
||||
intent.setClass(this, DecryptActivity.class);
|
||||
if (mDataString != null) {
|
||||
intent.setAction(Apg.Intent.DECRYPT);
|
||||
intent.putExtra(Apg.EXTRA_TEXT, mDataString);
|
||||
} else if (mDataUri != null) {
|
||||
intent.setAction(Apg.Intent.DECRYPT_FILE);
|
||||
intent.setDataAndType(mDataUri, mIntent.getType());
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case Id.choice.action.import_public: {
|
||||
intent.setClass(this, PublicKeyListActivity.class);
|
||||
intent.setAction(Apg.Intent.IMPORT);
|
||||
if (mDataString != null) {
|
||||
intent.putExtra(Apg.EXTRA_TEXT, mDataString);
|
||||
} else if (mDataUri != null) {
|
||||
intent.setDataAndType(mDataUri, mIntent.getType());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Id.choice.action.import_secret: {
|
||||
intent.setClass(this, SecretKeyListActivity.class);
|
||||
intent.setAction(Apg.Intent.IMPORT);
|
||||
if (mDataString != null) {
|
||||
intent.putExtra(Apg.EXTRA_TEXT, mDataString);
|
||||
} else if (mDataUri != null) {
|
||||
intent.setDataAndType(mDataUri, mIntent.getType());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
// shouldn't happen
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
startActivity(intent);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
package org.thialfihar.android.apg;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Vector;
|
||||
|
||||
import org.thialfihar.android.apg.utils.Choice;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.AdapterView.OnItemClickListener;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.ListView;
|
||||
import android.widget.Toast;
|
||||
|
||||
public class GeneralActivity extends BaseActivity {
|
||||
private Intent mIntent;
|
||||
private ArrayAdapter<Choice> mAdapter;
|
||||
private ListView mList;
|
||||
private Button mCancelButton;
|
||||
private String mDataString;
|
||||
private Uri mDataUri;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.general);
|
||||
|
||||
mIntent = getIntent();
|
||||
|
||||
InputStream inStream = null;
|
||||
{
|
||||
String data = mIntent.getStringExtra(Intent.EXTRA_TEXT);
|
||||
if (data != null) {
|
||||
mDataString = data;
|
||||
inStream = new ByteArrayInputStream(data.getBytes());
|
||||
}
|
||||
}
|
||||
|
||||
if (inStream == null) {
|
||||
Uri data = mIntent.getData();
|
||||
if (data != null) {
|
||||
mDataUri = data;
|
||||
try {
|
||||
inStream = getContentResolver().openInputStream(data);
|
||||
} catch (FileNotFoundException e) {
|
||||
// didn't work
|
||||
Toast.makeText(this, "failed to open stream", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (inStream == null) {
|
||||
Toast.makeText(this, "no data found", Toast.LENGTH_SHORT).show();
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
int contentType = Id.content.unknown;
|
||||
try {
|
||||
contentType = Apg.getStreamContent(this, inStream);
|
||||
inStream.close();
|
||||
} catch (IOException e) {
|
||||
// just means that there's no PGP data in there
|
||||
}
|
||||
|
||||
mList = (ListView) findViewById(R.id.options);
|
||||
Vector<Choice> choices = new Vector<Choice>();
|
||||
|
||||
if (contentType == Id.content.keys) {
|
||||
choices.add(new Choice(Id.choice.action.import_public,
|
||||
getString(R.string.action_importPublic)));
|
||||
choices.add(new Choice(Id.choice.action.import_secret,
|
||||
getString(R.string.action_importSecret)));
|
||||
}
|
||||
|
||||
if (contentType == Id.content.encrypted_data) {
|
||||
choices.add(new Choice(Id.choice.action.decrypt, getString(R.string.action_decrypt)));
|
||||
}
|
||||
|
||||
if (contentType == Id.content.unknown) {
|
||||
choices.add(new Choice(Id.choice.action.encrypt, getString(R.string.action_encrypt)));
|
||||
}
|
||||
|
||||
mAdapter = new ArrayAdapter<Choice>(this, android.R.layout.simple_list_item_1, choices);
|
||||
mList.setAdapter(mAdapter);
|
||||
|
||||
mList.setOnItemClickListener(new OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
|
||||
clicked(mAdapter.getItem(arg2).getId());
|
||||
}
|
||||
});
|
||||
|
||||
mCancelButton = (Button) findViewById(R.id.btn_cancel);
|
||||
mCancelButton.setOnClickListener(new OnClickListener() {
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
GeneralActivity.this.finish();
|
||||
}
|
||||
});
|
||||
|
||||
if (choices.size() == 1) {
|
||||
clicked(choices.get(0).getId());
|
||||
}
|
||||
}
|
||||
|
||||
private void clicked(int id) {
|
||||
Intent intent = new Intent();
|
||||
switch (id) {
|
||||
case Id.choice.action.encrypt: {
|
||||
intent.setClass(this, EncryptActivity.class);
|
||||
if (mDataString != null) {
|
||||
intent.setAction(Apg.Intent.ENCRYPT);
|
||||
intent.putExtra(Apg.EXTRA_TEXT, mDataString);
|
||||
} else if (mDataUri != null) {
|
||||
intent.setAction(Apg.Intent.ENCRYPT_FILE);
|
||||
intent.setDataAndType(mDataUri, mIntent.getType());
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case Id.choice.action.decrypt: {
|
||||
intent.setClass(this, DecryptActivity.class);
|
||||
if (mDataString != null) {
|
||||
intent.setAction(Apg.Intent.DECRYPT);
|
||||
intent.putExtra(Apg.EXTRA_TEXT, mDataString);
|
||||
} else if (mDataUri != null) {
|
||||
intent.setAction(Apg.Intent.DECRYPT_FILE);
|
||||
intent.setDataAndType(mDataUri, mIntent.getType());
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case Id.choice.action.import_public: {
|
||||
intent.setClass(this, PublicKeyListActivity.class);
|
||||
intent.setAction(Apg.Intent.IMPORT);
|
||||
if (mDataString != null) {
|
||||
intent.putExtra(Apg.EXTRA_TEXT, mDataString);
|
||||
} else if (mDataUri != null) {
|
||||
intent.setDataAndType(mDataUri, mIntent.getType());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Id.choice.action.import_secret: {
|
||||
intent.setClass(this, SecretKeyListActivity.class);
|
||||
intent.setAction(Apg.Intent.IMPORT);
|
||||
if (mDataString != null) {
|
||||
intent.putExtra(Apg.EXTRA_TEXT, mDataString);
|
||||
} else if (mDataUri != null) {
|
||||
intent.setDataAndType(mDataUri, mIntent.getType());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
// shouldn't happen
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
startActivity(intent);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
@ -1,155 +1,155 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.thialfihar.android.apg;
|
||||
|
||||
import org.bouncycastle2.bcpg.CompressionAlgorithmTags;
|
||||
|
||||
public final class Id {
|
||||
public static final class menu {
|
||||
public static final int export = 0x21070001;
|
||||
public static final int delete = 0x21070002;
|
||||
public static final int edit = 0x21070003;
|
||||
|
||||
public static final class option {
|
||||
public static final int new_pass_phrase = 0x21070001;
|
||||
public static final int create = 0x21070002;
|
||||
public static final int about = 0x21070003;
|
||||
public static final int manage_public_keys = 0x21070004;
|
||||
public static final int manage_secret_keys = 0x21070005;
|
||||
public static final int import_keys = 0x21070006;
|
||||
public static final int export_keys = 0x21070007;
|
||||
public static final int preferences = 0x21070008;
|
||||
public static final int search = 0x21070009;
|
||||
}
|
||||
}
|
||||
|
||||
public static final class message {
|
||||
public static final int progress_update = 0x21070001;
|
||||
public static final int done = 0x21070002;
|
||||
public static final int import_keys = 0x21070003;
|
||||
public static final int export_keys = 0x21070004;
|
||||
public static final int import_done = 0x21070005;
|
||||
public static final int export_done = 0x21070006;
|
||||
public static final int create_key = 0x21070007;
|
||||
public static final int edit_key = 0x21070008;
|
||||
}
|
||||
|
||||
public static final class request {
|
||||
public static final int public_keys = 0x21070001;
|
||||
public static final int secret_keys = 0x21070002;
|
||||
public static final int filename = 0x21070003;
|
||||
public static final int output_filename = 0x21070004;
|
||||
}
|
||||
|
||||
public static final class dialog {
|
||||
public static final int pass_phrase = 0x21070001;
|
||||
public static final int encrypting = 0x21070002;
|
||||
public static final int decrypting = 0x21070003;
|
||||
public static final int new_pass_phrase = 0x21070004;
|
||||
public static final int pass_phrases_do_not_match = 0x21070005;
|
||||
public static final int no_pass_phrase = 0x21070006;
|
||||
public static final int saving = 0x21070007;
|
||||
public static final int delete_key = 0x21070008;
|
||||
public static final int import_keys = 0x21070009;
|
||||
public static final int importing = 0x2107000a;
|
||||
public static final int export_key = 0x2107000b;
|
||||
public static final int export_keys = 0x2107000c;
|
||||
public static final int exporting = 0x2107000d;
|
||||
public static final int new_account = 0x2107000e;
|
||||
public static final int about = 0x2107000f;
|
||||
public static final int change_log = 0x21070010;
|
||||
public static final int output_filename = 0x21070011;
|
||||
public static final int delete_file = 0x21070012;
|
||||
}
|
||||
|
||||
public static final class task {
|
||||
public static final int import_keys = 0x21070001;
|
||||
public static final int export_keys = 0x21070002;
|
||||
}
|
||||
|
||||
public static final class database {
|
||||
public static final int type_public = 0;
|
||||
public static final int type_secret = 1;
|
||||
}
|
||||
|
||||
public static final class type {
|
||||
public static final int public_key = 0x21070001;
|
||||
public static final int secret_key = 0x21070002;
|
||||
public static final int user_id = 0x21070003;
|
||||
public static final int key = 0x21070004;
|
||||
}
|
||||
|
||||
public static final class choice {
|
||||
public static final class algorithm {
|
||||
public static final int dsa = 0x21070001;
|
||||
public static final int elgamal = 0x21070002;
|
||||
public static final int rsa = 0x21070003;
|
||||
}
|
||||
|
||||
public static final class compression {
|
||||
public static final int none = 0x21070001;
|
||||
public static final int zlib = CompressionAlgorithmTags.ZLIB;
|
||||
public static final int bzip2 = CompressionAlgorithmTags.BZIP2;
|
||||
public static final int zip = CompressionAlgorithmTags.ZIP;
|
||||
}
|
||||
|
||||
public static final class usage {
|
||||
public static final int sign_only = 0x21070001;
|
||||
public static final int encrypt_only = 0x21070002;
|
||||
public static final int sign_and_encrypt = 0x21070003;
|
||||
}
|
||||
|
||||
public static final class action {
|
||||
public static final int encrypt = 0x21070001;
|
||||
public static final int decrypt = 0x21070002;
|
||||
public static final int import_public = 0x21070003;
|
||||
public static final int import_secret = 0x21070004;
|
||||
}
|
||||
}
|
||||
|
||||
public static final class return_value {
|
||||
public static final int ok = 0;
|
||||
public static final int error = -1;
|
||||
public static final int no_master_key = -2;
|
||||
public static final int updated = 1;
|
||||
}
|
||||
|
||||
public static final class target {
|
||||
public static final int clipboard = 0x21070001;
|
||||
public static final int email = 0x21070002;
|
||||
public static final int file = 0x21070003;
|
||||
public static final int message = 0x21070004;
|
||||
}
|
||||
|
||||
public static final class mode {
|
||||
public static final int undefined = 0x21070001;
|
||||
public static final int byte_array = 0x21070002;
|
||||
public static final int file = 0x21070003;
|
||||
public static final int stream = 0x21070004;
|
||||
}
|
||||
|
||||
public static final class key {
|
||||
public static final int none = 0;
|
||||
public static final int symmetric = -1;
|
||||
}
|
||||
|
||||
public static final class content {
|
||||
public static final int unknown = 0;
|
||||
public static final int encrypted_data = 1;
|
||||
public static final int keys = 2;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.thialfihar.android.apg;
|
||||
|
||||
import org.bouncycastle2.bcpg.CompressionAlgorithmTags;
|
||||
|
||||
public final class Id {
|
||||
public static final class menu {
|
||||
public static final int export = 0x21070001;
|
||||
public static final int delete = 0x21070002;
|
||||
public static final int edit = 0x21070003;
|
||||
|
||||
public static final class option {
|
||||
public static final int new_pass_phrase = 0x21070001;
|
||||
public static final int create = 0x21070002;
|
||||
public static final int about = 0x21070003;
|
||||
public static final int manage_public_keys = 0x21070004;
|
||||
public static final int manage_secret_keys = 0x21070005;
|
||||
public static final int import_keys = 0x21070006;
|
||||
public static final int export_keys = 0x21070007;
|
||||
public static final int preferences = 0x21070008;
|
||||
public static final int search = 0x21070009;
|
||||
}
|
||||
}
|
||||
|
||||
public static final class message {
|
||||
public static final int progress_update = 0x21070001;
|
||||
public static final int done = 0x21070002;
|
||||
public static final int import_keys = 0x21070003;
|
||||
public static final int export_keys = 0x21070004;
|
||||
public static final int import_done = 0x21070005;
|
||||
public static final int export_done = 0x21070006;
|
||||
public static final int create_key = 0x21070007;
|
||||
public static final int edit_key = 0x21070008;
|
||||
}
|
||||
|
||||
public static final class request {
|
||||
public static final int public_keys = 0x21070001;
|
||||
public static final int secret_keys = 0x21070002;
|
||||
public static final int filename = 0x21070003;
|
||||
public static final int output_filename = 0x21070004;
|
||||
}
|
||||
|
||||
public static final class dialog {
|
||||
public static final int pass_phrase = 0x21070001;
|
||||
public static final int encrypting = 0x21070002;
|
||||
public static final int decrypting = 0x21070003;
|
||||
public static final int new_pass_phrase = 0x21070004;
|
||||
public static final int pass_phrases_do_not_match = 0x21070005;
|
||||
public static final int no_pass_phrase = 0x21070006;
|
||||
public static final int saving = 0x21070007;
|
||||
public static final int delete_key = 0x21070008;
|
||||
public static final int import_keys = 0x21070009;
|
||||
public static final int importing = 0x2107000a;
|
||||
public static final int export_key = 0x2107000b;
|
||||
public static final int export_keys = 0x2107000c;
|
||||
public static final int exporting = 0x2107000d;
|
||||
public static final int new_account = 0x2107000e;
|
||||
public static final int about = 0x2107000f;
|
||||
public static final int change_log = 0x21070010;
|
||||
public static final int output_filename = 0x21070011;
|
||||
public static final int delete_file = 0x21070012;
|
||||
}
|
||||
|
||||
public static final class task {
|
||||
public static final int import_keys = 0x21070001;
|
||||
public static final int export_keys = 0x21070002;
|
||||
}
|
||||
|
||||
public static final class database {
|
||||
public static final int type_public = 0;
|
||||
public static final int type_secret = 1;
|
||||
}
|
||||
|
||||
public static final class type {
|
||||
public static final int public_key = 0x21070001;
|
||||
public static final int secret_key = 0x21070002;
|
||||
public static final int user_id = 0x21070003;
|
||||
public static final int key = 0x21070004;
|
||||
}
|
||||
|
||||
public static final class choice {
|
||||
public static final class algorithm {
|
||||
public static final int dsa = 0x21070001;
|
||||
public static final int elgamal = 0x21070002;
|
||||
public static final int rsa = 0x21070003;
|
||||
}
|
||||
|
||||
public static final class compression {
|
||||
public static final int none = 0x21070001;
|
||||
public static final int zlib = CompressionAlgorithmTags.ZLIB;
|
||||
public static final int bzip2 = CompressionAlgorithmTags.BZIP2;
|
||||
public static final int zip = CompressionAlgorithmTags.ZIP;
|
||||
}
|
||||
|
||||
public static final class usage {
|
||||
public static final int sign_only = 0x21070001;
|
||||
public static final int encrypt_only = 0x21070002;
|
||||
public static final int sign_and_encrypt = 0x21070003;
|
||||
}
|
||||
|
||||
public static final class action {
|
||||
public static final int encrypt = 0x21070001;
|
||||
public static final int decrypt = 0x21070002;
|
||||
public static final int import_public = 0x21070003;
|
||||
public static final int import_secret = 0x21070004;
|
||||
}
|
||||
}
|
||||
|
||||
public static final class return_value {
|
||||
public static final int ok = 0;
|
||||
public static final int error = -1;
|
||||
public static final int no_master_key = -2;
|
||||
public static final int updated = 1;
|
||||
}
|
||||
|
||||
public static final class target {
|
||||
public static final int clipboard = 0x21070001;
|
||||
public static final int email = 0x21070002;
|
||||
public static final int file = 0x21070003;
|
||||
public static final int message = 0x21070004;
|
||||
}
|
||||
|
||||
public static final class mode {
|
||||
public static final int undefined = 0x21070001;
|
||||
public static final int byte_array = 0x21070002;
|
||||
public static final int file = 0x21070003;
|
||||
public static final int stream = 0x21070004;
|
||||
}
|
||||
|
||||
public static final class key {
|
||||
public static final int none = 0;
|
||||
public static final int symmetric = -1;
|
||||
}
|
||||
|
||||
public static final class content {
|
||||
public static final int unknown = 0;
|
||||
public static final int encrypted_data = 1;
|
||||
public static final int keys = 2;
|
||||
}
|
||||
}
|
||||
|
@ -1,25 +1,25 @@
|
||||
package org.thialfihar.android.apg;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
public class InputData {
|
||||
private PositionAwareInputStream mInputStream;
|
||||
private long mSize;
|
||||
|
||||
InputData(InputStream inputStream, long size) {
|
||||
mInputStream = new PositionAwareInputStream(inputStream);
|
||||
mSize = size;
|
||||
}
|
||||
|
||||
public InputStream getInputStream() {
|
||||
return mInputStream;
|
||||
}
|
||||
|
||||
public long getSize() {
|
||||
return mSize;
|
||||
}
|
||||
|
||||
public long getStreamPosition() {
|
||||
return mInputStream.position();
|
||||
}
|
||||
}
|
||||
package org.thialfihar.android.apg;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
public class InputData {
|
||||
private PositionAwareInputStream mInputStream;
|
||||
private long mSize;
|
||||
|
||||
InputData(InputStream inputStream, long size) {
|
||||
mInputStream = new PositionAwareInputStream(inputStream);
|
||||
mSize = size;
|
||||
}
|
||||
|
||||
public InputStream getInputStream() {
|
||||
return mInputStream;
|
||||
}
|
||||
|
||||
public long getSize() {
|
||||
return mSize;
|
||||
}
|
||||
|
||||
public long getStreamPosition() {
|
||||
return mInputStream.position();
|
||||
}
|
||||
}
|
||||
|
@ -1,95 +1,95 @@
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* 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.thialfihar.android.apg;
|
||||
|
||||
import android.content.Context;
|
||||
import android.preference.ListPreference;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
/**
|
||||
* A list preference which persists its values as integers instead of strings.
|
||||
* Code reading the values should use
|
||||
* {@link android.content.SharedPreferences#getInt}.
|
||||
* When using XML-declared arrays for entry values, the arrays should be regular
|
||||
* string arrays containing valid integer values.
|
||||
*
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public class IntegerListPreference extends ListPreference {
|
||||
|
||||
public IntegerListPreference(Context context) {
|
||||
super(context);
|
||||
|
||||
verifyEntryValues(null);
|
||||
}
|
||||
|
||||
public IntegerListPreference(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
|
||||
verifyEntryValues(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEntryValues(CharSequence[] entryValues) {
|
||||
CharSequence[] oldValues = getEntryValues();
|
||||
super.setEntryValues(entryValues);
|
||||
verifyEntryValues(oldValues);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEntryValues(int entryValuesResId) {
|
||||
CharSequence[] oldValues = getEntryValues();
|
||||
super.setEntryValues(entryValuesResId);
|
||||
verifyEntryValues(oldValues);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getPersistedString(String defaultReturnValue) {
|
||||
// During initial load, there's no known default value
|
||||
int defaultIntegerValue = Integer.MIN_VALUE;
|
||||
if (defaultReturnValue != null) {
|
||||
defaultIntegerValue = Integer.parseInt(defaultReturnValue);
|
||||
}
|
||||
|
||||
// When the list preference asks us to read a string, instead read an
|
||||
// integer.
|
||||
int value = getPersistedInt(defaultIntegerValue);
|
||||
return Integer.toString(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean persistString(String value) {
|
||||
// When asked to save a string, instead save an integer
|
||||
return persistInt(Integer.parseInt(value));
|
||||
}
|
||||
|
||||
private void verifyEntryValues(CharSequence[] oldValues) {
|
||||
CharSequence[] entryValues = getEntryValues();
|
||||
if (entryValues == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (CharSequence entryValue : entryValues) {
|
||||
try {
|
||||
Integer.parseInt(entryValue.toString());
|
||||
} catch (NumberFormatException nfe) {
|
||||
super.setEntryValues(oldValues);
|
||||
throw nfe;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* 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.thialfihar.android.apg;
|
||||
|
||||
import android.content.Context;
|
||||
import android.preference.ListPreference;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
/**
|
||||
* A list preference which persists its values as integers instead of strings.
|
||||
* Code reading the values should use
|
||||
* {@link android.content.SharedPreferences#getInt}.
|
||||
* When using XML-declared arrays for entry values, the arrays should be regular
|
||||
* string arrays containing valid integer values.
|
||||
*
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public class IntegerListPreference extends ListPreference {
|
||||
|
||||
public IntegerListPreference(Context context) {
|
||||
super(context);
|
||||
|
||||
verifyEntryValues(null);
|
||||
}
|
||||
|
||||
public IntegerListPreference(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
|
||||
verifyEntryValues(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEntryValues(CharSequence[] entryValues) {
|
||||
CharSequence[] oldValues = getEntryValues();
|
||||
super.setEntryValues(entryValues);
|
||||
verifyEntryValues(oldValues);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEntryValues(int entryValuesResId) {
|
||||
CharSequence[] oldValues = getEntryValues();
|
||||
super.setEntryValues(entryValuesResId);
|
||||
verifyEntryValues(oldValues);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getPersistedString(String defaultReturnValue) {
|
||||
// During initial load, there's no known default value
|
||||
int defaultIntegerValue = Integer.MIN_VALUE;
|
||||
if (defaultReturnValue != null) {
|
||||
defaultIntegerValue = Integer.parseInt(defaultReturnValue);
|
||||
}
|
||||
|
||||
// When the list preference asks us to read a string, instead read an
|
||||
// integer.
|
||||
int value = getPersistedInt(defaultIntegerValue);
|
||||
return Integer.toString(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean persistString(String value) {
|
||||
// When asked to save a string, instead save an integer
|
||||
return persistInt(Integer.parseInt(value));
|
||||
}
|
||||
|
||||
private void verifyEntryValues(CharSequence[] oldValues) {
|
||||
CharSequence[] entryValues = getEntryValues();
|
||||
if (entryValues == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (CharSequence entryValue : entryValues) {
|
||||
try {
|
||||
Integer.parseInt(entryValue.toString());
|
||||
} catch (NumberFormatException nfe) {
|
||||
super.setEntryValues(oldValues);
|
||||
throw nfe;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,218 +1,218 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.thialfihar.android.apg;
|
||||
|
||||
import java.util.Vector;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
import android.app.ListActivity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.text.Html;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.AdapterView.OnItemClickListener;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ListAdapter;
|
||||
import android.widget.TextView;
|
||||
|
||||
public class MailListActivity extends ListActivity {
|
||||
LayoutInflater mInflater = null;
|
||||
|
||||
private static class Conversation {
|
||||
public long id;
|
||||
public String subject;
|
||||
public Vector<Message> messages;
|
||||
|
||||
public Conversation(long id, String subject) {
|
||||
this.id = id;
|
||||
this.subject = subject;
|
||||
}
|
||||
}
|
||||
|
||||
private static class Message {
|
||||
public Conversation parent;
|
||||
public long id;
|
||||
public String subject;
|
||||
public String fromAddress;
|
||||
public String data;
|
||||
public String replyTo;
|
||||
public boolean signedOnly;
|
||||
|
||||
public Message(Conversation parent, long id, String subject,
|
||||
String fromAddress, String replyTo,
|
||||
String data, boolean signedOnly) {
|
||||
this.parent = parent;
|
||||
this.id = id;
|
||||
this.subject = subject;
|
||||
this.fromAddress = fromAddress;
|
||||
this.replyTo = replyTo;
|
||||
this.data = data;
|
||||
if (this.replyTo == null || this.replyTo.equals("")) {
|
||||
this.replyTo = this.fromAddress;
|
||||
}
|
||||
this.signedOnly = signedOnly;
|
||||
}
|
||||
}
|
||||
|
||||
private Vector<Conversation> mconversations;
|
||||
private Vector<Message> mmessages;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
mInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
|
||||
mconversations = new Vector<Conversation>();
|
||||
mmessages = new Vector<Message>();
|
||||
|
||||
String account = getIntent().getExtras().getString(Apg.EXTRA_ACCOUNT);
|
||||
// TODO: what if account is null?
|
||||
Uri uri = Uri.parse("content://gmail-ls/conversations/" + account);
|
||||
Cursor cursor =
|
||||
managedQuery(uri, new String[] { "conversation_id", "subject" }, null, null, null);
|
||||
for (int i = 0; i < cursor.getCount(); ++i) {
|
||||
cursor.moveToPosition(i);
|
||||
|
||||
int idIndex = cursor.getColumnIndex("conversation_id");
|
||||
int subjectIndex = cursor.getColumnIndex("subject");
|
||||
long conversationId = cursor.getLong(idIndex);
|
||||
Conversation conversation =
|
||||
new Conversation(conversationId, cursor.getString(subjectIndex));
|
||||
Uri messageUri = Uri.withAppendedPath(uri, "" + conversationId + "/messages");
|
||||
Cursor messageCursor =
|
||||
managedQuery(messageUri, new String[] {
|
||||
"messageId",
|
||||
"subject",
|
||||
"fromAddress",
|
||||
"replyToAddresses",
|
||||
"body" }, null, null, null);
|
||||
Vector<Message> messages = new Vector<Message>();
|
||||
for (int j = 0; j < messageCursor.getCount(); ++j) {
|
||||
messageCursor.moveToPosition(j);
|
||||
idIndex = messageCursor.getColumnIndex("messageId");
|
||||
subjectIndex = messageCursor.getColumnIndex("subject");
|
||||
int fromAddressIndex = messageCursor.getColumnIndex("fromAddress");
|
||||
int replyToIndex = messageCursor.getColumnIndex("replyToAddresses");
|
||||
int bodyIndex = messageCursor.getColumnIndex("body");
|
||||
String data = messageCursor.getString(bodyIndex);
|
||||
data = Html.fromHtml(data).toString();
|
||||
boolean signedOnly = false;
|
||||
Matcher matcher = Apg.PGP_MESSAGE.matcher(data);
|
||||
if (matcher.matches()) {
|
||||
data = matcher.group(1);
|
||||
} else {
|
||||
matcher = Apg.PGP_SIGNED_MESSAGE.matcher(data);
|
||||
if (matcher.matches()) {
|
||||
data = matcher.group(1);
|
||||
signedOnly = true;
|
||||
} else {
|
||||
data = null;
|
||||
}
|
||||
}
|
||||
Message message =
|
||||
new Message(conversation,
|
||||
messageCursor.getLong(idIndex),
|
||||
messageCursor.getString(subjectIndex),
|
||||
messageCursor.getString(fromAddressIndex),
|
||||
messageCursor.getString(replyToIndex),
|
||||
data, signedOnly);
|
||||
|
||||
messages.add(message);
|
||||
mmessages.add(message);
|
||||
}
|
||||
conversation.messages = messages;
|
||||
mconversations.add(conversation);
|
||||
}
|
||||
|
||||
setListAdapter(new MailboxAdapter());
|
||||
getListView().setOnItemClickListener(new OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> arg0, View v, int position, long id) {
|
||||
Intent intent = new Intent(MailListActivity.this, DecryptActivity.class);
|
||||
intent.setAction(Apg.Intent.DECRYPT);
|
||||
Message message = (Message) ((MailboxAdapter) getListAdapter()).getItem(position);
|
||||
intent.putExtra(Apg.EXTRA_TEXT, message.data);
|
||||
intent.putExtra(Apg.EXTRA_SUBJECT, message.subject);
|
||||
intent.putExtra(Apg.EXTRA_REPLY_TO, message.replyTo);
|
||||
startActivity(intent);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private class MailboxAdapter extends BaseAdapter implements ListAdapter {
|
||||
|
||||
@Override
|
||||
public boolean isEnabled(int position) {
|
||||
Message message = (Message) getItem(position);
|
||||
return message.data != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasStableIds() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return mmessages.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItem(int position) {
|
||||
return mmessages.get(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return mmessages.get(position).id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
View view = mInflater.inflate(R.layout.mailbox_message_item, null);
|
||||
|
||||
Message message = (Message) getItem(position);
|
||||
|
||||
TextView subject = (TextView) view.findViewById(R.id.subject);
|
||||
TextView email = (TextView) view.findViewById(R.id.emailAddress);
|
||||
ImageView status = (ImageView) view.findViewById(R.id.ic_status);
|
||||
|
||||
subject.setText(message.subject);
|
||||
email.setText(message.fromAddress);
|
||||
if (message.data != null) {
|
||||
if (message.signedOnly) {
|
||||
status.setImageResource(R.drawable.signed);
|
||||
} else {
|
||||
status.setImageResource(R.drawable.encrypted);
|
||||
}
|
||||
status.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
status.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.thialfihar.android.apg;
|
||||
|
||||
import java.util.Vector;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
import android.app.ListActivity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.text.Html;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.AdapterView.OnItemClickListener;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ListAdapter;
|
||||
import android.widget.TextView;
|
||||
|
||||
public class MailListActivity extends ListActivity {
|
||||
LayoutInflater mInflater = null;
|
||||
|
||||
private static class Conversation {
|
||||
public long id;
|
||||
public String subject;
|
||||
public Vector<Message> messages;
|
||||
|
||||
public Conversation(long id, String subject) {
|
||||
this.id = id;
|
||||
this.subject = subject;
|
||||
}
|
||||
}
|
||||
|
||||
private static class Message {
|
||||
public Conversation parent;
|
||||
public long id;
|
||||
public String subject;
|
||||
public String fromAddress;
|
||||
public String data;
|
||||
public String replyTo;
|
||||
public boolean signedOnly;
|
||||
|
||||
public Message(Conversation parent, long id, String subject,
|
||||
String fromAddress, String replyTo,
|
||||
String data, boolean signedOnly) {
|
||||
this.parent = parent;
|
||||
this.id = id;
|
||||
this.subject = subject;
|
||||
this.fromAddress = fromAddress;
|
||||
this.replyTo = replyTo;
|
||||
this.data = data;
|
||||
if (this.replyTo == null || this.replyTo.equals("")) {
|
||||
this.replyTo = this.fromAddress;
|
||||
}
|
||||
this.signedOnly = signedOnly;
|
||||
}
|
||||
}
|
||||
|
||||
private Vector<Conversation> mconversations;
|
||||
private Vector<Message> mmessages;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
mInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
|
||||
mconversations = new Vector<Conversation>();
|
||||
mmessages = new Vector<Message>();
|
||||
|
||||
String account = getIntent().getExtras().getString(Apg.EXTRA_ACCOUNT);
|
||||
// TODO: what if account is null?
|
||||
Uri uri = Uri.parse("content://gmail-ls/conversations/" + account);
|
||||
Cursor cursor =
|
||||
managedQuery(uri, new String[] { "conversation_id", "subject" }, null, null, null);
|
||||
for (int i = 0; i < cursor.getCount(); ++i) {
|
||||
cursor.moveToPosition(i);
|
||||
|
||||
int idIndex = cursor.getColumnIndex("conversation_id");
|
||||
int subjectIndex = cursor.getColumnIndex("subject");
|
||||
long conversationId = cursor.getLong(idIndex);
|
||||
Conversation conversation =
|
||||
new Conversation(conversationId, cursor.getString(subjectIndex));
|
||||
Uri messageUri = Uri.withAppendedPath(uri, "" + conversationId + "/messages");
|
||||
Cursor messageCursor =
|
||||
managedQuery(messageUri, new String[] {
|
||||
"messageId",
|
||||
"subject",
|
||||
"fromAddress",
|
||||
"replyToAddresses",
|
||||
"body" }, null, null, null);
|
||||
Vector<Message> messages = new Vector<Message>();
|
||||
for (int j = 0; j < messageCursor.getCount(); ++j) {
|
||||
messageCursor.moveToPosition(j);
|
||||
idIndex = messageCursor.getColumnIndex("messageId");
|
||||
subjectIndex = messageCursor.getColumnIndex("subject");
|
||||
int fromAddressIndex = messageCursor.getColumnIndex("fromAddress");
|
||||
int replyToIndex = messageCursor.getColumnIndex("replyToAddresses");
|
||||
int bodyIndex = messageCursor.getColumnIndex("body");
|
||||
String data = messageCursor.getString(bodyIndex);
|
||||
data = Html.fromHtml(data).toString();
|
||||
boolean signedOnly = false;
|
||||
Matcher matcher = Apg.PGP_MESSAGE.matcher(data);
|
||||
if (matcher.matches()) {
|
||||
data = matcher.group(1);
|
||||
} else {
|
||||
matcher = Apg.PGP_SIGNED_MESSAGE.matcher(data);
|
||||
if (matcher.matches()) {
|
||||
data = matcher.group(1);
|
||||
signedOnly = true;
|
||||
} else {
|
||||
data = null;
|
||||
}
|
||||
}
|
||||
Message message =
|
||||
new Message(conversation,
|
||||
messageCursor.getLong(idIndex),
|
||||
messageCursor.getString(subjectIndex),
|
||||
messageCursor.getString(fromAddressIndex),
|
||||
messageCursor.getString(replyToIndex),
|
||||
data, signedOnly);
|
||||
|
||||
messages.add(message);
|
||||
mmessages.add(message);
|
||||
}
|
||||
conversation.messages = messages;
|
||||
mconversations.add(conversation);
|
||||
}
|
||||
|
||||
setListAdapter(new MailboxAdapter());
|
||||
getListView().setOnItemClickListener(new OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> arg0, View v, int position, long id) {
|
||||
Intent intent = new Intent(MailListActivity.this, DecryptActivity.class);
|
||||
intent.setAction(Apg.Intent.DECRYPT);
|
||||
Message message = (Message) ((MailboxAdapter) getListAdapter()).getItem(position);
|
||||
intent.putExtra(Apg.EXTRA_TEXT, message.data);
|
||||
intent.putExtra(Apg.EXTRA_SUBJECT, message.subject);
|
||||
intent.putExtra(Apg.EXTRA_REPLY_TO, message.replyTo);
|
||||
startActivity(intent);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private class MailboxAdapter extends BaseAdapter implements ListAdapter {
|
||||
|
||||
@Override
|
||||
public boolean isEnabled(int position) {
|
||||
Message message = (Message) getItem(position);
|
||||
return message.data != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasStableIds() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return mmessages.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItem(int position) {
|
||||
return mmessages.get(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return mmessages.get(position).id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
View view = mInflater.inflate(R.layout.mailbox_message_item, null);
|
||||
|
||||
Message message = (Message) getItem(position);
|
||||
|
||||
TextView subject = (TextView) view.findViewById(R.id.subject);
|
||||
TextView email = (TextView) view.findViewById(R.id.emailAddress);
|
||||
ImageView status = (ImageView) view.findViewById(R.id.ic_status);
|
||||
|
||||
subject.setText(message.subject);
|
||||
email.setText(message.fromAddress);
|
||||
if (message.data != null) {
|
||||
if (message.signedOnly) {
|
||||
status.setImageResource(R.drawable.signed);
|
||||
} else {
|
||||
status.setImageResource(R.drawable.encrypted);
|
||||
}
|
||||
status.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
status.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,67 +1,67 @@
|
||||
package org.thialfihar.android.apg;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class PositionAwareInputStream extends InputStream {
|
||||
private InputStream mStream;
|
||||
private long mPosition;
|
||||
|
||||
public PositionAwareInputStream(InputStream in) {
|
||||
mStream = in;
|
||||
mPosition = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
int ch = mStream.read();
|
||||
++mPosition;
|
||||
return ch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int available() throws IOException {
|
||||
return mStream.available();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
mStream.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean markSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] b) throws IOException {
|
||||
int result = mStream.read(b);
|
||||
mPosition += result;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] b, int offset, int length) throws IOException {
|
||||
int result = mStream.read(b, offset, length);
|
||||
mPosition += result;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void reset() throws IOException {
|
||||
mStream.reset();
|
||||
mPosition = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long skip(long n) throws IOException {
|
||||
long result = mStream.skip(n);
|
||||
mPosition += result;
|
||||
return result;
|
||||
}
|
||||
|
||||
public long position() {
|
||||
return mPosition;
|
||||
}
|
||||
}
|
||||
package org.thialfihar.android.apg;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class PositionAwareInputStream extends InputStream {
|
||||
private InputStream mStream;
|
||||
private long mPosition;
|
||||
|
||||
public PositionAwareInputStream(InputStream in) {
|
||||
mStream = in;
|
||||
mPosition = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
int ch = mStream.read();
|
||||
++mPosition;
|
||||
return ch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int available() throws IOException {
|
||||
return mStream.available();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
mStream.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean markSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] b) throws IOException {
|
||||
int result = mStream.read(b);
|
||||
mPosition += result;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] b, int offset, int length) throws IOException {
|
||||
int result = mStream.read(b, offset, length);
|
||||
mPosition += result;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void reset() throws IOException {
|
||||
mStream.reset();
|
||||
mPosition = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long skip(long n) throws IOException {
|
||||
long result = mStream.skip(n);
|
||||
mPosition += result;
|
||||
return result;
|
||||
}
|
||||
|
||||
public long position() {
|
||||
return mPosition;
|
||||
}
|
||||
}
|
||||
|
@ -1,180 +1,180 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.thialfihar.android.apg;
|
||||
|
||||
import org.bouncycastle2.bcpg.HashAlgorithmTags;
|
||||
import org.bouncycastle2.openpgp.PGPEncryptedData;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.preference.CheckBoxPreference;
|
||||
import android.preference.Preference;
|
||||
import android.preference.PreferenceActivity;
|
||||
|
||||
public class PreferencesActivity extends PreferenceActivity {
|
||||
private IntegerListPreference mPassPhraseCacheTtl = null;
|
||||
private IntegerListPreference mEncryptionAlgorithm = null;
|
||||
private IntegerListPreference mHashAlgorithm = null;
|
||||
private IntegerListPreference mMessageCompression = null;
|
||||
private IntegerListPreference mFileCompression = null;
|
||||
private CheckBoxPreference mAsciiArmour = null;
|
||||
private Preferences mPreferences;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
mPreferences = Preferences.getPreferences(this);
|
||||
|
||||
addPreferencesFromResource(R.xml.apg_preferences);
|
||||
|
||||
mPassPhraseCacheTtl = (IntegerListPreference) findPreference(Constants.pref.pass_phrase_cache_ttl);
|
||||
mPassPhraseCacheTtl.setValue("" + mPreferences.getPassPhraseCacheTtl());
|
||||
mPassPhraseCacheTtl.setSummary(mPassPhraseCacheTtl.getEntry());
|
||||
mPassPhraseCacheTtl.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener()
|
||||
{
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue)
|
||||
{
|
||||
mPassPhraseCacheTtl.setValue(newValue.toString());
|
||||
mPassPhraseCacheTtl.setSummary(mPassPhraseCacheTtl.getEntry());
|
||||
mPreferences.setPassPhraseCacheTtl(Integer.parseInt(newValue.toString()));
|
||||
BaseActivity.startCacheService(PreferencesActivity.this, mPreferences);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
mEncryptionAlgorithm = (IntegerListPreference) findPreference(Constants.pref.default_encryption_algorithm);
|
||||
int valueIds[] = {
|
||||
PGPEncryptedData.AES_128, PGPEncryptedData.AES_192, PGPEncryptedData.AES_256,
|
||||
PGPEncryptedData.BLOWFISH, PGPEncryptedData.TWOFISH, PGPEncryptedData.CAST5,
|
||||
PGPEncryptedData.DES, PGPEncryptedData.TRIPLE_DES, PGPEncryptedData.IDEA,
|
||||
};
|
||||
String entries[] = {
|
||||
"AES-128", "AES-192", "AES-256",
|
||||
"Blowfish", "Twofish", "CAST5",
|
||||
"DES", "Triple DES", "IDEA",
|
||||
};
|
||||
String values[] = new String[valueIds.length];
|
||||
for (int i = 0; i < values.length; ++i) {
|
||||
values[i] = "" + valueIds[i];
|
||||
}
|
||||
mEncryptionAlgorithm.setEntries(entries);
|
||||
mEncryptionAlgorithm.setEntryValues(values);
|
||||
mEncryptionAlgorithm.setValue("" + mPreferences.getDefaultEncryptionAlgorithm());
|
||||
mEncryptionAlgorithm.setSummary(mEncryptionAlgorithm.getEntry());
|
||||
mEncryptionAlgorithm.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener()
|
||||
{
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue)
|
||||
{
|
||||
mEncryptionAlgorithm.setValue(newValue.toString());
|
||||
mEncryptionAlgorithm.setSummary(mEncryptionAlgorithm.getEntry());
|
||||
mPreferences.setDefaultEncryptionAlgorithm(Integer.parseInt(newValue.toString()));
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
mHashAlgorithm = (IntegerListPreference) findPreference(Constants.pref.default_hash_algorithm);
|
||||
valueIds = new int[] {
|
||||
HashAlgorithmTags.MD5, HashAlgorithmTags.RIPEMD160, HashAlgorithmTags.SHA1,
|
||||
HashAlgorithmTags.SHA224, HashAlgorithmTags.SHA256, HashAlgorithmTags.SHA384,
|
||||
HashAlgorithmTags.SHA512,
|
||||
};
|
||||
entries = new String[] {
|
||||
"MD5", "RIPEMD-160", "SHA-1",
|
||||
"SHA-224", "SHA-256", "SHA-384",
|
||||
"SHA-512",
|
||||
};
|
||||
values = new String[valueIds.length];
|
||||
for (int i = 0; i < values.length; ++i) {
|
||||
values[i] = "" + valueIds[i];
|
||||
}
|
||||
mHashAlgorithm.setEntries(entries);
|
||||
mHashAlgorithm.setEntryValues(values);
|
||||
mHashAlgorithm.setValue("" + mPreferences.getDefaultHashAlgorithm());
|
||||
mHashAlgorithm.setSummary(mHashAlgorithm.getEntry());
|
||||
mHashAlgorithm.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener()
|
||||
{
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue)
|
||||
{
|
||||
mHashAlgorithm.setValue(newValue.toString());
|
||||
mHashAlgorithm.setSummary(mHashAlgorithm.getEntry());
|
||||
mPreferences.setDefaultHashAlgorithm(Integer.parseInt(newValue.toString()));
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
mMessageCompression = (IntegerListPreference) findPreference(Constants.pref.default_message_compression);
|
||||
valueIds = new int[] {
|
||||
Id.choice.compression.none,
|
||||
Id.choice.compression.zip,
|
||||
Id.choice.compression.zlib,
|
||||
Id.choice.compression.bzip2,
|
||||
};
|
||||
entries = new String[] {
|
||||
getString(R.string.choice_none) + " (" + getString(R.string.fast) + ")",
|
||||
"ZIP (" + getString(R.string.fast) + ")",
|
||||
"ZLIB (" + getString(R.string.fast) + ")",
|
||||
"BZIP2 (" + getString(R.string.very_slow) + ")",
|
||||
};
|
||||
values = new String[valueIds.length];
|
||||
for (int i = 0; i < values.length; ++i) {
|
||||
values[i] = "" + valueIds[i];
|
||||
}
|
||||
mMessageCompression.setEntries(entries);
|
||||
mMessageCompression.setEntryValues(values);
|
||||
mMessageCompression.setValue("" + mPreferences.getDefaultMessageCompression());
|
||||
mMessageCompression.setSummary(mMessageCompression.getEntry());
|
||||
mMessageCompression.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener()
|
||||
{
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue)
|
||||
{
|
||||
mMessageCompression.setValue(newValue.toString());
|
||||
mMessageCompression.setSummary(mMessageCompression.getEntry());
|
||||
mPreferences.setDefaultMessageCompression(Integer.parseInt(newValue.toString()));
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
mFileCompression = (IntegerListPreference) findPreference(Constants.pref.default_file_compression);
|
||||
mFileCompression.setEntries(entries);
|
||||
mFileCompression.setEntryValues(values);
|
||||
mFileCompression.setValue("" + mPreferences.getDefaultFileCompression());
|
||||
mFileCompression.setSummary(mFileCompression.getEntry());
|
||||
mFileCompression.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener()
|
||||
{
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue)
|
||||
{
|
||||
mFileCompression.setValue(newValue.toString());
|
||||
mFileCompression.setSummary(mFileCompression.getEntry());
|
||||
mPreferences.setDefaultFileCompression(Integer.parseInt(newValue.toString()));
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
mAsciiArmour = (CheckBoxPreference) findPreference(Constants.pref.default_ascii_armour);
|
||||
mAsciiArmour.setChecked(mPreferences.getDefaultAsciiArmour());
|
||||
mAsciiArmour.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener()
|
||||
{
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue)
|
||||
{
|
||||
mAsciiArmour.setChecked((Boolean)newValue);
|
||||
mPreferences.setDefaultAsciiArmour((Boolean)newValue);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.thialfihar.android.apg;
|
||||
|
||||
import org.bouncycastle2.bcpg.HashAlgorithmTags;
|
||||
import org.bouncycastle2.openpgp.PGPEncryptedData;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.preference.CheckBoxPreference;
|
||||
import android.preference.Preference;
|
||||
import android.preference.PreferenceActivity;
|
||||
|
||||
public class PreferencesActivity extends PreferenceActivity {
|
||||
private IntegerListPreference mPassPhraseCacheTtl = null;
|
||||
private IntegerListPreference mEncryptionAlgorithm = null;
|
||||
private IntegerListPreference mHashAlgorithm = null;
|
||||
private IntegerListPreference mMessageCompression = null;
|
||||
private IntegerListPreference mFileCompression = null;
|
||||
private CheckBoxPreference mAsciiArmour = null;
|
||||
private Preferences mPreferences;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
mPreferences = Preferences.getPreferences(this);
|
||||
|
||||
addPreferencesFromResource(R.xml.apg_preferences);
|
||||
|
||||
mPassPhraseCacheTtl = (IntegerListPreference) findPreference(Constants.pref.pass_phrase_cache_ttl);
|
||||
mPassPhraseCacheTtl.setValue("" + mPreferences.getPassPhraseCacheTtl());
|
||||
mPassPhraseCacheTtl.setSummary(mPassPhraseCacheTtl.getEntry());
|
||||
mPassPhraseCacheTtl.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener()
|
||||
{
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue)
|
||||
{
|
||||
mPassPhraseCacheTtl.setValue(newValue.toString());
|
||||
mPassPhraseCacheTtl.setSummary(mPassPhraseCacheTtl.getEntry());
|
||||
mPreferences.setPassPhraseCacheTtl(Integer.parseInt(newValue.toString()));
|
||||
BaseActivity.startCacheService(PreferencesActivity.this, mPreferences);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
mEncryptionAlgorithm = (IntegerListPreference) findPreference(Constants.pref.default_encryption_algorithm);
|
||||
int valueIds[] = {
|
||||
PGPEncryptedData.AES_128, PGPEncryptedData.AES_192, PGPEncryptedData.AES_256,
|
||||
PGPEncryptedData.BLOWFISH, PGPEncryptedData.TWOFISH, PGPEncryptedData.CAST5,
|
||||
PGPEncryptedData.DES, PGPEncryptedData.TRIPLE_DES, PGPEncryptedData.IDEA,
|
||||
};
|
||||
String entries[] = {
|
||||
"AES-128", "AES-192", "AES-256",
|
||||
"Blowfish", "Twofish", "CAST5",
|
||||
"DES", "Triple DES", "IDEA",
|
||||
};
|
||||
String values[] = new String[valueIds.length];
|
||||
for (int i = 0; i < values.length; ++i) {
|
||||
values[i] = "" + valueIds[i];
|
||||
}
|
||||
mEncryptionAlgorithm.setEntries(entries);
|
||||
mEncryptionAlgorithm.setEntryValues(values);
|
||||
mEncryptionAlgorithm.setValue("" + mPreferences.getDefaultEncryptionAlgorithm());
|
||||
mEncryptionAlgorithm.setSummary(mEncryptionAlgorithm.getEntry());
|
||||
mEncryptionAlgorithm.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener()
|
||||
{
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue)
|
||||
{
|
||||
mEncryptionAlgorithm.setValue(newValue.toString());
|
||||
mEncryptionAlgorithm.setSummary(mEncryptionAlgorithm.getEntry());
|
||||
mPreferences.setDefaultEncryptionAlgorithm(Integer.parseInt(newValue.toString()));
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
mHashAlgorithm = (IntegerListPreference) findPreference(Constants.pref.default_hash_algorithm);
|
||||
valueIds = new int[] {
|
||||
HashAlgorithmTags.MD5, HashAlgorithmTags.RIPEMD160, HashAlgorithmTags.SHA1,
|
||||
HashAlgorithmTags.SHA224, HashAlgorithmTags.SHA256, HashAlgorithmTags.SHA384,
|
||||
HashAlgorithmTags.SHA512,
|
||||
};
|
||||
entries = new String[] {
|
||||
"MD5", "RIPEMD-160", "SHA-1",
|
||||
"SHA-224", "SHA-256", "SHA-384",
|
||||
"SHA-512",
|
||||
};
|
||||
values = new String[valueIds.length];
|
||||
for (int i = 0; i < values.length; ++i) {
|
||||
values[i] = "" + valueIds[i];
|
||||
}
|
||||
mHashAlgorithm.setEntries(entries);
|
||||
mHashAlgorithm.setEntryValues(values);
|
||||
mHashAlgorithm.setValue("" + mPreferences.getDefaultHashAlgorithm());
|
||||
mHashAlgorithm.setSummary(mHashAlgorithm.getEntry());
|
||||
mHashAlgorithm.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener()
|
||||
{
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue)
|
||||
{
|
||||
mHashAlgorithm.setValue(newValue.toString());
|
||||
mHashAlgorithm.setSummary(mHashAlgorithm.getEntry());
|
||||
mPreferences.setDefaultHashAlgorithm(Integer.parseInt(newValue.toString()));
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
mMessageCompression = (IntegerListPreference) findPreference(Constants.pref.default_message_compression);
|
||||
valueIds = new int[] {
|
||||
Id.choice.compression.none,
|
||||
Id.choice.compression.zip,
|
||||
Id.choice.compression.zlib,
|
||||
Id.choice.compression.bzip2,
|
||||
};
|
||||
entries = new String[] {
|
||||
getString(R.string.choice_none) + " (" + getString(R.string.fast) + ")",
|
||||
"ZIP (" + getString(R.string.fast) + ")",
|
||||
"ZLIB (" + getString(R.string.fast) + ")",
|
||||
"BZIP2 (" + getString(R.string.very_slow) + ")",
|
||||
};
|
||||
values = new String[valueIds.length];
|
||||
for (int i = 0; i < values.length; ++i) {
|
||||
values[i] = "" + valueIds[i];
|
||||
}
|
||||
mMessageCompression.setEntries(entries);
|
||||
mMessageCompression.setEntryValues(values);
|
||||
mMessageCompression.setValue("" + mPreferences.getDefaultMessageCompression());
|
||||
mMessageCompression.setSummary(mMessageCompression.getEntry());
|
||||
mMessageCompression.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener()
|
||||
{
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue)
|
||||
{
|
||||
mMessageCompression.setValue(newValue.toString());
|
||||
mMessageCompression.setSummary(mMessageCompression.getEntry());
|
||||
mPreferences.setDefaultMessageCompression(Integer.parseInt(newValue.toString()));
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
mFileCompression = (IntegerListPreference) findPreference(Constants.pref.default_file_compression);
|
||||
mFileCompression.setEntries(entries);
|
||||
mFileCompression.setEntryValues(values);
|
||||
mFileCompression.setValue("" + mPreferences.getDefaultFileCompression());
|
||||
mFileCompression.setSummary(mFileCompression.getEntry());
|
||||
mFileCompression.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener()
|
||||
{
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue)
|
||||
{
|
||||
mFileCompression.setValue(newValue.toString());
|
||||
mFileCompression.setSummary(mFileCompression.getEntry());
|
||||
mPreferences.setDefaultFileCompression(Integer.parseInt(newValue.toString()));
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
mAsciiArmour = (CheckBoxPreference) findPreference(Constants.pref.default_ascii_armour);
|
||||
mAsciiArmour.setChecked(mPreferences.getDefaultAsciiArmour());
|
||||
mAsciiArmour.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener()
|
||||
{
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue)
|
||||
{
|
||||
mAsciiArmour.setChecked((Boolean)newValue);
|
||||
mPreferences.setDefaultAsciiArmour((Boolean)newValue);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,185 +1,185 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.thialfihar.android.apg;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public final class Primes {
|
||||
// taken from http://www.ietf.org/rfc/rfc3526.txt
|
||||
public static final String P1536 =
|
||||
"FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
|
||||
"29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
|
||||
"EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
|
||||
"E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
|
||||
"EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
|
||||
"C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
|
||||
"83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
|
||||
"670C354E 4ABC9804 F1746C08 CA237327 FFFFFFFF FFFFFFFF";
|
||||
|
||||
public static final String P2048 =
|
||||
"FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
|
||||
"29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
|
||||
"EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
|
||||
"E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
|
||||
"EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
|
||||
"C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
|
||||
"83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
|
||||
"670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
|
||||
"E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
|
||||
"DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
|
||||
"15728E5A 8AACAA68 FFFFFFFF FFFFFFFF";
|
||||
|
||||
public static final String P3072 =
|
||||
"FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
|
||||
"29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
|
||||
"EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
|
||||
"E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
|
||||
"EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
|
||||
"C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
|
||||
"83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
|
||||
"670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
|
||||
"E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
|
||||
"DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
|
||||
"15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" +
|
||||
"ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" +
|
||||
"ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" +
|
||||
"F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" +
|
||||
"BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" +
|
||||
"43DB5BFC E0FD108E 4B82D120 A93AD2CA FFFFFFFF FFFFFFFF";
|
||||
|
||||
public static final String P4096 =
|
||||
"FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
|
||||
"29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
|
||||
"EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
|
||||
"E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
|
||||
"EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
|
||||
"C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
|
||||
"83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
|
||||
"670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
|
||||
"E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
|
||||
"DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
|
||||
"15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" +
|
||||
"ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" +
|
||||
"ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" +
|
||||
"F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" +
|
||||
"BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" +
|
||||
"43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" +
|
||||
"88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" +
|
||||
"2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" +
|
||||
"287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" +
|
||||
"1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" +
|
||||
"93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34063199" +
|
||||
"FFFFFFFF FFFFFFFF";
|
||||
|
||||
public static final String P6144 =
|
||||
"FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
|
||||
"29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
|
||||
"EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
|
||||
"E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
|
||||
"EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
|
||||
"C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
|
||||
"83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
|
||||
"670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
|
||||
"E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
|
||||
"DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
|
||||
"15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" +
|
||||
"ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" +
|
||||
"ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" +
|
||||
"F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" +
|
||||
"BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" +
|
||||
"43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" +
|
||||
"88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" +
|
||||
"2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" +
|
||||
"287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" +
|
||||
"1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" +
|
||||
"93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34028492" +
|
||||
"36C3FAB4 D27C7026 C1D4DCB2 602646DE C9751E76 3DBA37BD" +
|
||||
"F8FF9406 AD9E530E E5DB382F 413001AE B06A53ED 9027D831" +
|
||||
"179727B0 865A8918 DA3EDBEB CF9B14ED 44CE6CBA CED4BB1B" +
|
||||
"DB7F1447 E6CC254B 33205151 2BD7AF42 6FB8F401 378CD2BF" +
|
||||
"5983CA01 C64B92EC F032EA15 D1721D03 F482D7CE 6E74FEF6" +
|
||||
"D55E702F 46980C82 B5A84031 900B1C9E 59E7C97F BEC7E8F3" +
|
||||
"23A97A7E 36CC88BE 0F1D45B7 FF585AC5 4BD407B2 2B4154AA" +
|
||||
"CC8F6D7E BF48E1D8 14CC5ED2 0F8037E0 A79715EE F29BE328" +
|
||||
"06A1D58B B7C5DA76 F550AA3D 8A1FBFF0 EB19CCB1 A313D55C" +
|
||||
"DA56C9EC 2EF29632 387FE8D7 6E3C0468 043E8F66 3F4860EE" +
|
||||
"12BF2D5B 0B7474D6 E694F91E 6DCC4024 FFFFFFFF FFFFFFFF";
|
||||
|
||||
public static final String P8192 =
|
||||
"FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
|
||||
"29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
|
||||
"EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
|
||||
"E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
|
||||
"EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
|
||||
"C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
|
||||
"83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
|
||||
"670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
|
||||
"E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
|
||||
"DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
|
||||
"15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" +
|
||||
"ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" +
|
||||
"ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" +
|
||||
"F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" +
|
||||
"BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" +
|
||||
"43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" +
|
||||
"88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" +
|
||||
"2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" +
|
||||
"287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" +
|
||||
"1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" +
|
||||
"93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34028492" +
|
||||
"36C3FAB4 D27C7026 C1D4DCB2 602646DE C9751E76 3DBA37BD" +
|
||||
"F8FF9406 AD9E530E E5DB382F 413001AE B06A53ED 9027D831" +
|
||||
"179727B0 865A8918 DA3EDBEB CF9B14ED 44CE6CBA CED4BB1B" +
|
||||
"DB7F1447 E6CC254B 33205151 2BD7AF42 6FB8F401 378CD2BF" +
|
||||
"5983CA01 C64B92EC F032EA15 D1721D03 F482D7CE 6E74FEF6" +
|
||||
"D55E702F 46980C82 B5A84031 900B1C9E 59E7C97F BEC7E8F3" +
|
||||
"23A97A7E 36CC88BE 0F1D45B7 FF585AC5 4BD407B2 2B4154AA" +
|
||||
"CC8F6D7E BF48E1D8 14CC5ED2 0F8037E0 A79715EE F29BE328" +
|
||||
"06A1D58B B7C5DA76 F550AA3D 8A1FBFF0 EB19CCB1 A313D55C" +
|
||||
"DA56C9EC 2EF29632 387FE8D7 6E3C0468 043E8F66 3F4860EE" +
|
||||
"12BF2D5B 0B7474D6 E694F91E 6DBE1159 74A3926F 12FEE5E4" +
|
||||
"38777CB6 A932DF8C D8BEC4D0 73B931BA 3BC832B6 8D9DD300" +
|
||||
"741FA7BF 8AFC47ED 2576F693 6BA42466 3AAB639C 5AE4F568" +
|
||||
"3423B474 2BF1C978 238F16CB E39D652D E3FDB8BE FC848AD9" +
|
||||
"22222E04 A4037C07 13EB57A8 1A23F0C7 3473FC64 6CEA306B" +
|
||||
"4BCBC886 2F8385DD FA9D4B7F A2C087E8 79683303 ED5BDD3A" +
|
||||
"062B3CF5 B3A278A6 6D2A13F8 3F44F82D DF310EE0 74AB6A36" +
|
||||
"4597E899 A0255DC1 64F31CC5 0846851D F9AB4819 5DED7EA1" +
|
||||
"B1D510BD 7EE74D73 FAF36BC3 1ECFA268 359046F4 EB879F92" +
|
||||
"4009438B 481C6CD7 889A002E D5EE382B C9190DA6 FC026E47" +
|
||||
"9558E447 5677E9AA 9E3050E2 765694DF C81F56E8 80B96E71" +
|
||||
"60C980DD 98EDD3DF FFFFFFFF FFFFFFFF";
|
||||
|
||||
public static BigInteger getBestPrime(int keySize) {
|
||||
String primeString;
|
||||
if (keySize >= (8192 + 6144) / 2) {
|
||||
primeString = P8192;
|
||||
} else if (keySize >= (6144 + 4096) / 2) {
|
||||
primeString = P6144;
|
||||
} else if (keySize >= (4096 + 3072) / 2) {
|
||||
primeString = P4096;
|
||||
} else if (keySize >= (3072 + 2048) / 2) {
|
||||
primeString = P3072;
|
||||
} else if (keySize >= (2048 + 1536) / 2) {
|
||||
primeString = P2048;
|
||||
} else {
|
||||
primeString = P1536;
|
||||
}
|
||||
|
||||
return new BigInteger(primeString.replaceAll(" ", ""), 16);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.thialfihar.android.apg;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public final class Primes {
|
||||
// taken from http://www.ietf.org/rfc/rfc3526.txt
|
||||
public static final String P1536 =
|
||||
"FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
|
||||
"29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
|
||||
"EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
|
||||
"E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
|
||||
"EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
|
||||
"C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
|
||||
"83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
|
||||
"670C354E 4ABC9804 F1746C08 CA237327 FFFFFFFF FFFFFFFF";
|
||||
|
||||
public static final String P2048 =
|
||||
"FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
|
||||
"29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
|
||||
"EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
|
||||
"E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
|
||||
"EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
|
||||
"C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
|
||||
"83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
|
||||
"670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
|
||||
"E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
|
||||
"DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
|
||||
"15728E5A 8AACAA68 FFFFFFFF FFFFFFFF";
|
||||
|
||||
public static final String P3072 =
|
||||
"FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
|
||||
"29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
|
||||
"EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
|
||||
"E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
|
||||
"EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
|
||||
"C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
|
||||
"83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
|
||||
"670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
|
||||
"E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
|
||||
"DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
|
||||
"15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" +
|
||||
"ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" +
|
||||
"ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" +
|
||||
"F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" +
|
||||
"BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" +
|
||||
"43DB5BFC E0FD108E 4B82D120 A93AD2CA FFFFFFFF FFFFFFFF";
|
||||
|
||||
public static final String P4096 =
|
||||
"FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
|
||||
"29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
|
||||
"EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
|
||||
"E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
|
||||
"EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
|
||||
"C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
|
||||
"83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
|
||||
"670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
|
||||
"E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
|
||||
"DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
|
||||
"15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" +
|
||||
"ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" +
|
||||
"ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" +
|
||||
"F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" +
|
||||
"BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" +
|
||||
"43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" +
|
||||
"88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" +
|
||||
"2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" +
|
||||
"287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" +
|
||||
"1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" +
|
||||
"93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34063199" +
|
||||
"FFFFFFFF FFFFFFFF";
|
||||
|
||||
public static final String P6144 =
|
||||
"FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
|
||||
"29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
|
||||
"EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
|
||||
"E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
|
||||
"EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
|
||||
"C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
|
||||
"83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
|
||||
"670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
|
||||
"E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
|
||||
"DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
|
||||
"15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" +
|
||||
"ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" +
|
||||
"ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" +
|
||||
"F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" +
|
||||
"BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" +
|
||||
"43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" +
|
||||
"88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" +
|
||||
"2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" +
|
||||
"287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" +
|
||||
"1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" +
|
||||
"93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34028492" +
|
||||
"36C3FAB4 D27C7026 C1D4DCB2 602646DE C9751E76 3DBA37BD" +
|
||||
"F8FF9406 AD9E530E E5DB382F 413001AE B06A53ED 9027D831" +
|
||||
"179727B0 865A8918 DA3EDBEB CF9B14ED 44CE6CBA CED4BB1B" +
|
||||
"DB7F1447 E6CC254B 33205151 2BD7AF42 6FB8F401 378CD2BF" +
|
||||
"5983CA01 C64B92EC F032EA15 D1721D03 F482D7CE 6E74FEF6" +
|
||||
"D55E702F 46980C82 B5A84031 900B1C9E 59E7C97F BEC7E8F3" +
|
||||
"23A97A7E 36CC88BE 0F1D45B7 FF585AC5 4BD407B2 2B4154AA" +
|
||||
"CC8F6D7E BF48E1D8 14CC5ED2 0F8037E0 A79715EE F29BE328" +
|
||||
"06A1D58B B7C5DA76 F550AA3D 8A1FBFF0 EB19CCB1 A313D55C" +
|
||||
"DA56C9EC 2EF29632 387FE8D7 6E3C0468 043E8F66 3F4860EE" +
|
||||
"12BF2D5B 0B7474D6 E694F91E 6DCC4024 FFFFFFFF FFFFFFFF";
|
||||
|
||||
public static final String P8192 =
|
||||
"FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
|
||||
"29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
|
||||
"EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
|
||||
"E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
|
||||
"EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
|
||||
"C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
|
||||
"83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
|
||||
"670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
|
||||
"E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
|
||||
"DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
|
||||
"15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" +
|
||||
"ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" +
|
||||
"ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" +
|
||||
"F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" +
|
||||
"BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" +
|
||||
"43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" +
|
||||
"88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" +
|
||||
"2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" +
|
||||
"287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" +
|
||||
"1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" +
|
||||
"93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34028492" +
|
||||
"36C3FAB4 D27C7026 C1D4DCB2 602646DE C9751E76 3DBA37BD" +
|
||||
"F8FF9406 AD9E530E E5DB382F 413001AE B06A53ED 9027D831" +
|
||||
"179727B0 865A8918 DA3EDBEB CF9B14ED 44CE6CBA CED4BB1B" +
|
||||
"DB7F1447 E6CC254B 33205151 2BD7AF42 6FB8F401 378CD2BF" +
|
||||
"5983CA01 C64B92EC F032EA15 D1721D03 F482D7CE 6E74FEF6" +
|
||||
"D55E702F 46980C82 B5A84031 900B1C9E 59E7C97F BEC7E8F3" +
|
||||
"23A97A7E 36CC88BE 0F1D45B7 FF585AC5 4BD407B2 2B4154AA" +
|
||||
"CC8F6D7E BF48E1D8 14CC5ED2 0F8037E0 A79715EE F29BE328" +
|
||||
"06A1D58B B7C5DA76 F550AA3D 8A1FBFF0 EB19CCB1 A313D55C" +
|
||||
"DA56C9EC 2EF29632 387FE8D7 6E3C0468 043E8F66 3F4860EE" +
|
||||
"12BF2D5B 0B7474D6 E694F91E 6DBE1159 74A3926F 12FEE5E4" +
|
||||
"38777CB6 A932DF8C D8BEC4D0 73B931BA 3BC832B6 8D9DD300" +
|
||||
"741FA7BF 8AFC47ED 2576F693 6BA42466 3AAB639C 5AE4F568" +
|
||||
"3423B474 2BF1C978 238F16CB E39D652D E3FDB8BE FC848AD9" +
|
||||
"22222E04 A4037C07 13EB57A8 1A23F0C7 3473FC64 6CEA306B" +
|
||||
"4BCBC886 2F8385DD FA9D4B7F A2C087E8 79683303 ED5BDD3A" +
|
||||
"062B3CF5 B3A278A6 6D2A13F8 3F44F82D DF310EE0 74AB6A36" +
|
||||
"4597E899 A0255DC1 64F31CC5 0846851D F9AB4819 5DED7EA1" +
|
||||
"B1D510BD 7EE74D73 FAF36BC3 1ECFA268 359046F4 EB879F92" +
|
||||
"4009438B 481C6CD7 889A002E D5EE382B C9190DA6 FC026E47" +
|
||||
"9558E447 5677E9AA 9E3050E2 765694DF C81F56E8 80B96E71" +
|
||||
"60C980DD 98EDD3DF FFFFFFFF FFFFFFFF";
|
||||
|
||||
public static BigInteger getBestPrime(int keySize) {
|
||||
String primeString;
|
||||
if (keySize >= (8192 + 6144) / 2) {
|
||||
primeString = P8192;
|
||||
} else if (keySize >= (6144 + 4096) / 2) {
|
||||
primeString = P6144;
|
||||
} else if (keySize >= (4096 + 3072) / 2) {
|
||||
primeString = P4096;
|
||||
} else if (keySize >= (3072 + 2048) / 2) {
|
||||
primeString = P3072;
|
||||
} else if (keySize >= (2048 + 1536) / 2) {
|
||||
primeString = P2048;
|
||||
} else {
|
||||
primeString = P1536;
|
||||
}
|
||||
|
||||
return new BigInteger(primeString.replaceAll(" ", ""), 16);
|
||||
}
|
||||
}
|
||||
|
@ -1,23 +1,23 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.thialfihar.android.apg;
|
||||
|
||||
public interface ProgressDialogUpdater {
|
||||
void setProgress(String message, int current, int total);
|
||||
void setProgress(int resourceId, int current, int total);
|
||||
void setProgress(int current, int total);
|
||||
}
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.thialfihar.android.apg;
|
||||
|
||||
public interface ProgressDialogUpdater {
|
||||
void setProgress(String message, int current, int total);
|
||||
void setProgress(int resourceId, int current, int total);
|
||||
void setProgress(int current, int total);
|
||||
}
|
||||
|
@ -1,62 +1,62 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.thialfihar.android.apg;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.view.Menu;
|
||||
import android.view.View;
|
||||
import android.widget.ExpandableListView;
|
||||
|
||||
public class PublicKeyListActivity extends KeyListActivity {
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
mExportFilename = Constants.path.app_dir + "/pubexport.asc";
|
||||
mKeyType = Id.type.public_key;
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
menu.add(0, Id.menu.option.import_keys, 0, R.string.menu_importKeys)
|
||||
.setIcon(android.R.drawable.ic_menu_add);
|
||||
menu.add(0, Id.menu.option.export_keys, 1, R.string.menu_exportKeys)
|
||||
.setIcon(android.R.drawable.ic_menu_save);
|
||||
menu.add(1, Id.menu.option.search, 2, R.string.menu_search)
|
||||
.setIcon(android.R.drawable.ic_menu_search);
|
||||
menu.add(1, Id.menu.option.preferences, 3, R.string.menu_preferences)
|
||||
.setIcon(android.R.drawable.ic_menu_preferences);
|
||||
menu.add(1, Id.menu.option.about, 4, R.string.menu_about)
|
||||
.setIcon(android.R.drawable.ic_menu_info_details);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
|
||||
super.onCreateContextMenu(menu, v, menuInfo);
|
||||
ExpandableListView.ExpandableListContextMenuInfo info =
|
||||
(ExpandableListView.ExpandableListContextMenuInfo) menuInfo;
|
||||
int type = ExpandableListView.getPackedPositionType(info.packedPosition);
|
||||
|
||||
if (type == ExpandableListView.PACKED_POSITION_TYPE_GROUP) {
|
||||
// TODO: user id? menu.setHeaderTitle("Key");
|
||||
menu.add(0, Id.menu.export, 0, R.string.menu_exportKey);
|
||||
menu.add(0, Id.menu.delete, 1, R.string.menu_deleteKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.thialfihar.android.apg;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.view.Menu;
|
||||
import android.view.View;
|
||||
import android.widget.ExpandableListView;
|
||||
|
||||
public class PublicKeyListActivity extends KeyListActivity {
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
mExportFilename = Constants.path.app_dir + "/pubexport.asc";
|
||||
mKeyType = Id.type.public_key;
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
menu.add(0, Id.menu.option.import_keys, 0, R.string.menu_importKeys)
|
||||
.setIcon(android.R.drawable.ic_menu_add);
|
||||
menu.add(0, Id.menu.option.export_keys, 1, R.string.menu_exportKeys)
|
||||
.setIcon(android.R.drawable.ic_menu_save);
|
||||
menu.add(1, Id.menu.option.search, 2, R.string.menu_search)
|
||||
.setIcon(android.R.drawable.ic_menu_search);
|
||||
menu.add(1, Id.menu.option.preferences, 3, R.string.menu_preferences)
|
||||
.setIcon(android.R.drawable.ic_menu_preferences);
|
||||
menu.add(1, Id.menu.option.about, 4, R.string.menu_about)
|
||||
.setIcon(android.R.drawable.ic_menu_info_details);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
|
||||
super.onCreateContextMenu(menu, v, menuInfo);
|
||||
ExpandableListView.ExpandableListContextMenuInfo info =
|
||||
(ExpandableListView.ExpandableListContextMenuInfo) menuInfo;
|
||||
int type = ExpandableListView.getPackedPositionType(info.packedPosition);
|
||||
|
||||
if (type == ExpandableListView.PACKED_POSITION_TYPE_GROUP) {
|
||||
// TODO: user id? menu.setHeaderTitle("Key");
|
||||
menu.add(0, Id.menu.export, 0, R.string.menu_exportKey);
|
||||
menu.add(0, Id.menu.delete, 1, R.string.menu_deleteKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,180 +1,180 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.thialfihar.android.apg;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.ExpandableListView;
|
||||
import android.widget.ExpandableListView.ExpandableListContextMenuInfo;
|
||||
import android.widget.ExpandableListView.OnChildClickListener;
|
||||
|
||||
public class SecretKeyListActivity extends KeyListActivity implements OnChildClickListener {
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
mExportFilename = Constants.path.app_dir + "/secexport.asc";
|
||||
mKeyType = Id.type.secret_key;
|
||||
super.onCreate(savedInstanceState);
|
||||
mList.setOnChildClickListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
menu.add(0, Id.menu.option.import_keys, 0, R.string.menu_importKeys)
|
||||
.setIcon(android.R.drawable.ic_menu_add);
|
||||
menu.add(0, Id.menu.option.export_keys, 1, R.string.menu_exportKeys)
|
||||
.setIcon(android.R.drawable.ic_menu_save);
|
||||
menu.add(1, Id.menu.option.create, 2, R.string.menu_createKey)
|
||||
.setIcon(android.R.drawable.ic_menu_add);
|
||||
menu.add(3, Id.menu.option.search, 3, R.string.menu_search)
|
||||
.setIcon(android.R.drawable.ic_menu_search);
|
||||
menu.add(3, Id.menu.option.preferences, 4, R.string.menu_preferences)
|
||||
.setIcon(android.R.drawable.ic_menu_preferences);
|
||||
menu.add(3, Id.menu.option.about, 5, R.string.menu_about)
|
||||
.setIcon(android.R.drawable.ic_menu_info_details);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case Id.menu.option.create: {
|
||||
createKey();
|
||||
return true;
|
||||
}
|
||||
|
||||
default: {
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
|
||||
super.onCreateContextMenu(menu, v, menuInfo);
|
||||
ExpandableListView.ExpandableListContextMenuInfo info =
|
||||
(ExpandableListView.ExpandableListContextMenuInfo) menuInfo;
|
||||
int type = ExpandableListView.getPackedPositionType(info.packedPosition);
|
||||
|
||||
if (type == ExpandableListView.PACKED_POSITION_TYPE_GROUP) {
|
||||
// TODO: user id? menu.setHeaderTitle("Key");
|
||||
menu.add(0, Id.menu.edit, 0, R.string.menu_editKey);
|
||||
menu.add(0, Id.menu.export, 1, R.string.menu_exportKey);
|
||||
menu.add(0, Id.menu.delete, 2, R.string.menu_deleteKey);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onContextItemSelected(MenuItem menuItem) {
|
||||
ExpandableListContextMenuInfo info = (ExpandableListContextMenuInfo) menuItem.getMenuInfo();
|
||||
int type = ExpandableListView.getPackedPositionType(info.packedPosition);
|
||||
int groupPosition = ExpandableListView.getPackedPositionGroup(info.packedPosition);
|
||||
|
||||
if (type != ExpandableListView.PACKED_POSITION_TYPE_GROUP) {
|
||||
return super.onContextItemSelected(menuItem);
|
||||
}
|
||||
|
||||
switch (menuItem.getItemId()) {
|
||||
case Id.menu.edit: {
|
||||
mSelectedItem = groupPosition;
|
||||
checkPassPhraseAndEdit();
|
||||
return true;
|
||||
}
|
||||
|
||||
default: {
|
||||
return super.onContextItemSelected(menuItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onChildClick(ExpandableListView parent, View v, int groupPosition,
|
||||
int childPosition, long id) {
|
||||
mSelectedItem = groupPosition;
|
||||
checkPassPhraseAndEdit();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Dialog onCreateDialog(int id) {
|
||||
switch (id) {
|
||||
case Id.dialog.pass_phrase: {
|
||||
long keyId = ((KeyListAdapter) mList.getExpandableListAdapter()).getGroupId(mSelectedItem);
|
||||
return AskForSecretKeyPassPhrase.createDialog(this, keyId, this);
|
||||
}
|
||||
|
||||
default: {
|
||||
return super.onCreateDialog(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void checkPassPhraseAndEdit() {
|
||||
long keyId = ((KeyListAdapter) mList.getExpandableListAdapter()).getGroupId(mSelectedItem);
|
||||
String passPhrase = Apg.getCachedPassPhrase(keyId);
|
||||
if (passPhrase == null) {
|
||||
showDialog(Id.dialog.pass_phrase);
|
||||
} else {
|
||||
Apg.setEditPassPhrase(passPhrase);
|
||||
editKey();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void passPhraseCallback(long keyId, String passPhrase) {
|
||||
super.passPhraseCallback(keyId, passPhrase);
|
||||
Apg.setEditPassPhrase(passPhrase);
|
||||
editKey();
|
||||
}
|
||||
|
||||
private void createKey() {
|
||||
Apg.setEditPassPhrase("");
|
||||
Intent intent = new Intent(this, EditKeyActivity.class);
|
||||
startActivityForResult(intent, Id.message.create_key);
|
||||
}
|
||||
|
||||
private void editKey() {
|
||||
long keyId = ((KeyListAdapter) mList.getExpandableListAdapter()).getGroupId(mSelectedItem);
|
||||
Intent intent = new Intent(this, EditKeyActivity.class);
|
||||
intent.putExtra(Apg.EXTRA_KEY_ID, keyId);
|
||||
startActivityForResult(intent, Id.message.edit_key);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
switch (requestCode) {
|
||||
case Id.message.create_key: // intentionally no break
|
||||
case Id.message.edit_key: {
|
||||
if (resultCode == RESULT_OK) {
|
||||
refreshList();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.thialfihar.android.apg;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.ExpandableListView;
|
||||
import android.widget.ExpandableListView.ExpandableListContextMenuInfo;
|
||||
import android.widget.ExpandableListView.OnChildClickListener;
|
||||
|
||||
public class SecretKeyListActivity extends KeyListActivity implements OnChildClickListener {
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
mExportFilename = Constants.path.app_dir + "/secexport.asc";
|
||||
mKeyType = Id.type.secret_key;
|
||||
super.onCreate(savedInstanceState);
|
||||
mList.setOnChildClickListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
menu.add(0, Id.menu.option.import_keys, 0, R.string.menu_importKeys)
|
||||
.setIcon(android.R.drawable.ic_menu_add);
|
||||
menu.add(0, Id.menu.option.export_keys, 1, R.string.menu_exportKeys)
|
||||
.setIcon(android.R.drawable.ic_menu_save);
|
||||
menu.add(1, Id.menu.option.create, 2, R.string.menu_createKey)
|
||||
.setIcon(android.R.drawable.ic_menu_add);
|
||||
menu.add(3, Id.menu.option.search, 3, R.string.menu_search)
|
||||
.setIcon(android.R.drawable.ic_menu_search);
|
||||
menu.add(3, Id.menu.option.preferences, 4, R.string.menu_preferences)
|
||||
.setIcon(android.R.drawable.ic_menu_preferences);
|
||||
menu.add(3, Id.menu.option.about, 5, R.string.menu_about)
|
||||
.setIcon(android.R.drawable.ic_menu_info_details);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case Id.menu.option.create: {
|
||||
createKey();
|
||||
return true;
|
||||
}
|
||||
|
||||
default: {
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
|
||||
super.onCreateContextMenu(menu, v, menuInfo);
|
||||
ExpandableListView.ExpandableListContextMenuInfo info =
|
||||
(ExpandableListView.ExpandableListContextMenuInfo) menuInfo;
|
||||
int type = ExpandableListView.getPackedPositionType(info.packedPosition);
|
||||
|
||||
if (type == ExpandableListView.PACKED_POSITION_TYPE_GROUP) {
|
||||
// TODO: user id? menu.setHeaderTitle("Key");
|
||||
menu.add(0, Id.menu.edit, 0, R.string.menu_editKey);
|
||||
menu.add(0, Id.menu.export, 1, R.string.menu_exportKey);
|
||||
menu.add(0, Id.menu.delete, 2, R.string.menu_deleteKey);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onContextItemSelected(MenuItem menuItem) {
|
||||
ExpandableListContextMenuInfo info = (ExpandableListContextMenuInfo) menuItem.getMenuInfo();
|
||||
int type = ExpandableListView.getPackedPositionType(info.packedPosition);
|
||||
int groupPosition = ExpandableListView.getPackedPositionGroup(info.packedPosition);
|
||||
|
||||
if (type != ExpandableListView.PACKED_POSITION_TYPE_GROUP) {
|
||||
return super.onContextItemSelected(menuItem);
|
||||
}
|
||||
|
||||
switch (menuItem.getItemId()) {
|
||||
case Id.menu.edit: {
|
||||
mSelectedItem = groupPosition;
|
||||
checkPassPhraseAndEdit();
|
||||
return true;
|
||||
}
|
||||
|
||||
default: {
|
||||
return super.onContextItemSelected(menuItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onChildClick(ExpandableListView parent, View v, int groupPosition,
|
||||
int childPosition, long id) {
|
||||
mSelectedItem = groupPosition;
|
||||
checkPassPhraseAndEdit();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Dialog onCreateDialog(int id) {
|
||||
switch (id) {
|
||||
case Id.dialog.pass_phrase: {
|
||||
long keyId = ((KeyListAdapter) mList.getExpandableListAdapter()).getGroupId(mSelectedItem);
|
||||
return AskForSecretKeyPassPhrase.createDialog(this, keyId, this);
|
||||
}
|
||||
|
||||
default: {
|
||||
return super.onCreateDialog(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void checkPassPhraseAndEdit() {
|
||||
long keyId = ((KeyListAdapter) mList.getExpandableListAdapter()).getGroupId(mSelectedItem);
|
||||
String passPhrase = Apg.getCachedPassPhrase(keyId);
|
||||
if (passPhrase == null) {
|
||||
showDialog(Id.dialog.pass_phrase);
|
||||
} else {
|
||||
Apg.setEditPassPhrase(passPhrase);
|
||||
editKey();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void passPhraseCallback(long keyId, String passPhrase) {
|
||||
super.passPhraseCallback(keyId, passPhrase);
|
||||
Apg.setEditPassPhrase(passPhrase);
|
||||
editKey();
|
||||
}
|
||||
|
||||
private void createKey() {
|
||||
Apg.setEditPassPhrase("");
|
||||
Intent intent = new Intent(this, EditKeyActivity.class);
|
||||
startActivityForResult(intent, Id.message.create_key);
|
||||
}
|
||||
|
||||
private void editKey() {
|
||||
long keyId = ((KeyListAdapter) mList.getExpandableListAdapter()).getGroupId(mSelectedItem);
|
||||
Intent intent = new Intent(this, EditKeyActivity.class);
|
||||
intent.putExtra(Apg.EXTRA_KEY_ID, keyId);
|
||||
startActivityForResult(intent, Id.message.edit_key);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
switch (requestCode) {
|
||||
case Id.message.create_key: // intentionally no break
|
||||
case Id.message.edit_key: {
|
||||
if (resultCode == RESULT_OK) {
|
||||
refreshList();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
}
|
||||
|
@ -1,225 +1,225 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.thialfihar.android.apg;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.thialfihar.android.apg.provider.KeyRings;
|
||||
import org.thialfihar.android.apg.provider.Keys;
|
||||
import org.thialfihar.android.apg.provider.UserIds;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.DatabaseUtils;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteQueryBuilder;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
|
||||
public class SelectPublicKeyListAdapter extends BaseAdapter {
|
||||
protected LayoutInflater mInflater;
|
||||
protected ListView mParent;
|
||||
protected SQLiteDatabase mDatabase;
|
||||
protected Cursor mCursor;
|
||||
protected String mSearchString;
|
||||
protected Activity mActivity;
|
||||
|
||||
public SelectPublicKeyListAdapter(Activity activity, ListView parent,
|
||||
String searchString, long selectedKeyIds[]) {
|
||||
mSearchString = searchString;
|
||||
|
||||
mActivity = activity;
|
||||
mParent = parent;
|
||||
mDatabase = Apg.getDatabase().db();
|
||||
mInflater = (LayoutInflater) parent.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
long now = new Date().getTime() / 1000;
|
||||
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
|
||||
qb.setTables(KeyRings.TABLE_NAME + " INNER JOIN " + Keys.TABLE_NAME + " ON " +
|
||||
"(" + KeyRings.TABLE_NAME + "." + KeyRings._ID + " = " +
|
||||
Keys.TABLE_NAME + "." + Keys.KEY_RING_ID + " AND " +
|
||||
Keys.TABLE_NAME + "." + Keys.IS_MASTER_KEY + " = '1'" +
|
||||
") " +
|
||||
" INNER JOIN " + UserIds.TABLE_NAME + " ON " +
|
||||
"(" + Keys.TABLE_NAME + "." + Keys._ID + " = " +
|
||||
UserIds.TABLE_NAME + "." + UserIds.KEY_ID + " AND " +
|
||||
UserIds.TABLE_NAME + "." + UserIds.RANK + " = '0') ");
|
||||
|
||||
String inIdList = null;
|
||||
|
||||
if (selectedKeyIds != null && selectedKeyIds.length > 0) {
|
||||
inIdList = KeyRings.TABLE_NAME + "." + KeyRings.MASTER_KEY_ID + " IN (";
|
||||
for (int i = 0; i < selectedKeyIds.length; ++i) {
|
||||
if (i != 0) {
|
||||
inIdList += ", ";
|
||||
}
|
||||
inIdList += DatabaseUtils.sqlEscapeString("" + selectedKeyIds[i]);
|
||||
}
|
||||
inIdList += ")";
|
||||
}
|
||||
|
||||
if (searchString != null && searchString.trim().length() > 0) {
|
||||
String[] chunks = searchString.trim().split(" +");
|
||||
qb.appendWhere("(EXISTS (SELECT tmp." + UserIds._ID + " FROM " +
|
||||
UserIds.TABLE_NAME + " AS tmp WHERE " +
|
||||
"tmp." + UserIds.KEY_ID + " = " +
|
||||
Keys.TABLE_NAME + "." + Keys._ID);
|
||||
for (int i = 0; i < chunks.length; ++i) {
|
||||
qb.appendWhere(" AND tmp." + UserIds.USER_ID + " LIKE ");
|
||||
qb.appendWhereEscapeString("%" + chunks[i] + "%");
|
||||
}
|
||||
qb.appendWhere("))");
|
||||
|
||||
if (inIdList != null) {
|
||||
qb.appendWhere(" OR (" + inIdList + ")");
|
||||
}
|
||||
}
|
||||
|
||||
String orderBy = UserIds.TABLE_NAME + "." + UserIds.USER_ID + " ASC";
|
||||
if (inIdList != null) {
|
||||
orderBy = inIdList + " DESC, " + orderBy;
|
||||
}
|
||||
|
||||
mCursor = qb.query(mDatabase,
|
||||
new String[] {
|
||||
KeyRings.TABLE_NAME + "." + KeyRings._ID, // 0
|
||||
KeyRings.TABLE_NAME + "." + KeyRings.MASTER_KEY_ID, // 1
|
||||
UserIds.TABLE_NAME + "." + UserIds.USER_ID, // 2
|
||||
"(SELECT COUNT(tmp." + Keys._ID + ") FROM " + Keys.TABLE_NAME + " AS tmp WHERE " +
|
||||
"tmp." + Keys.KEY_RING_ID + " = " +
|
||||
KeyRings.TABLE_NAME + "." + KeyRings._ID + " AND " +
|
||||
"tmp." + Keys.IS_REVOKED + " = '0' AND " +
|
||||
"tmp." + Keys.CAN_ENCRYPT + " = '1')", // 3
|
||||
"(SELECT COUNT(tmp." + Keys._ID + ") FROM " + Keys.TABLE_NAME + " AS tmp WHERE " +
|
||||
"tmp." + Keys.KEY_RING_ID + " = " +
|
||||
KeyRings.TABLE_NAME + "." + KeyRings._ID + " AND " +
|
||||
"tmp." + Keys.IS_REVOKED + " = '0' AND " +
|
||||
"tmp." + Keys.CAN_ENCRYPT + " = '1' AND " +
|
||||
"tmp." + Keys.CREATION + " <= '" + now + "' AND " +
|
||||
"(tmp." + Keys.EXPIRY + " IS NULL OR " +
|
||||
"tmp." + Keys.EXPIRY + " >= '" + now + "'))", // 4
|
||||
},
|
||||
KeyRings.TABLE_NAME + "." + KeyRings.TYPE + " = ?",
|
||||
new String[] { "" + Id.database.type_public },
|
||||
null, null, orderBy);
|
||||
|
||||
activity.startManagingCursor(mCursor);
|
||||
}
|
||||
|
||||
public void cleanup() {
|
||||
if (mCursor != null) {
|
||||
mActivity.stopManagingCursor(mCursor);
|
||||
mCursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled(int position) {
|
||||
mCursor.moveToPosition(position);
|
||||
return mCursor.getInt(4) > 0; // valid CAN_ENCRYPT
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasStableIds() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return mCursor.getCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItem(int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
mCursor.moveToPosition(position);
|
||||
return mCursor.getLong(1); // MASTER_KEY_ID
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
mCursor.moveToPosition(position);
|
||||
|
||||
View view = mInflater.inflate(R.layout.select_public_key_item, null);
|
||||
boolean enabled = isEnabled(position);
|
||||
|
||||
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 = mCursor.getString(2); // USER_ID
|
||||
if (userId != null) {
|
||||
String chunks[] = userId.split(" <", 2);
|
||||
userId = chunks[0];
|
||||
if (chunks.length > 1) {
|
||||
mainUserIdRest.setText("<" + chunks[1]);
|
||||
}
|
||||
mainUserId.setText(userId);
|
||||
}
|
||||
|
||||
long masterKeyId = mCursor.getLong(1); // MASTER_KEY_ID
|
||||
keyId.setText("" + Long.toHexString(masterKeyId & 0xffffffffL));
|
||||
|
||||
if (mainUserIdRest.getText().length() == 0) {
|
||||
mainUserIdRest.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if (enabled) {
|
||||
status.setText(R.string.canEncrypt);
|
||||
} else {
|
||||
if (mCursor.getInt(3) > 0) {
|
||||
// has some CAN_ENCRYPT keys, but col(4) = 0, so must be revoked or expired
|
||||
status.setText(R.string.expired);
|
||||
} else {
|
||||
status.setText(R.string.noKey);
|
||||
}
|
||||
}
|
||||
|
||||
status.setText(status.getText() + " ");
|
||||
|
||||
CheckBox selected = (CheckBox) view.findViewById(R.id.selected);
|
||||
|
||||
if (!enabled) {
|
||||
mParent.setItemChecked(position, false);
|
||||
}
|
||||
|
||||
selected.setChecked(mParent.isItemChecked(position));
|
||||
|
||||
view.setEnabled(enabled);
|
||||
mainUserId.setEnabled(enabled);
|
||||
mainUserIdRest.setEnabled(enabled);
|
||||
keyId.setEnabled(enabled);
|
||||
selected.setEnabled(enabled);
|
||||
status.setEnabled(enabled);
|
||||
|
||||
return view;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.thialfihar.android.apg;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.thialfihar.android.apg.provider.KeyRings;
|
||||
import org.thialfihar.android.apg.provider.Keys;
|
||||
import org.thialfihar.android.apg.provider.UserIds;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.DatabaseUtils;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteQueryBuilder;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
|
||||
public class SelectPublicKeyListAdapter extends BaseAdapter {
|
||||
protected LayoutInflater mInflater;
|
||||
protected ListView mParent;
|
||||
protected SQLiteDatabase mDatabase;
|
||||
protected Cursor mCursor;
|
||||
protected String mSearchString;
|
||||
protected Activity mActivity;
|
||||
|
||||
public SelectPublicKeyListAdapter(Activity activity, ListView parent,
|
||||
String searchString, long selectedKeyIds[]) {
|
||||
mSearchString = searchString;
|
||||
|
||||
mActivity = activity;
|
||||
mParent = parent;
|
||||
mDatabase = Apg.getDatabase().db();
|
||||
mInflater = (LayoutInflater) parent.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
long now = new Date().getTime() / 1000;
|
||||
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
|
||||
qb.setTables(KeyRings.TABLE_NAME + " INNER JOIN " + Keys.TABLE_NAME + " ON " +
|
||||
"(" + KeyRings.TABLE_NAME + "." + KeyRings._ID + " = " +
|
||||
Keys.TABLE_NAME + "." + Keys.KEY_RING_ID + " AND " +
|
||||
Keys.TABLE_NAME + "." + Keys.IS_MASTER_KEY + " = '1'" +
|
||||
") " +
|
||||
" INNER JOIN " + UserIds.TABLE_NAME + " ON " +
|
||||
"(" + Keys.TABLE_NAME + "." + Keys._ID + " = " +
|
||||
UserIds.TABLE_NAME + "." + UserIds.KEY_ID + " AND " +
|
||||
UserIds.TABLE_NAME + "." + UserIds.RANK + " = '0') ");
|
||||
|
||||
String inIdList = null;
|
||||
|
||||
if (selectedKeyIds != null && selectedKeyIds.length > 0) {
|
||||
inIdList = KeyRings.TABLE_NAME + "." + KeyRings.MASTER_KEY_ID + " IN (";
|
||||
for (int i = 0; i < selectedKeyIds.length; ++i) {
|
||||
if (i != 0) {
|
||||
inIdList += ", ";
|
||||
}
|
||||
inIdList += DatabaseUtils.sqlEscapeString("" + selectedKeyIds[i]);
|
||||
}
|
||||
inIdList += ")";
|
||||
}
|
||||
|
||||
if (searchString != null && searchString.trim().length() > 0) {
|
||||
String[] chunks = searchString.trim().split(" +");
|
||||
qb.appendWhere("(EXISTS (SELECT tmp." + UserIds._ID + " FROM " +
|
||||
UserIds.TABLE_NAME + " AS tmp WHERE " +
|
||||
"tmp." + UserIds.KEY_ID + " = " +
|
||||
Keys.TABLE_NAME + "." + Keys._ID);
|
||||
for (int i = 0; i < chunks.length; ++i) {
|
||||
qb.appendWhere(" AND tmp." + UserIds.USER_ID + " LIKE ");
|
||||
qb.appendWhereEscapeString("%" + chunks[i] + "%");
|
||||
}
|
||||
qb.appendWhere("))");
|
||||
|
||||
if (inIdList != null) {
|
||||
qb.appendWhere(" OR (" + inIdList + ")");
|
||||
}
|
||||
}
|
||||
|
||||
String orderBy = UserIds.TABLE_NAME + "." + UserIds.USER_ID + " ASC";
|
||||
if (inIdList != null) {
|
||||
orderBy = inIdList + " DESC, " + orderBy;
|
||||
}
|
||||
|
||||
mCursor = qb.query(mDatabase,
|
||||
new String[] {
|
||||
KeyRings.TABLE_NAME + "." + KeyRings._ID, // 0
|
||||
KeyRings.TABLE_NAME + "." + KeyRings.MASTER_KEY_ID, // 1
|
||||
UserIds.TABLE_NAME + "." + UserIds.USER_ID, // 2
|
||||
"(SELECT COUNT(tmp." + Keys._ID + ") FROM " + Keys.TABLE_NAME + " AS tmp WHERE " +
|
||||
"tmp." + Keys.KEY_RING_ID + " = " +
|
||||
KeyRings.TABLE_NAME + "." + KeyRings._ID + " AND " +
|
||||
"tmp." + Keys.IS_REVOKED + " = '0' AND " +
|
||||
"tmp." + Keys.CAN_ENCRYPT + " = '1')", // 3
|
||||
"(SELECT COUNT(tmp." + Keys._ID + ") FROM " + Keys.TABLE_NAME + " AS tmp WHERE " +
|
||||
"tmp." + Keys.KEY_RING_ID + " = " +
|
||||
KeyRings.TABLE_NAME + "." + KeyRings._ID + " AND " +
|
||||
"tmp." + Keys.IS_REVOKED + " = '0' AND " +
|
||||
"tmp." + Keys.CAN_ENCRYPT + " = '1' AND " +
|
||||
"tmp." + Keys.CREATION + " <= '" + now + "' AND " +
|
||||
"(tmp." + Keys.EXPIRY + " IS NULL OR " +
|
||||
"tmp." + Keys.EXPIRY + " >= '" + now + "'))", // 4
|
||||
},
|
||||
KeyRings.TABLE_NAME + "." + KeyRings.TYPE + " = ?",
|
||||
new String[] { "" + Id.database.type_public },
|
||||
null, null, orderBy);
|
||||
|
||||
activity.startManagingCursor(mCursor);
|
||||
}
|
||||
|
||||
public void cleanup() {
|
||||
if (mCursor != null) {
|
||||
mActivity.stopManagingCursor(mCursor);
|
||||
mCursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled(int position) {
|
||||
mCursor.moveToPosition(position);
|
||||
return mCursor.getInt(4) > 0; // valid CAN_ENCRYPT
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasStableIds() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return mCursor.getCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItem(int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
mCursor.moveToPosition(position);
|
||||
return mCursor.getLong(1); // MASTER_KEY_ID
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
mCursor.moveToPosition(position);
|
||||
|
||||
View view = mInflater.inflate(R.layout.select_public_key_item, null);
|
||||
boolean enabled = isEnabled(position);
|
||||
|
||||
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 = mCursor.getString(2); // USER_ID
|
||||
if (userId != null) {
|
||||
String chunks[] = userId.split(" <", 2);
|
||||
userId = chunks[0];
|
||||
if (chunks.length > 1) {
|
||||
mainUserIdRest.setText("<" + chunks[1]);
|
||||
}
|
||||
mainUserId.setText(userId);
|
||||
}
|
||||
|
||||
long masterKeyId = mCursor.getLong(1); // MASTER_KEY_ID
|
||||
keyId.setText("" + Long.toHexString(masterKeyId & 0xffffffffL));
|
||||
|
||||
if (mainUserIdRest.getText().length() == 0) {
|
||||
mainUserIdRest.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if (enabled) {
|
||||
status.setText(R.string.canEncrypt);
|
||||
} else {
|
||||
if (mCursor.getInt(3) > 0) {
|
||||
// has some CAN_ENCRYPT keys, but col(4) = 0, so must be revoked or expired
|
||||
status.setText(R.string.expired);
|
||||
} else {
|
||||
status.setText(R.string.noKey);
|
||||
}
|
||||
}
|
||||
|
||||
status.setText(status.getText() + " ");
|
||||
|
||||
CheckBox selected = (CheckBox) view.findViewById(R.id.selected);
|
||||
|
||||
if (!enabled) {
|
||||
mParent.setItemChecked(position, false);
|
||||
}
|
||||
|
||||
selected.setChecked(mParent.isItemChecked(position));
|
||||
|
||||
view.setEnabled(enabled);
|
||||
mainUserId.setEnabled(enabled);
|
||||
mainUserIdRest.setEnabled(enabled);
|
||||
keyId.setEnabled(enabled);
|
||||
selected.setEnabled(enabled);
|
||||
status.setEnabled(enabled);
|
||||
|
||||
return view;
|
||||
}
|
||||
}
|
||||
|
@ -1,175 +1,175 @@
|
||||
package org.thialfihar.android.apg;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.thialfihar.android.apg.provider.KeyRings;
|
||||
import org.thialfihar.android.apg.provider.Keys;
|
||||
import org.thialfihar.android.apg.provider.UserIds;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteQueryBuilder;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
|
||||
public class SelectSecretKeyListAdapter extends BaseAdapter {
|
||||
protected LayoutInflater mInflater;
|
||||
protected ListView mParent;
|
||||
protected SQLiteDatabase mDatabase;
|
||||
protected Cursor mCursor;
|
||||
protected String mSearchString;
|
||||
protected Activity mActivity;
|
||||
|
||||
public SelectSecretKeyListAdapter(Activity activity, ListView parent, String searchString) {
|
||||
mSearchString = searchString;
|
||||
|
||||
mActivity = activity;
|
||||
mParent = parent;
|
||||
mDatabase = Apg.getDatabase().db();
|
||||
mInflater = (LayoutInflater) parent.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
long now = new Date().getTime() / 1000;
|
||||
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
|
||||
qb.setTables(KeyRings.TABLE_NAME + " INNER JOIN " + Keys.TABLE_NAME + " ON " +
|
||||
"(" + KeyRings.TABLE_NAME + "." + KeyRings._ID + " = " +
|
||||
Keys.TABLE_NAME + "." + Keys.KEY_RING_ID + " AND " +
|
||||
Keys.TABLE_NAME + "." + Keys.IS_MASTER_KEY + " = '1'" +
|
||||
") " +
|
||||
" INNER JOIN " + UserIds.TABLE_NAME + " ON " +
|
||||
"(" + Keys.TABLE_NAME + "." + Keys._ID + " = " +
|
||||
UserIds.TABLE_NAME + "." + UserIds.KEY_ID + " AND " +
|
||||
UserIds.TABLE_NAME + "." + UserIds.RANK + " = '0') ");
|
||||
|
||||
if (searchString != null && searchString.trim().length() > 0) {
|
||||
String[] chunks = searchString.trim().split(" +");
|
||||
qb.appendWhere("EXISTS (SELECT tmp." + UserIds._ID + " FROM " +
|
||||
UserIds.TABLE_NAME + " AS tmp WHERE " +
|
||||
"tmp." + UserIds.KEY_ID + " = " +
|
||||
Keys.TABLE_NAME + "." + Keys._ID);
|
||||
for (int i = 0; i < chunks.length; ++i) {
|
||||
qb.appendWhere(" AND tmp." + UserIds.USER_ID + " LIKE ");
|
||||
qb.appendWhereEscapeString("%" + chunks[i] + "%");
|
||||
}
|
||||
qb.appendWhere(")");
|
||||
}
|
||||
|
||||
mCursor = qb.query(mDatabase,
|
||||
new String[] {
|
||||
KeyRings.TABLE_NAME + "." + KeyRings._ID, // 0
|
||||
KeyRings.TABLE_NAME + "." + KeyRings.MASTER_KEY_ID, // 1
|
||||
UserIds.TABLE_NAME + "." + UserIds.USER_ID, // 2
|
||||
"(SELECT COUNT(tmp." + Keys._ID + ") FROM " + Keys.TABLE_NAME + " AS tmp WHERE " +
|
||||
"tmp." + Keys.KEY_RING_ID + " = " +
|
||||
KeyRings.TABLE_NAME + "." + KeyRings._ID + " AND " +
|
||||
"tmp." + Keys.IS_REVOKED + " = '0' AND " +
|
||||
"tmp." + Keys.CAN_SIGN + " = '1')", // 3,
|
||||
"(SELECT COUNT(tmp." + Keys._ID + ") FROM " + Keys.TABLE_NAME + " AS tmp WHERE " +
|
||||
"tmp." + Keys.KEY_RING_ID + " = " +
|
||||
KeyRings.TABLE_NAME + "." + KeyRings._ID + " AND " +
|
||||
"tmp." + Keys.IS_REVOKED + " = '0' AND " +
|
||||
"tmp." + Keys.CAN_SIGN + " = '1' AND " +
|
||||
"tmp." + Keys.CREATION + " <= '" + now + "' AND " +
|
||||
"(tmp." + Keys.EXPIRY + " IS NULL OR " +
|
||||
"tmp." + Keys.EXPIRY + " >= '" + now + "'))", // 4
|
||||
},
|
||||
KeyRings.TABLE_NAME + "." + KeyRings.TYPE + " = ?",
|
||||
new String[] { "" + Id.database.type_secret },
|
||||
null, null, UserIds.TABLE_NAME + "." + UserIds.USER_ID + " ASC");
|
||||
|
||||
activity.startManagingCursor(mCursor);
|
||||
}
|
||||
|
||||
public void cleanup() {
|
||||
if (mCursor != null) {
|
||||
mActivity.stopManagingCursor(mCursor);
|
||||
mCursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled(int position) {
|
||||
mCursor.moveToPosition(position);
|
||||
return mCursor.getInt(4) > 0; // valid CAN_SIGN
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasStableIds() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return mCursor.getCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItem(int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
mCursor.moveToPosition(position);
|
||||
return mCursor.getLong(1); // MASTER_KEY_ID
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
mCursor.moveToPosition(position);
|
||||
|
||||
View view = mInflater.inflate(R.layout.select_secret_key_item, null);
|
||||
boolean enabled = isEnabled(position);
|
||||
|
||||
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 = mCursor.getString(2); // USER_ID
|
||||
if (userId != null) {
|
||||
String chunks[] = userId.split(" <", 2);
|
||||
userId = chunks[0];
|
||||
if (chunks.length > 1) {
|
||||
mainUserIdRest.setText("<" + chunks[1]);
|
||||
}
|
||||
mainUserId.setText(userId);
|
||||
}
|
||||
|
||||
long masterKeyId = mCursor.getLong(1); // MASTER_KEY_ID
|
||||
keyId.setText("" + Long.toHexString(masterKeyId & 0xffffffffL));
|
||||
|
||||
if (mainUserIdRest.getText().length() == 0) {
|
||||
mainUserIdRest.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if (enabled) {
|
||||
status.setText(R.string.canSign);
|
||||
} else {
|
||||
if (mCursor.getInt(3) > 0) {
|
||||
// has some CAN_SIGN keys, but col(4) = 0, so must be revoked or expired
|
||||
status.setText(R.string.expired);
|
||||
} else {
|
||||
status.setText(R.string.noKey);
|
||||
}
|
||||
}
|
||||
|
||||
status.setText(status.getText() + " ");
|
||||
|
||||
view.setEnabled(enabled);
|
||||
mainUserId.setEnabled(enabled);
|
||||
mainUserIdRest.setEnabled(enabled);
|
||||
keyId.setEnabled(enabled);
|
||||
status.setEnabled(enabled);
|
||||
|
||||
return view;
|
||||
}
|
||||
package org.thialfihar.android.apg;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.thialfihar.android.apg.provider.KeyRings;
|
||||
import org.thialfihar.android.apg.provider.Keys;
|
||||
import org.thialfihar.android.apg.provider.UserIds;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteQueryBuilder;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
|
||||
public class SelectSecretKeyListAdapter extends BaseAdapter {
|
||||
protected LayoutInflater mInflater;
|
||||
protected ListView mParent;
|
||||
protected SQLiteDatabase mDatabase;
|
||||
protected Cursor mCursor;
|
||||
protected String mSearchString;
|
||||
protected Activity mActivity;
|
||||
|
||||
public SelectSecretKeyListAdapter(Activity activity, ListView parent, String searchString) {
|
||||
mSearchString = searchString;
|
||||
|
||||
mActivity = activity;
|
||||
mParent = parent;
|
||||
mDatabase = Apg.getDatabase().db();
|
||||
mInflater = (LayoutInflater) parent.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
long now = new Date().getTime() / 1000;
|
||||
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
|
||||
qb.setTables(KeyRings.TABLE_NAME + " INNER JOIN " + Keys.TABLE_NAME + " ON " +
|
||||
"(" + KeyRings.TABLE_NAME + "." + KeyRings._ID + " = " +
|
||||
Keys.TABLE_NAME + "." + Keys.KEY_RING_ID + " AND " +
|
||||
Keys.TABLE_NAME + "." + Keys.IS_MASTER_KEY + " = '1'" +
|
||||
") " +
|
||||
" INNER JOIN " + UserIds.TABLE_NAME + " ON " +
|
||||
"(" + Keys.TABLE_NAME + "." + Keys._ID + " = " +
|
||||
UserIds.TABLE_NAME + "." + UserIds.KEY_ID + " AND " +
|
||||
UserIds.TABLE_NAME + "." + UserIds.RANK + " = '0') ");
|
||||
|
||||
if (searchString != null && searchString.trim().length() > 0) {
|
||||
String[] chunks = searchString.trim().split(" +");
|
||||
qb.appendWhere("EXISTS (SELECT tmp." + UserIds._ID + " FROM " +
|
||||
UserIds.TABLE_NAME + " AS tmp WHERE " +
|
||||
"tmp." + UserIds.KEY_ID + " = " +
|
||||
Keys.TABLE_NAME + "." + Keys._ID);
|
||||
for (int i = 0; i < chunks.length; ++i) {
|
||||
qb.appendWhere(" AND tmp." + UserIds.USER_ID + " LIKE ");
|
||||
qb.appendWhereEscapeString("%" + chunks[i] + "%");
|
||||
}
|
||||
qb.appendWhere(")");
|
||||
}
|
||||
|
||||
mCursor = qb.query(mDatabase,
|
||||
new String[] {
|
||||
KeyRings.TABLE_NAME + "." + KeyRings._ID, // 0
|
||||
KeyRings.TABLE_NAME + "." + KeyRings.MASTER_KEY_ID, // 1
|
||||
UserIds.TABLE_NAME + "." + UserIds.USER_ID, // 2
|
||||
"(SELECT COUNT(tmp." + Keys._ID + ") FROM " + Keys.TABLE_NAME + " AS tmp WHERE " +
|
||||
"tmp." + Keys.KEY_RING_ID + " = " +
|
||||
KeyRings.TABLE_NAME + "." + KeyRings._ID + " AND " +
|
||||
"tmp." + Keys.IS_REVOKED + " = '0' AND " +
|
||||
"tmp." + Keys.CAN_SIGN + " = '1')", // 3,
|
||||
"(SELECT COUNT(tmp." + Keys._ID + ") FROM " + Keys.TABLE_NAME + " AS tmp WHERE " +
|
||||
"tmp." + Keys.KEY_RING_ID + " = " +
|
||||
KeyRings.TABLE_NAME + "." + KeyRings._ID + " AND " +
|
||||
"tmp." + Keys.IS_REVOKED + " = '0' AND " +
|
||||
"tmp." + Keys.CAN_SIGN + " = '1' AND " +
|
||||
"tmp." + Keys.CREATION + " <= '" + now + "' AND " +
|
||||
"(tmp." + Keys.EXPIRY + " IS NULL OR " +
|
||||
"tmp." + Keys.EXPIRY + " >= '" + now + "'))", // 4
|
||||
},
|
||||
KeyRings.TABLE_NAME + "." + KeyRings.TYPE + " = ?",
|
||||
new String[] { "" + Id.database.type_secret },
|
||||
null, null, UserIds.TABLE_NAME + "." + UserIds.USER_ID + " ASC");
|
||||
|
||||
activity.startManagingCursor(mCursor);
|
||||
}
|
||||
|
||||
public void cleanup() {
|
||||
if (mCursor != null) {
|
||||
mActivity.stopManagingCursor(mCursor);
|
||||
mCursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled(int position) {
|
||||
mCursor.moveToPosition(position);
|
||||
return mCursor.getInt(4) > 0; // valid CAN_SIGN
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasStableIds() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return mCursor.getCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItem(int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
mCursor.moveToPosition(position);
|
||||
return mCursor.getLong(1); // MASTER_KEY_ID
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
mCursor.moveToPosition(position);
|
||||
|
||||
View view = mInflater.inflate(R.layout.select_secret_key_item, null);
|
||||
boolean enabled = isEnabled(position);
|
||||
|
||||
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 = mCursor.getString(2); // USER_ID
|
||||
if (userId != null) {
|
||||
String chunks[] = userId.split(" <", 2);
|
||||
userId = chunks[0];
|
||||
if (chunks.length > 1) {
|
||||
mainUserIdRest.setText("<" + chunks[1]);
|
||||
}
|
||||
mainUserId.setText(userId);
|
||||
}
|
||||
|
||||
long masterKeyId = mCursor.getLong(1); // MASTER_KEY_ID
|
||||
keyId.setText("" + Long.toHexString(masterKeyId & 0xffffffffL));
|
||||
|
||||
if (mainUserIdRest.getText().length() == 0) {
|
||||
mainUserIdRest.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if (enabled) {
|
||||
status.setText(R.string.canSign);
|
||||
} else {
|
||||
if (mCursor.getInt(3) > 0) {
|
||||
// has some CAN_SIGN keys, but col(4) = 0, so must be revoked or expired
|
||||
status.setText(R.string.expired);
|
||||
} else {
|
||||
status.setText(R.string.noKey);
|
||||
}
|
||||
}
|
||||
|
||||
status.setText(status.getText() + " ");
|
||||
|
||||
view.setEnabled(enabled);
|
||||
mainUserId.setEnabled(enabled);
|
||||
mainUserIdRest.setEnabled(enabled);
|
||||
keyId.setEnabled(enabled);
|
||||
status.setEnabled(enabled);
|
||||
|
||||
return view;
|
||||
}
|
||||
}
|
@ -1,78 +1,78 @@
|
||||
package org.thialfihar.android.apg;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Binder;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
|
||||
public class Service extends android.app.Service {
|
||||
private final IBinder mBinder = new LocalBinder();
|
||||
|
||||
public static final String EXTRA_TTL = "ttl";
|
||||
|
||||
private int mPassPhraseCacheTtl = 15;
|
||||
private Handler mCacheHandler = new Handler();
|
||||
private Runnable mCacheTask = new Runnable() {
|
||||
public void run() {
|
||||
// check every ttl/2 seconds, which shouldn't be heavy on the device (even if ttl = 15),
|
||||
// and makes sure the longest a pass phrase survives in the cache is 1.5 * ttl
|
||||
int delay = mPassPhraseCacheTtl * 1000 / 2;
|
||||
// also make sure the delay is not longer than one minute
|
||||
if (delay > 60000) {
|
||||
delay = 60000;
|
||||
}
|
||||
|
||||
delay = Apg.cleanUpCache(mPassPhraseCacheTtl, delay);
|
||||
// don't check too often, even if we were close
|
||||
if (delay < 5000) {
|
||||
delay = 5000;
|
||||
}
|
||||
|
||||
mCacheHandler.postDelayed(this, delay);
|
||||
}
|
||||
};
|
||||
|
||||
static private boolean mIsRunning = false;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
|
||||
mIsRunning = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
mIsRunning = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart(Intent intent, int startId) {
|
||||
super.onStart(intent, startId);
|
||||
|
||||
if (intent != null) {
|
||||
mPassPhraseCacheTtl = intent.getIntExtra(EXTRA_TTL, 15);
|
||||
}
|
||||
if (mPassPhraseCacheTtl < 15) {
|
||||
mPassPhraseCacheTtl = 15;
|
||||
}
|
||||
mCacheHandler.removeCallbacks(mCacheTask);
|
||||
mCacheHandler.postDelayed(mCacheTask, 1000);
|
||||
}
|
||||
|
||||
static public boolean isRunning() {
|
||||
return mIsRunning;
|
||||
}
|
||||
|
||||
public class LocalBinder extends Binder {
|
||||
Service getService() {
|
||||
return Service.this;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return mBinder;
|
||||
}
|
||||
}
|
||||
package org.thialfihar.android.apg;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Binder;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
|
||||
public class Service extends android.app.Service {
|
||||
private final IBinder mBinder = new LocalBinder();
|
||||
|
||||
public static final String EXTRA_TTL = "ttl";
|
||||
|
||||
private int mPassPhraseCacheTtl = 15;
|
||||
private Handler mCacheHandler = new Handler();
|
||||
private Runnable mCacheTask = new Runnable() {
|
||||
public void run() {
|
||||
// check every ttl/2 seconds, which shouldn't be heavy on the device (even if ttl = 15),
|
||||
// and makes sure the longest a pass phrase survives in the cache is 1.5 * ttl
|
||||
int delay = mPassPhraseCacheTtl * 1000 / 2;
|
||||
// also make sure the delay is not longer than one minute
|
||||
if (delay > 60000) {
|
||||
delay = 60000;
|
||||
}
|
||||
|
||||
delay = Apg.cleanUpCache(mPassPhraseCacheTtl, delay);
|
||||
// don't check too often, even if we were close
|
||||
if (delay < 5000) {
|
||||
delay = 5000;
|
||||
}
|
||||
|
||||
mCacheHandler.postDelayed(this, delay);
|
||||
}
|
||||
};
|
||||
|
||||
static private boolean mIsRunning = false;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
|
||||
mIsRunning = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
mIsRunning = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart(Intent intent, int startId) {
|
||||
super.onStart(intent, startId);
|
||||
|
||||
if (intent != null) {
|
||||
mPassPhraseCacheTtl = intent.getIntExtra(EXTRA_TTL, 15);
|
||||
}
|
||||
if (mPassPhraseCacheTtl < 15) {
|
||||
mPassPhraseCacheTtl = 15;
|
||||
}
|
||||
mCacheHandler.removeCallbacks(mCacheTask);
|
||||
mCacheHandler.postDelayed(mCacheTask, 1000);
|
||||
}
|
||||
|
||||
static public boolean isRunning() {
|
||||
return mIsRunning;
|
||||
}
|
||||
|
||||
public class LocalBinder extends Binder {
|
||||
Service getService() {
|
||||
return Service.this;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return mBinder;
|
||||
}
|
||||
}
|
||||
|
@ -1,27 +1,27 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.thialfihar.android.apg.provider;
|
||||
|
||||
import android.provider.BaseColumns;
|
||||
|
||||
public class Accounts implements BaseColumns {
|
||||
public static final String TABLE_NAME = "accounts";
|
||||
|
||||
public static final String _ID_type = "INTEGER PRIMARY KEY";
|
||||
public static final String NAME = "c_name";
|
||||
public static final String NAME_type = "TEXT";
|
||||
}
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.thialfihar.android.apg.provider;
|
||||
|
||||
import android.provider.BaseColumns;
|
||||
|
||||
public class Accounts implements BaseColumns {
|
||||
public static final String TABLE_NAME = "accounts";
|
||||
|
||||
public static final String _ID_type = "INTEGER PRIMARY KEY";
|
||||
public static final String NAME = "c_name";
|
||||
public static final String NAME_type = "TEXT";
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,33 +1,33 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.thialfihar.android.apg.provider;
|
||||
|
||||
import android.provider.BaseColumns;
|
||||
|
||||
public class KeyRings implements BaseColumns {
|
||||
public static final String TABLE_NAME = "key_rings";
|
||||
|
||||
public static final String _ID_type = "INTEGER PRIMARY KEY";
|
||||
public static final String MASTER_KEY_ID = "c_master_key_id";
|
||||
public static final String MASTER_KEY_ID_type = "INT64";
|
||||
public static final String TYPE = "c_type";
|
||||
public static final String TYPE_type = "INTEGER";
|
||||
public static final String WHO_ID = "c_who_id";
|
||||
public static final String WHO_ID_type = "INTEGER";
|
||||
public static final String KEY_RING_DATA = "c_key_ring_data";
|
||||
public static final String KEY_RING_DATA_type = "BLOB";
|
||||
}
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.thialfihar.android.apg.provider;
|
||||
|
||||
import android.provider.BaseColumns;
|
||||
|
||||
public class KeyRings implements BaseColumns {
|
||||
public static final String TABLE_NAME = "key_rings";
|
||||
|
||||
public static final String _ID_type = "INTEGER PRIMARY KEY";
|
||||
public static final String MASTER_KEY_ID = "c_master_key_id";
|
||||
public static final String MASTER_KEY_ID_type = "INT64";
|
||||
public static final String TYPE = "c_type";
|
||||
public static final String TYPE_type = "INTEGER";
|
||||
public static final String WHO_ID = "c_who_id";
|
||||
public static final String WHO_ID_type = "INTEGER";
|
||||
public static final String KEY_RING_DATA = "c_key_ring_data";
|
||||
public static final String KEY_RING_DATA_type = "BLOB";
|
||||
}
|
||||
|
@ -1,31 +1,31 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.thialfihar.android.apg.provider;
|
||||
|
||||
import android.provider.BaseColumns;
|
||||
|
||||
public class UserIds implements BaseColumns {
|
||||
public static final String TABLE_NAME = "user_ids";
|
||||
|
||||
public static final String _ID_type = "INTEGER PRIMARY KEY";
|
||||
public static final String KEY_ID = "c_key_id";
|
||||
public static final String KEY_ID_type = "INTEGER";
|
||||
public static final String USER_ID = "c_user_id";
|
||||
public static final String USER_ID_type = "TEXT";
|
||||
public static final String RANK = "c_rank";
|
||||
public static final String RANK_type = "INTEGER";
|
||||
}
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.thialfihar.android.apg.provider;
|
||||
|
||||
import android.provider.BaseColumns;
|
||||
|
||||
public class UserIds implements BaseColumns {
|
||||
public static final String TABLE_NAME = "user_ids";
|
||||
|
||||
public static final String _ID_type = "INTEGER PRIMARY KEY";
|
||||
public static final String KEY_ID = "c_key_id";
|
||||
public static final String KEY_ID_type = "INTEGER";
|
||||
public static final String USER_ID = "c_user_id";
|
||||
public static final String USER_ID_type = "TEXT";
|
||||
public static final String RANK = "c_rank";
|
||||
public static final String RANK_type = "INTEGER";
|
||||
}
|
||||
|
@ -1,25 +1,25 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.thialfihar.android.apg.ui.widget;
|
||||
|
||||
public interface Editor {
|
||||
public interface EditorListener {
|
||||
public void onDeleted(Editor editor);
|
||||
}
|
||||
|
||||
public void setEditorListener(EditorListener listener);
|
||||
}
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.thialfihar.android.apg.ui.widget;
|
||||
|
||||
public interface Editor {
|
||||
public interface EditorListener {
|
||||
public void onDeleted(Editor editor);
|
||||
}
|
||||
|
||||
public void setEditorListener(EditorListener listener);
|
||||
}
|
||||
|
@ -1,242 +1,242 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.thialfihar.android.apg.ui.widget;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.Vector;
|
||||
|
||||
import org.bouncycastle2.openpgp.PGPPublicKey;
|
||||
import org.bouncycastle2.openpgp.PGPSecretKey;
|
||||
import org.thialfihar.android.apg.Apg;
|
||||
import org.thialfihar.android.apg.Id;
|
||||
import org.thialfihar.android.apg.R;
|
||||
import org.thialfihar.android.apg.utils.Choice;
|
||||
|
||||
import android.app.DatePickerDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.DatePicker;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
|
||||
public class KeyEditor extends LinearLayout implements Editor, OnClickListener {
|
||||
private PGPSecretKey mKey;
|
||||
|
||||
private EditorListener mEditorListener = null;
|
||||
|
||||
private boolean mIsMasterKey;
|
||||
ImageButton mDeleteButton;
|
||||
TextView mAlgorithm;
|
||||
TextView mKeyId;
|
||||
Spinner mUsage;
|
||||
TextView mCreationDate;
|
||||
Button mExpiryDateButton;
|
||||
GregorianCalendar mExpiryDate;
|
||||
|
||||
private DatePickerDialog.OnDateSetListener mExpiryDateSetListener =
|
||||
new DatePickerDialog.OnDateSetListener() {
|
||||
public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
|
||||
GregorianCalendar date = new GregorianCalendar(year, monthOfYear, dayOfMonth);
|
||||
setExpiryDate(date);
|
||||
}
|
||||
};
|
||||
|
||||
public KeyEditor(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public KeyEditor(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
setDrawingCacheEnabled(true);
|
||||
setAlwaysDrawnWithCacheEnabled(true);
|
||||
|
||||
mAlgorithm = (TextView) findViewById(R.id.algorithm);
|
||||
mKeyId = (TextView) findViewById(R.id.keyId);
|
||||
mCreationDate = (TextView) findViewById(R.id.creation);
|
||||
mExpiryDateButton = (Button) findViewById(R.id.expiry);
|
||||
mUsage = (Spinner) findViewById(R.id.usage);
|
||||
Choice choices[] = {
|
||||
new Choice(Id.choice.usage.sign_only,
|
||||
getResources().getString(R.string.choice_signOnly)),
|
||||
new Choice(Id.choice.usage.encrypt_only,
|
||||
getResources().getString(R.string.choice_encryptOnly)),
|
||||
new Choice(Id.choice.usage.sign_and_encrypt,
|
||||
getResources().getString(R.string.choice_signAndEncrypt)),
|
||||
};
|
||||
ArrayAdapter<Choice> adapter =
|
||||
new ArrayAdapter<Choice>(getContext(),
|
||||
android.R.layout.simple_spinner_item, choices);
|
||||
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||
mUsage.setAdapter(adapter);
|
||||
|
||||
mDeleteButton = (ImageButton) findViewById(R.id.delete);
|
||||
mDeleteButton.setOnClickListener(this);
|
||||
|
||||
setExpiryDate(null);
|
||||
|
||||
mExpiryDateButton.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
GregorianCalendar date = mExpiryDate;
|
||||
if (date == null) {
|
||||
date = new GregorianCalendar();
|
||||
}
|
||||
|
||||
DatePickerDialog dialog =
|
||||
new DatePickerDialog(getContext(), mExpiryDateSetListener,
|
||||
date.get(Calendar.YEAR),
|
||||
date.get(Calendar.MONTH),
|
||||
date.get(Calendar.DAY_OF_MONTH));
|
||||
dialog.setCancelable(true);
|
||||
dialog.setButton(Dialog.BUTTON_NEGATIVE,
|
||||
getContext().getString(R.string.btn_noDate),
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
setExpiryDate(null);
|
||||
}
|
||||
});
|
||||
dialog.show();
|
||||
}
|
||||
});
|
||||
|
||||
super.onFinishInflate();
|
||||
}
|
||||
|
||||
public void setValue(PGPSecretKey key, boolean isMasterKey) {
|
||||
mKey = key;
|
||||
|
||||
mIsMasterKey = isMasterKey;
|
||||
if (mIsMasterKey) {
|
||||
mDeleteButton.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
|
||||
mAlgorithm.setText(Apg.getAlgorithmInfo(key));
|
||||
String keyId1Str = Long.toHexString((key.getKeyID() >> 32) & 0xffffffffL);
|
||||
while (keyId1Str.length() < 8) {
|
||||
keyId1Str = "0" + keyId1Str;
|
||||
}
|
||||
String keyId2Str = Long.toHexString(key.getKeyID() & 0xffffffffL);
|
||||
while (keyId2Str.length() < 8) {
|
||||
keyId2Str = "0" + keyId2Str;
|
||||
}
|
||||
mKeyId.setText(keyId1Str + " " + keyId2Str);
|
||||
|
||||
Vector<Choice> choices = new Vector<Choice>();
|
||||
boolean isElGamalKey = (key.getPublicKey().getAlgorithm() == PGPPublicKey.ELGAMAL_ENCRYPT);
|
||||
if (!isElGamalKey) {
|
||||
choices.add(new Choice(Id.choice.usage.sign_only,
|
||||
getResources().getString(R.string.choice_signOnly)));
|
||||
}
|
||||
if (!mIsMasterKey) {
|
||||
choices.add(new Choice(Id.choice.usage.encrypt_only,
|
||||
getResources().getString(R.string.choice_encryptOnly)));
|
||||
}
|
||||
if (!isElGamalKey) {
|
||||
choices.add(new Choice(Id.choice.usage.sign_and_encrypt,
|
||||
getResources().getString(R.string.choice_signAndEncrypt)));
|
||||
}
|
||||
|
||||
ArrayAdapter<Choice> adapter =
|
||||
new ArrayAdapter<Choice>(getContext(),
|
||||
android.R.layout.simple_spinner_item, choices);
|
||||
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||
mUsage.setAdapter(adapter);
|
||||
|
||||
int selectId = 0;
|
||||
if (Apg.isEncryptionKey(key)) {
|
||||
if (Apg.isSigningKey(key)) {
|
||||
selectId = Id.choice.usage.sign_and_encrypt;
|
||||
} else {
|
||||
selectId = Id.choice.usage.encrypt_only;
|
||||
}
|
||||
} else {
|
||||
selectId = Id.choice.usage.sign_only;
|
||||
}
|
||||
|
||||
for (int i = 0; i < choices.size(); ++i) {
|
||||
if (choices.get(i).getId() == selectId) {
|
||||
mUsage.setSelection(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
GregorianCalendar cal = new GregorianCalendar();
|
||||
cal.setTime(Apg.getCreationDate(key));
|
||||
mCreationDate.setText(DateFormat.getDateInstance().format(cal.getTime()));
|
||||
cal = new GregorianCalendar();
|
||||
Date date = Apg.getExpiryDate(key);
|
||||
if (date == null) {
|
||||
setExpiryDate(null);
|
||||
} else {
|
||||
cal.setTime(Apg.getExpiryDate(key));
|
||||
setExpiryDate(cal);
|
||||
}
|
||||
}
|
||||
|
||||
public PGPSecretKey getValue() {
|
||||
return mKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
final ViewGroup parent = (ViewGroup)getParent();
|
||||
if (v == mDeleteButton) {
|
||||
parent.removeView(this);
|
||||
if (mEditorListener != null) {
|
||||
mEditorListener.onDeleted(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEditorListener(EditorListener listener) {
|
||||
mEditorListener = listener;
|
||||
}
|
||||
|
||||
private void setExpiryDate(GregorianCalendar date) {
|
||||
mExpiryDate = date;
|
||||
if (date == null) {
|
||||
mExpiryDateButton.setText(R.string.none);
|
||||
} else {
|
||||
mExpiryDateButton.setText(DateFormat.getDateInstance().format(date.getTime()));
|
||||
}
|
||||
}
|
||||
|
||||
public GregorianCalendar getExpiryDate() {
|
||||
return mExpiryDate;
|
||||
}
|
||||
|
||||
public int getUsage() {
|
||||
return ((Choice) mUsage.getSelectedItem()).getId();
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.thialfihar.android.apg.ui.widget;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.Vector;
|
||||
|
||||
import org.bouncycastle2.openpgp.PGPPublicKey;
|
||||
import org.bouncycastle2.openpgp.PGPSecretKey;
|
||||
import org.thialfihar.android.apg.Apg;
|
||||
import org.thialfihar.android.apg.Id;
|
||||
import org.thialfihar.android.apg.R;
|
||||
import org.thialfihar.android.apg.utils.Choice;
|
||||
|
||||
import android.app.DatePickerDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.DatePicker;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
|
||||
public class KeyEditor extends LinearLayout implements Editor, OnClickListener {
|
||||
private PGPSecretKey mKey;
|
||||
|
||||
private EditorListener mEditorListener = null;
|
||||
|
||||
private boolean mIsMasterKey;
|
||||
ImageButton mDeleteButton;
|
||||
TextView mAlgorithm;
|
||||
TextView mKeyId;
|
||||
Spinner mUsage;
|
||||
TextView mCreationDate;
|
||||
Button mExpiryDateButton;
|
||||
GregorianCalendar mExpiryDate;
|
||||
|
||||
private DatePickerDialog.OnDateSetListener mExpiryDateSetListener =
|
||||
new DatePickerDialog.OnDateSetListener() {
|
||||
public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
|
||||
GregorianCalendar date = new GregorianCalendar(year, monthOfYear, dayOfMonth);
|
||||
setExpiryDate(date);
|
||||
}
|
||||
};
|
||||
|
||||
public KeyEditor(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public KeyEditor(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
setDrawingCacheEnabled(true);
|
||||
setAlwaysDrawnWithCacheEnabled(true);
|
||||
|
||||
mAlgorithm = (TextView) findViewById(R.id.algorithm);
|
||||
mKeyId = (TextView) findViewById(R.id.keyId);
|
||||
mCreationDate = (TextView) findViewById(R.id.creation);
|
||||
mExpiryDateButton = (Button) findViewById(R.id.expiry);
|
||||
mUsage = (Spinner) findViewById(R.id.usage);
|
||||
Choice choices[] = {
|
||||
new Choice(Id.choice.usage.sign_only,
|
||||
getResources().getString(R.string.choice_signOnly)),
|
||||
new Choice(Id.choice.usage.encrypt_only,
|
||||
getResources().getString(R.string.choice_encryptOnly)),
|
||||
new Choice(Id.choice.usage.sign_and_encrypt,
|
||||
getResources().getString(R.string.choice_signAndEncrypt)),
|
||||
};
|
||||
ArrayAdapter<Choice> adapter =
|
||||
new ArrayAdapter<Choice>(getContext(),
|
||||
android.R.layout.simple_spinner_item, choices);
|
||||
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||
mUsage.setAdapter(adapter);
|
||||
|
||||
mDeleteButton = (ImageButton) findViewById(R.id.delete);
|
||||
mDeleteButton.setOnClickListener(this);
|
||||
|
||||
setExpiryDate(null);
|
||||
|
||||
mExpiryDateButton.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
GregorianCalendar date = mExpiryDate;
|
||||
if (date == null) {
|
||||
date = new GregorianCalendar();
|
||||
}
|
||||
|
||||
DatePickerDialog dialog =
|
||||
new DatePickerDialog(getContext(), mExpiryDateSetListener,
|
||||
date.get(Calendar.YEAR),
|
||||
date.get(Calendar.MONTH),
|
||||
date.get(Calendar.DAY_OF_MONTH));
|
||||
dialog.setCancelable(true);
|
||||
dialog.setButton(Dialog.BUTTON_NEGATIVE,
|
||||
getContext().getString(R.string.btn_noDate),
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
setExpiryDate(null);
|
||||
}
|
||||
});
|
||||
dialog.show();
|
||||
}
|
||||
});
|
||||
|
||||
super.onFinishInflate();
|
||||
}
|
||||
|
||||
public void setValue(PGPSecretKey key, boolean isMasterKey) {
|
||||
mKey = key;
|
||||
|
||||
mIsMasterKey = isMasterKey;
|
||||
if (mIsMasterKey) {
|
||||
mDeleteButton.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
|
||||
mAlgorithm.setText(Apg.getAlgorithmInfo(key));
|
||||
String keyId1Str = Long.toHexString((key.getKeyID() >> 32) & 0xffffffffL);
|
||||
while (keyId1Str.length() < 8) {
|
||||
keyId1Str = "0" + keyId1Str;
|
||||
}
|
||||
String keyId2Str = Long.toHexString(key.getKeyID() & 0xffffffffL);
|
||||
while (keyId2Str.length() < 8) {
|
||||
keyId2Str = "0" + keyId2Str;
|
||||
}
|
||||
mKeyId.setText(keyId1Str + " " + keyId2Str);
|
||||
|
||||
Vector<Choice> choices = new Vector<Choice>();
|
||||
boolean isElGamalKey = (key.getPublicKey().getAlgorithm() == PGPPublicKey.ELGAMAL_ENCRYPT);
|
||||
if (!isElGamalKey) {
|
||||
choices.add(new Choice(Id.choice.usage.sign_only,
|
||||
getResources().getString(R.string.choice_signOnly)));
|
||||
}
|
||||
if (!mIsMasterKey) {
|
||||
choices.add(new Choice(Id.choice.usage.encrypt_only,
|
||||
getResources().getString(R.string.choice_encryptOnly)));
|
||||
}
|
||||
if (!isElGamalKey) {
|
||||
choices.add(new Choice(Id.choice.usage.sign_and_encrypt,
|
||||
getResources().getString(R.string.choice_signAndEncrypt)));
|
||||
}
|
||||
|
||||
ArrayAdapter<Choice> adapter =
|
||||
new ArrayAdapter<Choice>(getContext(),
|
||||
android.R.layout.simple_spinner_item, choices);
|
||||
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||
mUsage.setAdapter(adapter);
|
||||
|
||||
int selectId = 0;
|
||||
if (Apg.isEncryptionKey(key)) {
|
||||
if (Apg.isSigningKey(key)) {
|
||||
selectId = Id.choice.usage.sign_and_encrypt;
|
||||
} else {
|
||||
selectId = Id.choice.usage.encrypt_only;
|
||||
}
|
||||
} else {
|
||||
selectId = Id.choice.usage.sign_only;
|
||||
}
|
||||
|
||||
for (int i = 0; i < choices.size(); ++i) {
|
||||
if (choices.get(i).getId() == selectId) {
|
||||
mUsage.setSelection(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
GregorianCalendar cal = new GregorianCalendar();
|
||||
cal.setTime(Apg.getCreationDate(key));
|
||||
mCreationDate.setText(DateFormat.getDateInstance().format(cal.getTime()));
|
||||
cal = new GregorianCalendar();
|
||||
Date date = Apg.getExpiryDate(key);
|
||||
if (date == null) {
|
||||
setExpiryDate(null);
|
||||
} else {
|
||||
cal.setTime(Apg.getExpiryDate(key));
|
||||
setExpiryDate(cal);
|
||||
}
|
||||
}
|
||||
|
||||
public PGPSecretKey getValue() {
|
||||
return mKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
final ViewGroup parent = (ViewGroup)getParent();
|
||||
if (v == mDeleteButton) {
|
||||
parent.removeView(this);
|
||||
if (mEditorListener != null) {
|
||||
mEditorListener.onDeleted(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEditorListener(EditorListener listener) {
|
||||
mEditorListener = listener;
|
||||
}
|
||||
|
||||
private void setExpiryDate(GregorianCalendar date) {
|
||||
mExpiryDate = date;
|
||||
if (date == null) {
|
||||
mExpiryDateButton.setText(R.string.none);
|
||||
} else {
|
||||
mExpiryDateButton.setText(DateFormat.getDateInstance().format(date.getTime()));
|
||||
}
|
||||
}
|
||||
|
||||
public GregorianCalendar getExpiryDate() {
|
||||
return mExpiryDate;
|
||||
}
|
||||
|
||||
public int getUsage() {
|
||||
return ((Choice) mUsage.getSelectedItem()).getId();
|
||||
}
|
||||
}
|
||||
|
@ -1,337 +1,337 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.thialfihar.android.apg.ui.widget;
|
||||
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.InvalidParameterException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.util.Vector;
|
||||
|
||||
import org.bouncycastle2.openpgp.PGPException;
|
||||
import org.bouncycastle2.openpgp.PGPSecretKey;
|
||||
import org.thialfihar.android.apg.Apg;
|
||||
import org.thialfihar.android.apg.Id;
|
||||
import org.thialfihar.android.apg.R;
|
||||
import org.thialfihar.android.apg.ui.widget.Editor.EditorListener;
|
||||
import org.thialfihar.android.apg.utils.Choice;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.EditText;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
public class SectionView extends LinearLayout implements OnClickListener, EditorListener, Runnable {
|
||||
private LayoutInflater mInflater;
|
||||
private View mAdd;
|
||||
private ViewGroup mEditors;
|
||||
private TextView mTitle;
|
||||
private int mType = 0;
|
||||
|
||||
private Choice mNewKeyAlgorithmChoice;
|
||||
private int mNewKeySize;
|
||||
|
||||
volatile private PGPSecretKey mNewKey;
|
||||
private ProgressDialog mProgressDialog;
|
||||
private Thread mRunningThread = null;
|
||||
|
||||
private Handler mHandler = new Handler() {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
Bundle data = msg.getData();
|
||||
if (data != null) {
|
||||
boolean closeProgressDialog = data.getBoolean("closeProgressDialog");
|
||||
if (closeProgressDialog) {
|
||||
if (mProgressDialog != null) {
|
||||
mProgressDialog.dismiss();
|
||||
mProgressDialog = null;
|
||||
}
|
||||
}
|
||||
|
||||
String error = data.getString(Apg.EXTRA_ERROR);
|
||||
if (error != null) {
|
||||
Toast.makeText(getContext(),
|
||||
getContext().getString(R.string.errorMessage, error),
|
||||
Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
boolean gotNewKey = data.getBoolean("gotNewKey");
|
||||
if (gotNewKey) {
|
||||
KeyEditor view =
|
||||
(KeyEditor) mInflater.inflate(R.layout.edit_key_key_item,
|
||||
mEditors, false);
|
||||
view.setEditorListener(SectionView.this);
|
||||
boolean isMasterKey = (mEditors.getChildCount() == 0);
|
||||
view.setValue(mNewKey, isMasterKey);
|
||||
mEditors.addView(view);
|
||||
SectionView.this.updateEditorsVisible();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public SectionView(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public SectionView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public ViewGroup getEditors() {
|
||||
return mEditors;
|
||||
}
|
||||
|
||||
public void setType(int type) {
|
||||
mType = type;
|
||||
switch (type) {
|
||||
case Id.type.user_id: {
|
||||
mTitle.setText(R.string.section_userIds);
|
||||
break;
|
||||
}
|
||||
|
||||
case Id.type.key: {
|
||||
mTitle.setText(R.string.section_keys);
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
mInflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
|
||||
setDrawingCacheEnabled(true);
|
||||
setAlwaysDrawnWithCacheEnabled(true);
|
||||
|
||||
mAdd = findViewById(R.id.header);
|
||||
mAdd.setOnClickListener(this);
|
||||
|
||||
mEditors = (ViewGroup) findViewById(R.id.editors);
|
||||
mTitle = (TextView) findViewById(R.id.title);
|
||||
|
||||
updateEditorsVisible();
|
||||
super.onFinishInflate();
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void onDeleted(Editor editor) {
|
||||
this.updateEditorsVisible();
|
||||
}
|
||||
|
||||
protected void updateEditorsVisible() {
|
||||
final boolean hasChildren = mEditors.getChildCount() > 0;
|
||||
mEditors.setVisibility(hasChildren ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void onClick(View v) {
|
||||
switch (mType) {
|
||||
case Id.type.user_id: {
|
||||
UserIdEditor view =
|
||||
(UserIdEditor) mInflater.inflate(R.layout.edit_key_user_id_item,
|
||||
mEditors, false);
|
||||
view.setEditorListener(this);
|
||||
if (mEditors.getChildCount() == 0) {
|
||||
view.setIsMainUserId(true);
|
||||
}
|
||||
mEditors.addView(view);
|
||||
break;
|
||||
}
|
||||
|
||||
case Id.type.key: {
|
||||
AlertDialog.Builder dialog = new AlertDialog.Builder(getContext());
|
||||
|
||||
View view = mInflater.inflate(R.layout.create_key, null);
|
||||
dialog.setView(view);
|
||||
dialog.setTitle(R.string.title_createKey);
|
||||
dialog.setMessage(R.string.keyCreationElGamalInfo);
|
||||
|
||||
boolean wouldBeMasterKey = (mEditors.getChildCount() == 0);
|
||||
|
||||
final Spinner algorithm = (Spinner) view.findViewById(R.id.algorithm);
|
||||
Vector<Choice> choices = new Vector<Choice>();
|
||||
choices.add(new Choice(Id.choice.algorithm.dsa,
|
||||
getResources().getString(R.string.dsa)));
|
||||
if (!wouldBeMasterKey) {
|
||||
choices.add(new Choice(Id.choice.algorithm.elgamal,
|
||||
getResources().getString(R.string.elgamal)));
|
||||
}
|
||||
|
||||
choices.add(new Choice(Id.choice.algorithm.rsa,
|
||||
getResources().getString(R.string.rsa)));
|
||||
|
||||
ArrayAdapter<Choice> adapter =
|
||||
new ArrayAdapter<Choice>(getContext(),
|
||||
android.R.layout.simple_spinner_item,
|
||||
choices);
|
||||
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||
algorithm.setAdapter(adapter);
|
||||
// make RSA the default
|
||||
for (int i = 0; i < choices.size(); ++i) {
|
||||
if (choices.get(i).getId() == Id.choice.algorithm.rsa) {
|
||||
algorithm.setSelection(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
final EditText keySize = (EditText) view.findViewById(R.id.size);
|
||||
|
||||
dialog.setPositiveButton(android.R.string.ok,
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface di, int id) {
|
||||
di.dismiss();
|
||||
try {
|
||||
mNewKeySize = Integer.parseInt("" + keySize.getText());
|
||||
} catch (NumberFormatException e) {
|
||||
mNewKeySize = 0;
|
||||
}
|
||||
|
||||
mNewKeyAlgorithmChoice = (Choice) algorithm.getSelectedItem();
|
||||
createKey();
|
||||
}
|
||||
});
|
||||
|
||||
dialog.setCancelable(true);
|
||||
dialog.setNegativeButton(android.R.string.cancel,
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface di, int id) {
|
||||
di.dismiss();
|
||||
}
|
||||
});
|
||||
|
||||
dialog.create().show();
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.updateEditorsVisible();
|
||||
}
|
||||
|
||||
public void setUserIds(Vector<String> list) {
|
||||
if (mType != Id.type.user_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
mEditors.removeAllViews();
|
||||
for (String userId : list) {
|
||||
UserIdEditor view =
|
||||
(UserIdEditor) mInflater.inflate(R.layout.edit_key_user_id_item, mEditors, false);
|
||||
view.setEditorListener(this);
|
||||
view.setValue(userId);
|
||||
if (mEditors.getChildCount() == 0) {
|
||||
view.setIsMainUserId(true);
|
||||
}
|
||||
mEditors.addView(view);
|
||||
}
|
||||
|
||||
this.updateEditorsVisible();
|
||||
}
|
||||
|
||||
public void setKeys(Vector<PGPSecretKey> list) {
|
||||
if (mType != Id.type.key) {
|
||||
return;
|
||||
}
|
||||
|
||||
mEditors.removeAllViews();
|
||||
for (PGPSecretKey key : list) {
|
||||
KeyEditor view =
|
||||
(KeyEditor) mInflater.inflate(R.layout.edit_key_key_item, mEditors, false);
|
||||
view.setEditorListener(this);
|
||||
boolean isMasterKey = (mEditors.getChildCount() == 0);
|
||||
view.setValue(key, isMasterKey);
|
||||
mEditors.addView(view);
|
||||
}
|
||||
|
||||
this.updateEditorsVisible();
|
||||
}
|
||||
|
||||
private void createKey() {
|
||||
mProgressDialog = new ProgressDialog(getContext());
|
||||
mProgressDialog.setMessage(getContext().getString(R.string.progress_generating));
|
||||
mProgressDialog.setCancelable(false);
|
||||
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
|
||||
mProgressDialog.show();
|
||||
mRunningThread = new Thread(this);
|
||||
mRunningThread.start();
|
||||
}
|
||||
|
||||
public void run() {
|
||||
String error = null;
|
||||
try {
|
||||
PGPSecretKey masterKey = null;
|
||||
String passPhrase;
|
||||
if (mEditors.getChildCount() > 0) {
|
||||
masterKey = ((KeyEditor) mEditors.getChildAt(0)).getValue();
|
||||
passPhrase = Apg.getCachedPassPhrase(masterKey.getKeyID());
|
||||
} else {
|
||||
passPhrase = "";
|
||||
}
|
||||
mNewKey = Apg.createKey(getContext(),
|
||||
mNewKeyAlgorithmChoice.getId(),
|
||||
mNewKeySize, passPhrase,
|
||||
masterKey);
|
||||
} catch (NoSuchProviderException e) {
|
||||
error = "" + e;
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
error = "" + e;
|
||||
} catch (PGPException e) {
|
||||
error = "" + e;
|
||||
} catch (InvalidParameterException e) {
|
||||
error = "" + e;
|
||||
} catch (InvalidAlgorithmParameterException e) {
|
||||
error = "" + e;
|
||||
} catch (Apg.GeneralException e) {
|
||||
error = "" + e;
|
||||
}
|
||||
|
||||
Message message = new Message();
|
||||
Bundle data = new Bundle();
|
||||
data.putBoolean("closeProgressDialog", true);
|
||||
if (error != null) {
|
||||
data.putString(Apg.EXTRA_ERROR, error);
|
||||
} else {
|
||||
data.putBoolean("gotNewKey", true);
|
||||
}
|
||||
message.setData(data);
|
||||
mHandler.sendMessage(message);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.thialfihar.android.apg.ui.widget;
|
||||
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.InvalidParameterException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.util.Vector;
|
||||
|
||||
import org.bouncycastle2.openpgp.PGPException;
|
||||
import org.bouncycastle2.openpgp.PGPSecretKey;
|
||||
import org.thialfihar.android.apg.Apg;
|
||||
import org.thialfihar.android.apg.Id;
|
||||
import org.thialfihar.android.apg.R;
|
||||
import org.thialfihar.android.apg.ui.widget.Editor.EditorListener;
|
||||
import org.thialfihar.android.apg.utils.Choice;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.EditText;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
public class SectionView extends LinearLayout implements OnClickListener, EditorListener, Runnable {
|
||||
private LayoutInflater mInflater;
|
||||
private View mAdd;
|
||||
private ViewGroup mEditors;
|
||||
private TextView mTitle;
|
||||
private int mType = 0;
|
||||
|
||||
private Choice mNewKeyAlgorithmChoice;
|
||||
private int mNewKeySize;
|
||||
|
||||
volatile private PGPSecretKey mNewKey;
|
||||
private ProgressDialog mProgressDialog;
|
||||
private Thread mRunningThread = null;
|
||||
|
||||
private Handler mHandler = new Handler() {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
Bundle data = msg.getData();
|
||||
if (data != null) {
|
||||
boolean closeProgressDialog = data.getBoolean("closeProgressDialog");
|
||||
if (closeProgressDialog) {
|
||||
if (mProgressDialog != null) {
|
||||
mProgressDialog.dismiss();
|
||||
mProgressDialog = null;
|
||||
}
|
||||
}
|
||||
|
||||
String error = data.getString(Apg.EXTRA_ERROR);
|
||||
if (error != null) {
|
||||
Toast.makeText(getContext(),
|
||||
getContext().getString(R.string.errorMessage, error),
|
||||
Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
boolean gotNewKey = data.getBoolean("gotNewKey");
|
||||
if (gotNewKey) {
|
||||
KeyEditor view =
|
||||
(KeyEditor) mInflater.inflate(R.layout.edit_key_key_item,
|
||||
mEditors, false);
|
||||
view.setEditorListener(SectionView.this);
|
||||
boolean isMasterKey = (mEditors.getChildCount() == 0);
|
||||
view.setValue(mNewKey, isMasterKey);
|
||||
mEditors.addView(view);
|
||||
SectionView.this.updateEditorsVisible();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public SectionView(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public SectionView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public ViewGroup getEditors() {
|
||||
return mEditors;
|
||||
}
|
||||
|
||||
public void setType(int type) {
|
||||
mType = type;
|
||||
switch (type) {
|
||||
case Id.type.user_id: {
|
||||
mTitle.setText(R.string.section_userIds);
|
||||
break;
|
||||
}
|
||||
|
||||
case Id.type.key: {
|
||||
mTitle.setText(R.string.section_keys);
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
mInflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
|
||||
setDrawingCacheEnabled(true);
|
||||
setAlwaysDrawnWithCacheEnabled(true);
|
||||
|
||||
mAdd = findViewById(R.id.header);
|
||||
mAdd.setOnClickListener(this);
|
||||
|
||||
mEditors = (ViewGroup) findViewById(R.id.editors);
|
||||
mTitle = (TextView) findViewById(R.id.title);
|
||||
|
||||
updateEditorsVisible();
|
||||
super.onFinishInflate();
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void onDeleted(Editor editor) {
|
||||
this.updateEditorsVisible();
|
||||
}
|
||||
|
||||
protected void updateEditorsVisible() {
|
||||
final boolean hasChildren = mEditors.getChildCount() > 0;
|
||||
mEditors.setVisibility(hasChildren ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void onClick(View v) {
|
||||
switch (mType) {
|
||||
case Id.type.user_id: {
|
||||
UserIdEditor view =
|
||||
(UserIdEditor) mInflater.inflate(R.layout.edit_key_user_id_item,
|
||||
mEditors, false);
|
||||
view.setEditorListener(this);
|
||||
if (mEditors.getChildCount() == 0) {
|
||||
view.setIsMainUserId(true);
|
||||
}
|
||||
mEditors.addView(view);
|
||||
break;
|
||||
}
|
||||
|
||||
case Id.type.key: {
|
||||
AlertDialog.Builder dialog = new AlertDialog.Builder(getContext());
|
||||
|
||||
View view = mInflater.inflate(R.layout.create_key, null);
|
||||
dialog.setView(view);
|
||||
dialog.setTitle(R.string.title_createKey);
|
||||
dialog.setMessage(R.string.keyCreationElGamalInfo);
|
||||
|
||||
boolean wouldBeMasterKey = (mEditors.getChildCount() == 0);
|
||||
|
||||
final Spinner algorithm = (Spinner) view.findViewById(R.id.algorithm);
|
||||
Vector<Choice> choices = new Vector<Choice>();
|
||||
choices.add(new Choice(Id.choice.algorithm.dsa,
|
||||
getResources().getString(R.string.dsa)));
|
||||
if (!wouldBeMasterKey) {
|
||||
choices.add(new Choice(Id.choice.algorithm.elgamal,
|
||||
getResources().getString(R.string.elgamal)));
|
||||
}
|
||||
|
||||
choices.add(new Choice(Id.choice.algorithm.rsa,
|
||||
getResources().getString(R.string.rsa)));
|
||||
|
||||
ArrayAdapter<Choice> adapter =
|
||||
new ArrayAdapter<Choice>(getContext(),
|
||||
android.R.layout.simple_spinner_item,
|
||||
choices);
|
||||
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||
algorithm.setAdapter(adapter);
|
||||
// make RSA the default
|
||||
for (int i = 0; i < choices.size(); ++i) {
|
||||
if (choices.get(i).getId() == Id.choice.algorithm.rsa) {
|
||||
algorithm.setSelection(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
final EditText keySize = (EditText) view.findViewById(R.id.size);
|
||||
|
||||
dialog.setPositiveButton(android.R.string.ok,
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface di, int id) {
|
||||
di.dismiss();
|
||||
try {
|
||||
mNewKeySize = Integer.parseInt("" + keySize.getText());
|
||||
} catch (NumberFormatException e) {
|
||||
mNewKeySize = 0;
|
||||
}
|
||||
|
||||
mNewKeyAlgorithmChoice = (Choice) algorithm.getSelectedItem();
|
||||
createKey();
|
||||
}
|
||||
});
|
||||
|
||||
dialog.setCancelable(true);
|
||||
dialog.setNegativeButton(android.R.string.cancel,
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface di, int id) {
|
||||
di.dismiss();
|
||||
}
|
||||
});
|
||||
|
||||
dialog.create().show();
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.updateEditorsVisible();
|
||||
}
|
||||
|
||||
public void setUserIds(Vector<String> list) {
|
||||
if (mType != Id.type.user_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
mEditors.removeAllViews();
|
||||
for (String userId : list) {
|
||||
UserIdEditor view =
|
||||
(UserIdEditor) mInflater.inflate(R.layout.edit_key_user_id_item, mEditors, false);
|
||||
view.setEditorListener(this);
|
||||
view.setValue(userId);
|
||||
if (mEditors.getChildCount() == 0) {
|
||||
view.setIsMainUserId(true);
|
||||
}
|
||||
mEditors.addView(view);
|
||||
}
|
||||
|
||||
this.updateEditorsVisible();
|
||||
}
|
||||
|
||||
public void setKeys(Vector<PGPSecretKey> list) {
|
||||
if (mType != Id.type.key) {
|
||||
return;
|
||||
}
|
||||
|
||||
mEditors.removeAllViews();
|
||||
for (PGPSecretKey key : list) {
|
||||
KeyEditor view =
|
||||
(KeyEditor) mInflater.inflate(R.layout.edit_key_key_item, mEditors, false);
|
||||
view.setEditorListener(this);
|
||||
boolean isMasterKey = (mEditors.getChildCount() == 0);
|
||||
view.setValue(key, isMasterKey);
|
||||
mEditors.addView(view);
|
||||
}
|
||||
|
||||
this.updateEditorsVisible();
|
||||
}
|
||||
|
||||
private void createKey() {
|
||||
mProgressDialog = new ProgressDialog(getContext());
|
||||
mProgressDialog.setMessage(getContext().getString(R.string.progress_generating));
|
||||
mProgressDialog.setCancelable(false);
|
||||
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
|
||||
mProgressDialog.show();
|
||||
mRunningThread = new Thread(this);
|
||||
mRunningThread.start();
|
||||
}
|
||||
|
||||
public void run() {
|
||||
String error = null;
|
||||
try {
|
||||
PGPSecretKey masterKey = null;
|
||||
String passPhrase;
|
||||
if (mEditors.getChildCount() > 0) {
|
||||
masterKey = ((KeyEditor) mEditors.getChildAt(0)).getValue();
|
||||
passPhrase = Apg.getCachedPassPhrase(masterKey.getKeyID());
|
||||
} else {
|
||||
passPhrase = "";
|
||||
}
|
||||
mNewKey = Apg.createKey(getContext(),
|
||||
mNewKeyAlgorithmChoice.getId(),
|
||||
mNewKeySize, passPhrase,
|
||||
masterKey);
|
||||
} catch (NoSuchProviderException e) {
|
||||
error = "" + e;
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
error = "" + e;
|
||||
} catch (PGPException e) {
|
||||
error = "" + e;
|
||||
} catch (InvalidParameterException e) {
|
||||
error = "" + e;
|
||||
} catch (InvalidAlgorithmParameterException e) {
|
||||
error = "" + e;
|
||||
} catch (Apg.GeneralException e) {
|
||||
error = "" + e;
|
||||
}
|
||||
|
||||
Message message = new Message();
|
||||
Bundle data = new Bundle();
|
||||
data.putBoolean("closeProgressDialog", true);
|
||||
if (error != null) {
|
||||
data.putString(Apg.EXTRA_ERROR, error);
|
||||
} else {
|
||||
data.putBoolean("gotNewKey", true);
|
||||
}
|
||||
message.setData(data);
|
||||
mHandler.sendMessage(message);
|
||||
}
|
||||
}
|
||||
|
@ -1,194 +1,194 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.thialfihar.android.apg.ui.widget;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.thialfihar.android.apg.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.RadioButton;
|
||||
|
||||
public class UserIdEditor extends LinearLayout implements Editor, OnClickListener {
|
||||
private EditorListener mEditorListener = null;
|
||||
|
||||
private ImageButton mDeleteButton;
|
||||
private RadioButton mIsMainUserId;
|
||||
private EditText mName;
|
||||
private EditText mEmail;
|
||||
private EditText mComment;
|
||||
|
||||
private static final Pattern EMAIL_PATTERN =
|
||||
Pattern.compile("^([a-zA-Z0-9_.-])+@([a-zA-Z0-9_.-])+[.]([a-zA-Z])+([a-zA-Z])+",
|
||||
Pattern.CASE_INSENSITIVE);
|
||||
|
||||
public static class NoNameException extends Exception {
|
||||
static final long serialVersionUID = 0xf812773343L;
|
||||
|
||||
public NoNameException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
||||
public static class NoEmailException extends Exception {
|
||||
static final long serialVersionUID = 0xf812773344L;
|
||||
|
||||
public NoEmailException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
||||
public static class InvalidEmailException extends Exception {
|
||||
static final long serialVersionUID = 0xf812773345L;
|
||||
|
||||
public InvalidEmailException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
||||
public UserIdEditor(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public UserIdEditor(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
setDrawingCacheEnabled(true);
|
||||
setAlwaysDrawnWithCacheEnabled(true);
|
||||
|
||||
mDeleteButton = (ImageButton) findViewById(R.id.delete);
|
||||
mDeleteButton.setOnClickListener(this);
|
||||
mIsMainUserId = (RadioButton) findViewById(R.id.isMainUserId);
|
||||
mIsMainUserId.setOnClickListener(this);
|
||||
|
||||
mName = (EditText) findViewById(R.id.name);
|
||||
mEmail = (EditText) findViewById(R.id.email);
|
||||
mComment = (EditText) findViewById(R.id.comment);
|
||||
|
||||
super.onFinishInflate();
|
||||
}
|
||||
|
||||
public void setValue(String userId) {
|
||||
mName.setText("");
|
||||
mComment.setText("");
|
||||
mEmail.setText("");
|
||||
|
||||
Pattern withComment = Pattern.compile("^(.*) [(](.*)[)] <(.*)>$");
|
||||
Matcher matcher = withComment.matcher(userId);
|
||||
if (matcher.matches()) {
|
||||
mName.setText(matcher.group(1));
|
||||
mComment.setText(matcher.group(2));
|
||||
mEmail.setText(matcher.group(3));
|
||||
return;
|
||||
}
|
||||
|
||||
Pattern withoutComment = Pattern.compile("^(.*) <(.*)>$");
|
||||
matcher = withoutComment.matcher(userId);
|
||||
if (matcher.matches()) {
|
||||
mName.setText(matcher.group(1));
|
||||
mEmail.setText(matcher.group(2));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public String getValue() throws NoNameException, NoEmailException, InvalidEmailException {
|
||||
String name = ("" + mName.getText()).trim();
|
||||
String email = ("" + mEmail.getText()).trim();
|
||||
String comment = ("" + mComment.getText()).trim();
|
||||
|
||||
if (email.length() > 0) {
|
||||
Matcher emailMatcher = EMAIL_PATTERN.matcher(email);
|
||||
if (!emailMatcher.matches()) {
|
||||
throw new InvalidEmailException(
|
||||
getContext().getString(R.string.error_invalidEmail, email));
|
||||
}
|
||||
}
|
||||
|
||||
String userId = name;
|
||||
if (comment.length() > 0) {
|
||||
userId += " (" + comment + ")";
|
||||
}
|
||||
if (email.length() > 0) {
|
||||
userId += " <" + email + ">";
|
||||
}
|
||||
|
||||
if (userId.equals("")) {
|
||||
// ok, empty one...
|
||||
return userId;
|
||||
}
|
||||
|
||||
// otherwise make sure that name and email exist
|
||||
if (name.equals("")) {
|
||||
throw new NoNameException("need a name");
|
||||
}
|
||||
|
||||
if (email.equals("")) {
|
||||
throw new NoEmailException("need an email");
|
||||
}
|
||||
|
||||
return userId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
final ViewGroup parent = (ViewGroup)getParent();
|
||||
if (v == mDeleteButton) {
|
||||
boolean wasMainUserId = mIsMainUserId.isChecked();
|
||||
parent.removeView(this);
|
||||
if (mEditorListener != null) {
|
||||
mEditorListener.onDeleted(this);
|
||||
}
|
||||
if (wasMainUserId && parent.getChildCount() > 0) {
|
||||
UserIdEditor editor = (UserIdEditor) parent.getChildAt(0);
|
||||
editor.setIsMainUserId(true);
|
||||
}
|
||||
} else if (v == mIsMainUserId) {
|
||||
for (int i = 0; i < parent.getChildCount(); ++i) {
|
||||
UserIdEditor editor = (UserIdEditor) parent.getChildAt(i);
|
||||
if (editor == this) {
|
||||
editor.setIsMainUserId(true);
|
||||
} else {
|
||||
editor.setIsMainUserId(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setIsMainUserId(boolean value) {
|
||||
mIsMainUserId.setChecked(value);
|
||||
}
|
||||
|
||||
public boolean isMainUserId() {
|
||||
return mIsMainUserId.isChecked();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEditorListener(EditorListener listener) {
|
||||
mEditorListener = listener;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.thialfihar.android.apg.ui.widget;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.thialfihar.android.apg.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.RadioButton;
|
||||
|
||||
public class UserIdEditor extends LinearLayout implements Editor, OnClickListener {
|
||||
private EditorListener mEditorListener = null;
|
||||
|
||||
private ImageButton mDeleteButton;
|
||||
private RadioButton mIsMainUserId;
|
||||
private EditText mName;
|
||||
private EditText mEmail;
|
||||
private EditText mComment;
|
||||
|
||||
private static final Pattern EMAIL_PATTERN =
|
||||
Pattern.compile("^([a-zA-Z0-9_.-])+@([a-zA-Z0-9_.-])+[.]([a-zA-Z])+([a-zA-Z])+",
|
||||
Pattern.CASE_INSENSITIVE);
|
||||
|
||||
public static class NoNameException extends Exception {
|
||||
static final long serialVersionUID = 0xf812773343L;
|
||||
|
||||
public NoNameException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
||||
public static class NoEmailException extends Exception {
|
||||
static final long serialVersionUID = 0xf812773344L;
|
||||
|
||||
public NoEmailException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
||||
public static class InvalidEmailException extends Exception {
|
||||
static final long serialVersionUID = 0xf812773345L;
|
||||
|
||||
public InvalidEmailException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
||||
public UserIdEditor(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public UserIdEditor(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
setDrawingCacheEnabled(true);
|
||||
setAlwaysDrawnWithCacheEnabled(true);
|
||||
|
||||
mDeleteButton = (ImageButton) findViewById(R.id.delete);
|
||||
mDeleteButton.setOnClickListener(this);
|
||||
mIsMainUserId = (RadioButton) findViewById(R.id.isMainUserId);
|
||||
mIsMainUserId.setOnClickListener(this);
|
||||
|
||||
mName = (EditText) findViewById(R.id.name);
|
||||
mEmail = (EditText) findViewById(R.id.email);
|
||||
mComment = (EditText) findViewById(R.id.comment);
|
||||
|
||||
super.onFinishInflate();
|
||||
}
|
||||
|
||||
public void setValue(String userId) {
|
||||
mName.setText("");
|
||||
mComment.setText("");
|
||||
mEmail.setText("");
|
||||
|
||||
Pattern withComment = Pattern.compile("^(.*) [(](.*)[)] <(.*)>$");
|
||||
Matcher matcher = withComment.matcher(userId);
|
||||
if (matcher.matches()) {
|
||||
mName.setText(matcher.group(1));
|
||||
mComment.setText(matcher.group(2));
|
||||
mEmail.setText(matcher.group(3));
|
||||
return;
|
||||
}
|
||||
|
||||
Pattern withoutComment = Pattern.compile("^(.*) <(.*)>$");
|
||||
matcher = withoutComment.matcher(userId);
|
||||
if (matcher.matches()) {
|
||||
mName.setText(matcher.group(1));
|
||||
mEmail.setText(matcher.group(2));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public String getValue() throws NoNameException, NoEmailException, InvalidEmailException {
|
||||
String name = ("" + mName.getText()).trim();
|
||||
String email = ("" + mEmail.getText()).trim();
|
||||
String comment = ("" + mComment.getText()).trim();
|
||||
|
||||
if (email.length() > 0) {
|
||||
Matcher emailMatcher = EMAIL_PATTERN.matcher(email);
|
||||
if (!emailMatcher.matches()) {
|
||||
throw new InvalidEmailException(
|
||||
getContext().getString(R.string.error_invalidEmail, email));
|
||||
}
|
||||
}
|
||||
|
||||
String userId = name;
|
||||
if (comment.length() > 0) {
|
||||
userId += " (" + comment + ")";
|
||||
}
|
||||
if (email.length() > 0) {
|
||||
userId += " <" + email + ">";
|
||||
}
|
||||
|
||||
if (userId.equals("")) {
|
||||
// ok, empty one...
|
||||
return userId;
|
||||
}
|
||||
|
||||
// otherwise make sure that name and email exist
|
||||
if (name.equals("")) {
|
||||
throw new NoNameException("need a name");
|
||||
}
|
||||
|
||||
if (email.equals("")) {
|
||||
throw new NoEmailException("need an email");
|
||||
}
|
||||
|
||||
return userId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
final ViewGroup parent = (ViewGroup)getParent();
|
||||
if (v == mDeleteButton) {
|
||||
boolean wasMainUserId = mIsMainUserId.isChecked();
|
||||
parent.removeView(this);
|
||||
if (mEditorListener != null) {
|
||||
mEditorListener.onDeleted(this);
|
||||
}
|
||||
if (wasMainUserId && parent.getChildCount() > 0) {
|
||||
UserIdEditor editor = (UserIdEditor) parent.getChildAt(0);
|
||||
editor.setIsMainUserId(true);
|
||||
}
|
||||
} else if (v == mIsMainUserId) {
|
||||
for (int i = 0; i < parent.getChildCount(); ++i) {
|
||||
UserIdEditor editor = (UserIdEditor) parent.getChildAt(i);
|
||||
if (editor == this) {
|
||||
editor.setIsMainUserId(true);
|
||||
} else {
|
||||
editor.setIsMainUserId(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setIsMainUserId(boolean value) {
|
||||
mIsMainUserId.setChecked(value);
|
||||
}
|
||||
|
||||
public boolean isMainUserId() {
|
||||
return mIsMainUserId.isChecked();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEditorListener(EditorListener listener) {
|
||||
mEditorListener = listener;
|
||||
}
|
||||
}
|
||||
|
@ -1,44 +1,44 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.thialfihar.android.apg.utils;
|
||||
|
||||
public class Choice {
|
||||
private String mName;
|
||||
private int mId;
|
||||
|
||||
public Choice() {
|
||||
mId = -1;
|
||||
mName = "";
|
||||
}
|
||||
|
||||
public Choice(int id, String name) {
|
||||
mId = id;
|
||||
mName = name;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return mId;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return mName;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return mName;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.thialfihar.android.apg.utils;
|
||||
|
||||
public class Choice {
|
||||
private String mName;
|
||||
private int mId;
|
||||
|
||||
public Choice() {
|
||||
mId = -1;
|
||||
mName = "";
|
||||
}
|
||||
|
||||
public Choice(int id, String name) {
|
||||
mId = id;
|
||||
mName = name;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return mId;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return mName;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return mName;
|
||||
}
|
||||
}
|
||||
|
@ -1,31 +1,31 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.thialfihar.android.apg.utils;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
public class IterableIterator<T> implements Iterable<T> {
|
||||
private Iterator<T> mIter;
|
||||
|
||||
public IterableIterator(Iterator<T> iter) {
|
||||
mIter = iter;
|
||||
}
|
||||
|
||||
public Iterator<T> iterator() {
|
||||
return mIter;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.thialfihar.android.apg.utils;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
public class IterableIterator<T> implements Iterable<T> {
|
||||
private Iterator<T> mIter;
|
||||
|
||||
public IterableIterator(Iterator<T> iter) {
|
||||
mIter = iter;
|
||||
}
|
||||
|
||||
public Iterator<T> iterator() {
|
||||
return mIter;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user