diff options
68 files changed, 799 insertions, 316 deletions
diff --git a/.gitignore b/.gitignore index afa9dfc45..71c11b159 100644 --- a/.gitignore +++ b/.gitignore @@ -14,9 +14,6 @@ ant.properties .gradle build gradle.properties -gradlew -gradlew.bat -gradle #Maven target diff --git a/OpenPGP-Keychain-API-Demo/AndroidManifest.xml b/OpenPGP-Keychain-API-Demo/AndroidManifest.xml index 2543f0129..8b8c43776 100644 --- a/OpenPGP-Keychain-API-Demo/AndroidManifest.xml +++ b/OpenPGP-Keychain-API-Demo/AndroidManifest.xml @@ -5,8 +5,8 @@ android:versionName="1.1" > <uses-sdk - android:minSdkVersion="7" - android:targetSdkVersion="18" /> + android:minSdkVersion="8" + android:targetSdkVersion="19" /> <application android:allowBackup="true" diff --git a/OpenPGP-Keychain-API-Demo/project.properties b/OpenPGP-Keychain-API-Demo/project.properties index 73fc66102..a5578ba09 100644 --- a/OpenPGP-Keychain-API-Demo/project.properties +++ b/OpenPGP-Keychain-API-Demo/project.properties @@ -8,4 +8,4 @@ # project structure. # Project target. -target=android-18 +target=android-19 diff --git a/OpenPGP-Keychain-API-Demo/res/xml/base_preference.xml b/OpenPGP-Keychain-API-Demo/res/xml/base_preference.xml index f36c5f5a9..5febfad44 100644 --- a/OpenPGP-Keychain-API-Demo/res/xml/base_preference.xml +++ b/OpenPGP-Keychain-API-Demo/res/xml/base_preference.xml @@ -12,6 +12,9 @@ <!-- android:title="AIDL Demo (ACCESS_KEYS permission)" /> --> <!-- </PreferenceCategory> --> <PreferenceCategory android:title="OpenPGP Provider" > + <org.openintents.openpgp.OpenPgpListPreference + android:key="openpgp_provider_list" + android:title="Select OpenPGP Provider!" /> <Preference android:key="openpgp_provider_demo" android:title="OpenPGP Provider" /> diff --git a/OpenPGP-Keychain-API-Demo/src/org/openintents/openpgp/IOpenPgpService.aidl b/OpenPGP-Keychain-API-Demo/src/org/openintents/openpgp/IOpenPgpService.aidl index 69a608dc6..8f9e8a0fd 100644 --- a/OpenPGP-Keychain-API-Demo/src/org/openintents/openpgp/IOpenPgpService.aidl +++ b/OpenPGP-Keychain-API-Demo/src/org/openintents/openpgp/IOpenPgpService.aidl @@ -25,12 +25,12 @@ import org.openintents.openpgp.IOpenPgpKeyIdsCallback; * Results are returned to the callback, which has to be implemented on client side. */ interface IOpenPgpService { - + /** - * Encrypt - * - * After successful encryption, callback's onSuccess will contain the resulting output bytes. + * Sign * + * After successful signing, callback's onSuccess will contain the resulting output. + * * @param input * OpenPgpData object containing String, byte[], ParcelFileDescriptor, or Uri * @param output @@ -45,18 +45,16 @@ interface IOpenPgpService { * Writes output to given Uri * new OpenPgpData(fileDescriptor) * Writes output to given ParcelFileDescriptor - * @param keyIds - * Key Ids of recipients. Can be retrieved with getKeyIds() * @param callback * Callback where to return results */ - oneway void encrypt(in OpenPgpData input, in OpenPgpData output, in long[] keyIds, in IOpenPgpCallback callback); + oneway void sign(in OpenPgpData input, in OpenPgpData output, in IOpenPgpCallback callback); /** - * Sign + * Encrypt + * + * After successful encryption, callback's onSuccess will contain the resulting output. * - * After successful signing, callback's onSuccess will contain the resulting output bytes. - * * @param input * OpenPgpData object containing String, byte[], ParcelFileDescriptor, or Uri * @param output @@ -71,15 +69,17 @@ interface IOpenPgpService { * Writes output to given Uri * new OpenPgpData(fileDescriptor) * Writes output to given ParcelFileDescriptor + * @param keyIds + * Key Ids of recipients. Can be retrieved with getKeyIds() * @param callback * Callback where to return results */ - oneway void sign(in OpenPgpData input, in OpenPgpData output, in IOpenPgpCallback callback); + oneway void encrypt(in OpenPgpData input, in OpenPgpData output, in long[] keyIds, in IOpenPgpCallback callback); /** * Sign then encrypt * - * After successful signing and encryption, callback's onSuccess will contain the resulting output bytes. + * After successful signing and encryption, callback's onSuccess will contain the resulting output. * * @param input * OpenPgpData object containing String, byte[], ParcelFileDescriptor, or Uri @@ -104,9 +104,9 @@ interface IOpenPgpService { /** * Decrypts and verifies given input bytes. This methods handles encrypted-only, signed-and-encrypted, - * and also signed-only inputBytes. + * and also signed-only input. * - * After successful decryption/verification, callback's onSuccess will contain the resulting output bytes. + * After successful decryption/verification, callback's onSuccess will contain the resulting output. * The signatureResult in onSuccess is only non-null if signed-and-encrypted or signed-only inputBytes were given. * * @param input diff --git a/OpenPGP-Keychain-API-Demo/src/org/openintents/openpgp/OpenPgpConstants.java b/OpenPGP-Keychain-API-Demo/src/org/openintents/openpgp/OpenPgpConstants.java new file mode 100644 index 000000000..b1ca1bfe6 --- /dev/null +++ b/OpenPGP-Keychain-API-Demo/src/org/openintents/openpgp/OpenPgpConstants.java @@ -0,0 +1,10 @@ +package org.openintents.openpgp; + +public class OpenPgpConstants { + + public static final String TAG = "OpenPgp API"; + + public static final int REQUIRED_API_VERSION = 1; + public static final String SERVICE_INTENT = "org.openintents.openpgp.IOpenPgpService"; + +} diff --git a/OpenPGP-Keychain-API-Demo/src/org/openintents/openpgp/OpenPgpHelper.java b/OpenPGP-Keychain-API-Demo/src/org/openintents/openpgp/OpenPgpHelper.java index 56c4a4dca..7305c47ce 100644 --- a/OpenPGP-Keychain-API-Demo/src/org/openintents/openpgp/OpenPgpHelper.java +++ b/OpenPGP-Keychain-API-Demo/src/org/openintents/openpgp/OpenPgpHelper.java @@ -40,7 +40,7 @@ public class OpenPgpHelper { } public boolean isAvailable() { - Intent intent = new Intent(IOpenPgpService.class.getName()); + Intent intent = new Intent(OpenPgpConstants.SERVICE_INTENT); List<ResolveInfo> resInfo = context.getPackageManager().queryIntentServices(intent, 0); if (!resInfo.isEmpty()) { return true; diff --git a/OpenPGP-Keychain-API-Demo/src/org/openintents/openpgp/OpenPgpListPreference.java b/OpenPGP-Keychain-API-Demo/src/org/openintents/openpgp/OpenPgpListPreference.java index 551401b18..c8e709df9 100644 --- a/OpenPGP-Keychain-API-Demo/src/org/openintents/openpgp/OpenPgpListPreference.java +++ b/OpenPGP-Keychain-API-Demo/src/org/openintents/openpgp/OpenPgpListPreference.java @@ -26,6 +26,8 @@ import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; +import android.graphics.Bitmap; +import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.preference.DialogPreference; import android.util.AttributeSet; @@ -39,22 +41,19 @@ public class OpenPgpListPreference extends DialogPreference { ArrayList<OpenPgpProviderEntry> mProviderList = new ArrayList<OpenPgpProviderEntry>(); private String mSelectedPackage; - public static final int REQUIRED_API_VERSION = 1; - public OpenPgpListPreference(Context context, AttributeSet attrs) { super(context, attrs); - List<ResolveInfo> resInfo = - context.getPackageManager().queryIntentServices( - new Intent(IOpenPgpService.class.getName()), PackageManager.GET_META_DATA); + List<ResolveInfo> resInfo = context.getPackageManager().queryIntentServices( + new Intent(OpenPgpConstants.SERVICE_INTENT), PackageManager.GET_META_DATA); if (!resInfo.isEmpty()) { for (ResolveInfo resolveInfo : resInfo) { if (resolveInfo.serviceInfo == null) continue; String packageName = resolveInfo.serviceInfo.packageName; - String simpleName = String.valueOf(resolveInfo.serviceInfo - .loadLabel(context.getPackageManager())); + String simpleName = String.valueOf(resolveInfo.serviceInfo.loadLabel(context + .getPackageManager())); Drawable icon = resolveInfo.serviceInfo.loadIcon(context.getPackageManager()); // get api version @@ -95,22 +94,20 @@ public class OpenPgpListPreference extends DialogPreference { TextView tv = (TextView) v.findViewById(android.R.id.text1); // Put the image on the TextView - tv.setCompoundDrawablesWithIntrinsicBounds(mProviderList.get(position).icon, - null, null, null); + tv.setCompoundDrawablesWithIntrinsicBounds(mProviderList.get(position).icon, null, + null, null); - // Add margin between image and text (support various screen - // densities) - int dp5 = (int) (5 * getContext().getResources().getDisplayMetrics().density + 0.5f); - tv.setCompoundDrawablePadding(dp5); + // Add margin between image and text (support various screen densities) + int dp10 = (int) (10 * getContext().getResources().getDisplayMetrics().density + 0.5f); + tv.setCompoundDrawablePadding(dp10); // disable if it has the wrong api_version - if (mProviderList.get(position).apiVersion == REQUIRED_API_VERSION) { + if (mProviderList.get(position).apiVersion == OpenPgpConstants.REQUIRED_API_VERSION) { tv.setEnabled(true); } else { tv.setEnabled(false); - tv.setText(tv.getText() + " (API v" - + mProviderList.get(position).apiVersion + ", needs v" - + REQUIRED_API_VERSION + ")"); + tv.setText(tv.getText() + " (API v" + mProviderList.get(position).apiVersion + + ", needs v" + OpenPgpConstants.REQUIRED_API_VERSION + ")"); } return v; @@ -125,8 +122,8 @@ public class OpenPgpListPreference extends DialogPreference { mSelectedPackage = mProviderList.get(which).packageName; /* - * Clicking on an item simulates the positive button - * click, and dismisses the dialog. + * Clicking on an item simulates the positive button click, and dismisses + * the dialog. */ OpenPgpListPreference.this.onClick(dialog, DialogInterface.BUTTON_POSITIVE); dialog.dismiss(); @@ -134,9 +131,8 @@ public class OpenPgpListPreference extends DialogPreference { }); /* - * The typical interaction for list-based dialogs is to have - * click-on-an-item dismiss the dialog instead of the user having to - * press 'Ok'. + * The typical interaction for list-based dialogs is to have click-on-an-item dismiss the + * dialog instead of the user having to press 'Ok'. */ builder.setPositiveButton(null, null); } diff --git a/OpenPGP-Keychain-API-Demo/src/org/openintents/openpgp/OpenPgpServiceConnection.java b/OpenPGP-Keychain-API-Demo/src/org/openintents/openpgp/OpenPgpServiceConnection.java index 56a922d73..f7ba06aaf 100644 --- a/OpenPGP-Keychain-API-Demo/src/org/openintents/openpgp/OpenPgpServiceConnection.java +++ b/OpenPGP-Keychain-API-Demo/src/org/openintents/openpgp/OpenPgpServiceConnection.java @@ -29,14 +29,12 @@ public class OpenPgpServiceConnection { private Context mApplicationContext; private IOpenPgpService mService; - private boolean bound; - private String cryptoProviderPackageName; - - private static final String TAG = "OpenPgpServiceConnection"; + private boolean mBound; + private String mCryptoProviderPackageName; public OpenPgpServiceConnection(Context context, String cryptoProviderPackageName) { - mApplicationContext = context.getApplicationContext(); - this.cryptoProviderPackageName = cryptoProviderPackageName; + this.mApplicationContext = context.getApplicationContext(); + this.mCryptoProviderPackageName = cryptoProviderPackageName; } public IOpenPgpService getService() { @@ -44,20 +42,20 @@ public class OpenPgpServiceConnection { } public boolean isBound() { - return bound; + return mBound; } private ServiceConnection mCryptoServiceConnection = new ServiceConnection() { public void onServiceConnected(ComponentName name, IBinder service) { mService = IOpenPgpService.Stub.asInterface(service); - Log.d(TAG, "connected to service"); - bound = true; + Log.d(OpenPgpConstants.TAG, "connected to service"); + mBound = true; } public void onServiceDisconnected(ComponentName name) { mService = null; - Log.d(TAG, "disconnected from service"); - bound = false; + Log.d(OpenPgpConstants.TAG, "disconnected from service"); + mBound = false; } }; @@ -67,23 +65,23 @@ public class OpenPgpServiceConnection { * @return */ public boolean bindToService() { - if (mService == null && !bound) { // if not already connected + if (mService == null && !mBound) { // if not already connected try { - Log.d(TAG, "not bound yet"); + Log.d(OpenPgpConstants.TAG, "not bound yet"); Intent serviceIntent = new Intent(); serviceIntent.setAction(IOpenPgpService.class.getName()); - serviceIntent.setPackage(cryptoProviderPackageName); + serviceIntent.setPackage(mCryptoProviderPackageName); mApplicationContext.bindService(serviceIntent, mCryptoServiceConnection, Context.BIND_AUTO_CREATE); return true; } catch (Exception e) { - Log.d(TAG, "Exception", e); + Log.d(OpenPgpConstants.TAG, "Exception on binding", e); return false; } - } else { // already connected - Log.d(TAG, "already bound... "); + } else { + Log.d(OpenPgpConstants.TAG, "already bound"); return true; } } diff --git a/OpenPGP-Keychain/AndroidManifest.xml b/OpenPGP-Keychain/AndroidManifest.xml index e363047e6..4b843bc01 100644 --- a/OpenPGP-Keychain/AndroidManifest.xml +++ b/OpenPGP-Keychain/AndroidManifest.xml @@ -47,7 +47,7 @@ <uses-sdk android:minSdkVersion="8" - android:targetSdkVersion="18" /> + android:targetSdkVersion="19" /> <uses-feature android:name="android.hardware.wifi" @@ -65,7 +65,6 @@ <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.NFC" /> - <uses-permission android:name="com.fsck.k9.permission.READ_ATTACHMENT" /> <!-- android:allowBackup="false": Don't allow backup over adb backup or other apps! --> <application diff --git a/OpenPGP-Keychain/build.gradle b/OpenPGP-Keychain/build.gradle index 5d55d1ea5..80c0f05cd 100644 --- a/OpenPGP-Keychain/build.gradle +++ b/OpenPGP-Keychain/build.gradle @@ -4,7 +4,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:0.5.+' + classpath 'com.android.tools.build:gradle:0.6.3' } } @@ -22,15 +22,16 @@ dependencies { compile 'com.android.support:support-v4:18.0.+' // already in actionbarsherlock compile project(':libraries:ActionBarSherlock') compile project(':libraries:HtmlTextView') + compile project(':libraries:pinned-section-listview:library') } android { - compileSdkVersion 18 - buildToolsVersion "18.0.1" + compileSdkVersion 19 + buildToolsVersion "19" defaultConfig { minSdkVersion 8 - targetSdkVersion 18 + targetSdkVersion 19 } sourceSets { diff --git a/OpenPGP-Keychain/project.properties b/OpenPGP-Keychain/project.properties index 084aff4b6..7347abfcd 100644 --- a/OpenPGP-Keychain/project.properties +++ b/OpenPGP-Keychain/project.properties @@ -8,6 +8,7 @@ # project structure. # Project target. -target=android-18 +target=android-19 android.library.reference.1=../libraries/ActionBarSherlock android.library.reference.2=../libraries/HtmlTextView +android.library.reference.3=../libraries/pinned-section-listview/library diff --git a/OpenPGP-Keychain/res/drawable-xhdpi/icon.png b/OpenPGP-Keychain/res/drawable-xhdpi/icon.png Binary files differindex 03ee31bbd..ec8e9fc6d 100644 --- a/OpenPGP-Keychain/res/drawable-xhdpi/icon.png +++ b/OpenPGP-Keychain/res/drawable-xhdpi/icon.png diff --git a/OpenPGP-Keychain/res/drawable-xxhdpi/icon.png b/OpenPGP-Keychain/res/drawable-xxhdpi/icon.png Binary files differnew file mode 100644 index 000000000..a55413501 --- /dev/null +++ b/OpenPGP-Keychain/res/drawable-xxhdpi/icon.png diff --git a/OpenPGP-Keychain/res/drawable-xxxhdpi/icon.png b/OpenPGP-Keychain/res/drawable-xxxhdpi/icon.png Binary files differnew file mode 100644 index 000000000..d4c77573e --- /dev/null +++ b/OpenPGP-Keychain/res/drawable-xxxhdpi/icon.png diff --git a/OpenPGP-Keychain/res/layout/api_app_error_message.xml b/OpenPGP-Keychain/res/layout/api_app_error_message.xml new file mode 100644 index 000000000..5927dbf43 --- /dev/null +++ b/OpenPGP-Keychain/res/layout/api_app_error_message.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:orientation="vertical" > + + <org.sufficientlysecure.htmltextview.HtmlTextView + android:id="@+id/api_app_error_message_text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:padding="8dp" + android:paddingBottom="0dip" + android:text="Set in-code!" + android:textAppearance="?android:attr/textAppearanceLarge" /> + +</LinearLayout>
\ No newline at end of file diff --git a/OpenPGP-Keychain/res/layout/api_app_settings_fragment.xml b/OpenPGP-Keychain/res/layout/api_app_settings_fragment.xml index 81b48be72..a40444e0f 100644 --- a/OpenPGP-Keychain/res/layout/api_app_settings_fragment.xml +++ b/OpenPGP-Keychain/res/layout/api_app_settings_fragment.xml @@ -1,122 +1,153 @@ <?xml version="1.0" encoding="utf-8"?> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="fill_parent" - android:layout_height="fill_parent" - android:orientation="vertical" > +<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" > - <RelativeLayout + <LinearLayout android:layout_width="match_parent" - android:layout_height="?android:attr/listPreferredItemHeight" - android:gravity="center_horizontal" - android:orientation="horizontal" - android:paddingBottom="3dip" > - - <ImageView - android:id="@+id/api_app_settings_app_icon" - android:layout_width="48dp" - android:layout_height="48dp" - android:layout_alignParentBottom="true" - android:layout_alignParentTop="true" - android:layout_marginRight="6dp" - android:src="@drawable/icon" /> - - <TextView - android:id="@+id/api_app_settings_app_name" - android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="vertical" > + + <RelativeLayout + android:layout_width="match_parent" + android:layout_height="?android:attr/listPreferredItemHeight" + android:gravity="center_horizontal" + android:orientation="horizontal" + android:paddingBottom="3dip" > + + <ImageView + android:id="@+id/api_app_settings_app_icon" + android:layout_width="48dp" + android:layout_height="48dp" + android:layout_alignParentBottom="true" + android:layout_alignParentTop="true" + android:layout_marginRight="6dp" + android:src="@drawable/icon" /> + + <TextView + android:id="@+id/api_app_settings_app_name" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_centerVertical="true" + android:layout_toRightOf="@+id/api_app_settings_app_icon" + android:gravity="center_vertical" + android:orientation="vertical" + android:text="Name (set in-code)" + android:textAppearance="?android:attr/textAppearanceMedium" /> + </RelativeLayout> + + <LinearLayout + android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_centerVertical="true" - android:layout_toRightOf="@+id/api_app_settings_app_icon" - android:gravity="center_vertical" - android:orientation="vertical" - android:text="Name (set in-code)" - android:textAppearance="?android:attr/textAppearanceMedium" /> - </RelativeLayout> + android:orientation="horizontal" > - <LinearLayout - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:orientation="horizontal" > + <Button + android:id="@+id/api_app_settings_select_key_button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:text="@string/api_settings_select_key" /> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:paddingLeft="16dp" > + + <TextView + android:id="@+id/api_app_settings_user_id" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="right" + android:ellipsize="end" + android:singleLine="true" + android:text="@string/api_settings_no_key" + android:textAppearance="?android:attr/textAppearanceMedium" /> + + <TextView + android:id="@+id/api_app_settings_user_id_rest" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="right" + android:ellipsize="end" + android:singleLine="true" + android:text="" + android:textAppearance="?android:attr/textAppearanceSmall" /> + </LinearLayout> + </LinearLayout> <Button - android:id="@+id/api_app_settings_select_key_button" - android:layout_width="wrap_content" + android:id="@+id/api_app_settings_advanced_button" + android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_gravity="center_vertical" - android:text="@string/api_settings_select_key" /> + android:text="@string/api_settings_show_advanced" /> <LinearLayout - android:layout_width="fill_parent" + android:id="@+id/api_app_settings_advanced" + android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" - android:paddingLeft="16dp" > + android:visibility="gone" > <TextView - android:id="@+id/api_app_settings_user_id" - android:layout_width="wrap_content" + android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_gravity="right" - android:ellipsize="end" - android:singleLine="true" - android:text="@string/api_settings_no_key" + android:text="@string/label_encryption_algorithm" android:textAppearance="?android:attr/textAppearanceMedium" /> + <Spinner + android:id="@+id/api_app_settings_encryption_algorithm" + android:layout_width="match_parent" + android:layout_height="wrap_content" /> + <TextView - android:id="@+id/api_app_settings_user_id_rest" - android:layout_width="wrap_content" + android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_gravity="right" - android:ellipsize="end" - android:singleLine="true" - android:text="" - android:textAppearance="?android:attr/textAppearanceSmall" /> - </LinearLayout> - </LinearLayout> - - <Button - android:id="@+id/api_app_settings_advanced_button" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="@string/api_settings_show_advanced" /> + android:text="@string/label_hash_algorithm" + android:textAppearance="?android:attr/textAppearanceMedium" /> - <LinearLayout - android:id="@+id/api_app_settings_advanced" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:orientation="vertical" - android:visibility="invisible" > + <Spinner + android:id="@+id/api_app_settings_hash_algorithm" + android:layout_width="match_parent" + android:layout_height="wrap_content" /> - <TextView - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="@string/label_encryption_algorithm" - android:textAppearance="?android:attr/textAppearanceMedium" /> + <TextView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/label_message_compression" + android:textAppearance="?android:attr/textAppearanceMedium" /> - <Spinner - android:id="@+id/api_app_settings_encryption_algorithm" - android:layout_width="match_parent" - android:layout_height="wrap_content" /> + <Spinner + android:id="@+id/api_app_settings_compression" + android:layout_width="match_parent" + android:layout_height="wrap_content" /> - <TextView - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="@string/label_hash_algorithm" - android:textAppearance="?android:attr/textAppearanceMedium" /> + <TextView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/api_settings_package_name" + android:textAppearance="?android:attr/textAppearanceMedium" /> - <Spinner - android:id="@+id/api_app_settings_hash_algorithm" - android:layout_width="match_parent" - android:layout_height="wrap_content" /> + <TextView + android:id="@+id/api_app_settings_package_name" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="com.example" + android:textAppearance="?android:attr/textAppearanceMedium" /> - <TextView - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="@string/label_message_compression" - android:textAppearance="?android:attr/textAppearanceMedium" /> + <TextView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/api_settings_package_signature" + android:textAppearance="?android:attr/textAppearanceMedium" /> - <Spinner - android:id="@+id/api_app_settings_compression" - android:layout_width="match_parent" - android:layout_height="wrap_content" /> + <TextView + android:id="@+id/api_app_settings_package_signature" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="Base64 encoded signature" + android:textAppearance="?android:attr/textAppearanceSmall" /> + </LinearLayout> </LinearLayout> -</LinearLayout>
\ No newline at end of file +</ScrollView>
\ No newline at end of file diff --git a/OpenPGP-Keychain/res/values/strings.xml b/OpenPGP-Keychain/res/values/strings.xml index 02e1e5bd1..c3736815c 100644 --- a/OpenPGP-Keychain/res/values/strings.xml +++ b/OpenPGP-Keychain/res/values/strings.xml @@ -317,7 +317,7 @@ <string name="import_qr_code_missing">Missing QR Codes: %1$s</string> <string name="import_qr_code_wrong">QR Code malformed! Please try again!</string> <string name="import_qr_code_finished">QR Code scanning finished!</string> - + <!-- Intent labels --> <string name="intent_decrypt_file">OpenPGP: Decrypt File</string> <string name="intent_import_key">OpenPGP: Import Key</string> @@ -333,6 +333,8 @@ <string name="api_settings_save">Save</string> <string name="api_settings_cancel">Cancel</string> <string name="api_settings_revoke">Revoke access</string> + <string name="api_settings_package_name">Package Name</string> + <string name="api_settings_package_signature">SHA-256 of Package Signature</string> <string name="api_register_text">The following application requests access to OpenPGP Keychain\'s API.\n\nAllow permanent access?</string> <string name="api_register_allow">Allow access</string> <string name="api_register_disallow">Disallow access</string> @@ -340,6 +342,7 @@ <string name="api_select_pub_keys_missing_text">No public keys were found for these user ids:</string> <string name="api_select_pub_keys_dublicates_text">More than one public key exist for these user ids:</string> <string name="api_select_pub_keys_text">Please review the list of recipients!</string> + <string name="api_error_wrong_signature">Signature check failed! Have you installed this app from a different source? If you are sure that this is not an attack, revoke this app\'s registration in OpenPGP Keychain and then register the app again.</string> <!-- Share --> <string name="share_qr_code_dialog_start">Go through all QR Codes using \'Next\', and scan them one by one.</string> diff --git a/OpenPGP-Keychain/src/org/openintents/openpgp/IOpenPgpService.aidl b/OpenPGP-Keychain/src/org/openintents/openpgp/IOpenPgpService.aidl index 7cbf96b56..8f9e8a0fd 100644 --- a/OpenPGP-Keychain/src/org/openintents/openpgp/IOpenPgpService.aidl +++ b/OpenPGP-Keychain/src/org/openintents/openpgp/IOpenPgpService.aidl @@ -50,7 +50,6 @@ interface IOpenPgpService { */ oneway void sign(in OpenPgpData input, in OpenPgpData output, in IOpenPgpCallback callback); - /** * Encrypt * diff --git a/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpConstants.java b/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpConstants.java new file mode 100644 index 000000000..b1ca1bfe6 --- /dev/null +++ b/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpConstants.java @@ -0,0 +1,10 @@ +package org.openintents.openpgp; + +public class OpenPgpConstants { + + public static final String TAG = "OpenPgp API"; + + public static final int REQUIRED_API_VERSION = 1; + public static final String SERVICE_INTENT = "org.openintents.openpgp.IOpenPgpService"; + +} diff --git a/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpHelper.java b/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpHelper.java index 56c4a4dca..7305c47ce 100644 --- a/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpHelper.java +++ b/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpHelper.java @@ -40,7 +40,7 @@ public class OpenPgpHelper { } public boolean isAvailable() { - Intent intent = new Intent(IOpenPgpService.class.getName()); + Intent intent = new Intent(OpenPgpConstants.SERVICE_INTENT); List<ResolveInfo> resInfo = context.getPackageManager().queryIntentServices(intent, 0); if (!resInfo.isEmpty()) { return true; diff --git a/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpListPreference.java b/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpListPreference.java index 551401b18..4ddd97485 100644 --- a/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpListPreference.java +++ b/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpListPreference.java @@ -39,22 +39,19 @@ public class OpenPgpListPreference extends DialogPreference { ArrayList<OpenPgpProviderEntry> mProviderList = new ArrayList<OpenPgpProviderEntry>(); private String mSelectedPackage; - public static final int REQUIRED_API_VERSION = 1; - public OpenPgpListPreference(Context context, AttributeSet attrs) { super(context, attrs); - List<ResolveInfo> resInfo = - context.getPackageManager().queryIntentServices( - new Intent(IOpenPgpService.class.getName()), PackageManager.GET_META_DATA); + List<ResolveInfo> resInfo = context.getPackageManager().queryIntentServices( + new Intent(OpenPgpConstants.SERVICE_INTENT), PackageManager.GET_META_DATA); if (!resInfo.isEmpty()) { for (ResolveInfo resolveInfo : resInfo) { if (resolveInfo.serviceInfo == null) continue; String packageName = resolveInfo.serviceInfo.packageName; - String simpleName = String.valueOf(resolveInfo.serviceInfo - .loadLabel(context.getPackageManager())); + String simpleName = String.valueOf(resolveInfo.serviceInfo.loadLabel(context + .getPackageManager())); Drawable icon = resolveInfo.serviceInfo.loadIcon(context.getPackageManager()); // get api version @@ -95,22 +92,20 @@ public class OpenPgpListPreference extends DialogPreference { TextView tv = (TextView) v.findViewById(android.R.id.text1); // Put the image on the TextView - tv.setCompoundDrawablesWithIntrinsicBounds(mProviderList.get(position).icon, - null, null, null); + tv.setCompoundDrawablesWithIntrinsicBounds(mProviderList.get(position).icon, null, + null, null); - // Add margin between image and text (support various screen - // densities) - int dp5 = (int) (5 * getContext().getResources().getDisplayMetrics().density + 0.5f); - tv.setCompoundDrawablePadding(dp5); + // Add margin between image and text (support various screen densities) + int dp10 = (int) (10 * getContext().getResources().getDisplayMetrics().density + 0.5f); + tv.setCompoundDrawablePadding(dp10); // disable if it has the wrong api_version - if (mProviderList.get(position).apiVersion == REQUIRED_API_VERSION) { + if (mProviderList.get(position).apiVersion == OpenPgpConstants.REQUIRED_API_VERSION) { tv.setEnabled(true); } else { tv.setEnabled(false); - tv.setText(tv.getText() + " (API v" - + mProviderList.get(position).apiVersion + ", needs v" - + REQUIRED_API_VERSION + ")"); + tv.setText(tv.getText() + " (API v" + mProviderList.get(position).apiVersion + + ", needs v" + OpenPgpConstants.REQUIRED_API_VERSION + ")"); } return v; @@ -125,8 +120,8 @@ public class OpenPgpListPreference extends DialogPreference { mSelectedPackage = mProviderList.get(which).packageName; /* - * Clicking on an item simulates the positive button - * click, and dismisses the dialog. + * Clicking on an item simulates the positive button click, and dismisses + * the dialog. */ OpenPgpListPreference.this.onClick(dialog, DialogInterface.BUTTON_POSITIVE); dialog.dismiss(); @@ -134,9 +129,8 @@ public class OpenPgpListPreference extends DialogPreference { }); /* - * The typical interaction for list-based dialogs is to have - * click-on-an-item dismiss the dialog instead of the user having to - * press 'Ok'. + * The typical interaction for list-based dialogs is to have click-on-an-item dismiss the + * dialog instead of the user having to press 'Ok'. */ builder.setPositiveButton(null, null); } diff --git a/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpServiceConnection.java b/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpServiceConnection.java index 56a922d73..f7ba06aaf 100644 --- a/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpServiceConnection.java +++ b/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpServiceConnection.java @@ -29,14 +29,12 @@ public class OpenPgpServiceConnection { private Context mApplicationContext; private IOpenPgpService mService; - private boolean bound; - private String cryptoProviderPackageName; - - private static final String TAG = "OpenPgpServiceConnection"; + private boolean mBound; + private String mCryptoProviderPackageName; public OpenPgpServiceConnection(Context context, String cryptoProviderPackageName) { - mApplicationContext = context.getApplicationContext(); - this.cryptoProviderPackageName = cryptoProviderPackageName; + this.mApplicationContext = context.getApplicationContext(); + this.mCryptoProviderPackageName = cryptoProviderPackageName; } public IOpenPgpService getService() { @@ -44,20 +42,20 @@ public class OpenPgpServiceConnection { } public boolean isBound() { - return bound; + return mBound; } private ServiceConnection mCryptoServiceConnection = new ServiceConnection() { public void onServiceConnected(ComponentName name, IBinder service) { mService = IOpenPgpService.Stub.asInterface(service); - Log.d(TAG, "connected to service"); - bound = true; + Log.d(OpenPgpConstants.TAG, "connected to service"); + mBound = true; } public void onServiceDisconnected(ComponentName name) { mService = null; - Log.d(TAG, "disconnected from service"); - bound = false; + Log.d(OpenPgpConstants.TAG, "disconnected from service"); + mBound = false; } }; @@ -67,23 +65,23 @@ public class OpenPgpServiceConnection { * @return */ public boolean bindToService() { - if (mService == null && !bound) { // if not already connected + if (mService == null && !mBound) { // if not already connected try { - Log.d(TAG, "not bound yet"); + Log.d(OpenPgpConstants.TAG, "not bound yet"); Intent serviceIntent = new Intent(); serviceIntent.setAction(IOpenPgpService.class.getName()); - serviceIntent.setPackage(cryptoProviderPackageName); + serviceIntent.setPackage(mCryptoProviderPackageName); mApplicationContext.bindService(serviceIntent, mCryptoServiceConnection, Context.BIND_AUTO_CREATE); return true; } catch (Exception e) { - Log.d(TAG, "Exception", e); + Log.d(OpenPgpConstants.TAG, "Exception on binding", e); return false; } - } else { // already connected - Log.d(TAG, "already bound... "); + } else { + Log.d(OpenPgpConstants.TAG, "already bound"); return true; } } diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/helper/ActionBarHelper.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/helper/ActionBarHelper.java index c0fc4df86..fee120273 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/helper/ActionBarHelper.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/helper/ActionBarHelper.java @@ -81,8 +81,9 @@ public class ActionBarHelper { cancelOnClickListener); // Show the custom action bar view and hide the normal Home icon and title. - actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM, ActionBar.DISPLAY_SHOW_CUSTOM - | ActionBar.DISPLAY_SHOW_HOME | ActionBar.DISPLAY_SHOW_TITLE); + actionBar.setDisplayShowTitleEnabled(false); + actionBar.setDisplayShowHomeEnabled(false); + actionBar.setDisplayShowCustomEnabled(true); actionBar.setCustomView(customActionBarView, new ActionBar.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); } @@ -102,14 +103,14 @@ public class ActionBarHelper { final View customActionBarView = inflater .inflate(R.layout.actionbar_custom_view_done, null); - ((TextView) customActionBarView.findViewById(R.id.actionbar_done_text)) - .setText(R.string.api_settings_save); + ((TextView) customActionBarView.findViewById(R.id.actionbar_done_text)).setText(doneText); customActionBarView.findViewById(R.id.actionbar_done).setOnClickListener( doneOnClickListener); // Show the custom action bar view and hide the normal Home icon and title. - actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM, ActionBar.DISPLAY_SHOW_CUSTOM - | ActionBar.DISPLAY_SHOW_HOME | ActionBar.DISPLAY_SHOW_TITLE); + actionBar.setDisplayShowTitleEnabled(false); + actionBar.setDisplayShowHomeEnabled(false); + actionBar.setDisplayShowCustomEnabled(true); actionBar.setCustomView(customActionBarView); } diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/KeychainContract.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/KeychainContract.java index ea4ca377c..82bb473f6 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/KeychainContract.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/KeychainContract.java @@ -55,6 +55,7 @@ public class KeychainContract { interface ApiAppsColumns { String PACKAGE_NAME = "package_name"; + String PACKAGE_SIGNATURE = "package_signature"; String KEY_ID = "key_id"; // not a database id String ENCRYPTION_ALGORITHM = "encryption_algorithm"; String HASH_ALORITHM = "hash_algorithm"; diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/KeychainDatabase.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/KeychainDatabase.java index 0f962967d..60c5c91a8 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/KeychainDatabase.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/KeychainDatabase.java @@ -31,7 +31,7 @@ import android.provider.BaseColumns; public class KeychainDatabase extends SQLiteOpenHelper { private static final String DATABASE_NAME = "apg.db"; - private static final int DATABASE_VERSION = 5; + private static final int DATABASE_VERSION = 6; public interface Tables { String KEY_RINGS = "key_rings"; @@ -66,9 +66,10 @@ public class KeychainDatabase extends SQLiteOpenHelper { private static final String CREATE_API_APPS = "CREATE TABLE IF NOT EXISTS " + Tables.API_APPS + " (" + BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " - + ApiAppsColumns.PACKAGE_NAME + " TEXT UNIQUE, " + ApiAppsColumns.KEY_ID + " INT64, " - + ApiAppsColumns.ENCRYPTION_ALGORITHM + " INTEGER, " + ApiAppsColumns.HASH_ALORITHM - + " INTEGER, " + ApiAppsColumns.COMPRESSION + " INTEGER)"; + + ApiAppsColumns.PACKAGE_NAME + " TEXT UNIQUE, " + ApiAppsColumns.PACKAGE_SIGNATURE + + " BLOB, " + ApiAppsColumns.KEY_ID + " INT64, " + ApiAppsColumns.ENCRYPTION_ALGORITHM + + " INTEGER, " + ApiAppsColumns.HASH_ALORITHM + " INTEGER, " + + ApiAppsColumns.COMPRESSION + " INTEGER)"; KeychainDatabase(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); @@ -110,6 +111,10 @@ public class KeychainDatabase extends SQLiteOpenHelper { break; case 4: db.execSQL(CREATE_API_APPS); + case 5: + // new column: package_signature + db.execSQL("DROP TABLE IF EXISTS " + Tables.API_APPS); + db.execSQL(CREATE_API_APPS); default: break; diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/ProviderHelper.java index 7ef61c15b..f12048277 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -742,6 +742,7 @@ public class ProviderHelper { private static ContentValues contentValueForApiApps(AppSettings appSettings) { ContentValues values = new ContentValues(); values.put(ApiApps.PACKAGE_NAME, appSettings.getPackageName()); + values.put(ApiApps.PACKAGE_SIGNATURE, appSettings.getPackageSignature()); values.put(ApiApps.KEY_ID, appSettings.getKeyId()); values.put(ApiApps.COMPRESSION, appSettings.getCompression()); values.put(ApiApps.ENCRYPTION_ALGORITHM, appSettings.getEncryptionAlgorithm()); @@ -770,6 +771,8 @@ public class ProviderHelper { settings = new AppSettings(); settings.setPackageName(cur.getString(cur .getColumnIndex(KeychainContract.ApiApps.PACKAGE_NAME))); + settings.setPackageSignature(cur.getBlob(cur + .getColumnIndex(KeychainContract.ApiApps.PACKAGE_SIGNATURE))); settings.setKeyId(cur.getLong(cur.getColumnIndex(KeychainContract.ApiApps.KEY_ID))); settings.setCompression(cur.getInt(cur .getColumnIndexOrThrow(KeychainContract.ApiApps.COMPRESSION))); @@ -781,4 +784,26 @@ public class ProviderHelper { return settings; } + + public static byte[] getApiAppSignature(Context context, String packageName) { + Uri queryUri = KeychainContract.ApiApps.buildByPackageNameUri(packageName); + + String[] projection = new String[] { ApiApps.PACKAGE_SIGNATURE }; + + ContentResolver cr = context.getContentResolver(); + Cursor cursor = cr.query(queryUri, projection, null, null, null); + + byte[] signature = null; + if (cursor != null && cursor.moveToFirst()) { + int signatureCol = 0; + + signature = cursor.getBlob(signatureCol); + } + + if (cursor != null) { + cursor.close(); + } + + return signature; + } } diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/exception/WrongPackageSignatureException.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/exception/WrongPackageSignatureException.java new file mode 100644 index 000000000..cef002265 --- /dev/null +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/exception/WrongPackageSignatureException.java @@ -0,0 +1,10 @@ +package org.sufficientlysecure.keychain.service.exception; + +public class WrongPackageSignatureException extends Exception { + + private static final long serialVersionUID = -8294642703122196028L; + + public WrongPackageSignatureException(String message) { + super(message); + } +}
\ No newline at end of file diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/AppSettings.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/AppSettings.java index 381a4065c..9da4c8392 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/AppSettings.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/AppSettings.java @@ -23,6 +23,7 @@ import org.sufficientlysecure.keychain.Id; public class AppSettings { private String packageName; + private byte[] packageSignature; private long keyId = Id.key.none; private int encryptionAlgorithm; private int hashAlgorithm; @@ -32,9 +33,10 @@ public class AppSettings { } - public AppSettings(String packageName) { + public AppSettings(String packageName, byte[] packageSignature) { super(); this.packageName = packageName; + this.packageSignature = packageSignature; // defaults: this.encryptionAlgorithm = PGPEncryptedData.AES_256; this.hashAlgorithm = HashAlgorithmTags.SHA512; @@ -49,6 +51,14 @@ public class AppSettings { this.packageName = packageName; } + public byte[] getPackageSignature() { + return packageSignature; + } + + public void setPackageSignature(byte[] packageSignature) { + this.packageSignature = packageSignature; + } + public long getKeyId() { return keyId; } diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/AppSettingsActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/AppSettingsActivity.java index 7b04d3da6..4f1bedb6f 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/AppSettingsActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/AppSettingsActivity.java @@ -41,7 +41,7 @@ public class AppSettingsActivity extends SherlockFragmentActivity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - // Inflate a "Done" custom action bar view to serve as the "Up" affordance. + // Inflate a "Done" custom action bar ActionBarHelper.setDoneView(getSupportActionBar(), R.string.api_settings_save, new View.OnClickListener() { @Override diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/AppSettingsFragment.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/AppSettingsFragment.java index 942f8eba8..e592f5d57 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/AppSettingsFragment.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/AppSettingsFragment.java @@ -17,8 +17,12 @@ package org.sufficientlysecure.keychain.service.remote; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + import org.spongycastle.openpgp.PGPSecretKey; import org.spongycastle.openpgp.PGPSecretKeyRing; +import org.spongycastle.util.encoders.Hex; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Id; import org.sufficientlysecure.keychain.R; @@ -67,6 +71,8 @@ public class AppSettingsFragment extends Fragment { private Spinner mEncryptionAlgorithm; private Spinner mHashAlgorithm; private Spinner mCompression; + private TextView mPackageName; + private TextView mPackageSignature; KeyValueSpinnerAdapter encryptionAdapter; KeyValueSpinnerAdapter hashAdapter; @@ -79,6 +85,19 @@ public class AppSettingsFragment extends Fragment { public void setAppSettings(AppSettings appSettings) { this.appSettings = appSettings; setPackage(appSettings.getPackageName()); + mPackageName.setText(appSettings.getPackageName()); + + try { + MessageDigest md = MessageDigest.getInstance("SHA-256"); + md.update(appSettings.getPackageSignature()); + byte[] digest = md.digest(); + String signature = new String(Hex.encode(digest)); + + mPackageSignature.setText(signature); + } catch (NoSuchAlgorithmException e) { + Log.e(Constants.TAG, "Should not happen!", e); + } + updateSelectedKeyView(appSettings.getKeyId()); mEncryptionAlgorithm.setSelection(encryptionAdapter.getPosition(appSettings .getEncryptionAlgorithm())); @@ -110,6 +129,8 @@ public class AppSettingsFragment extends Fragment { .findViewById(R.id.api_app_settings_encryption_algorithm); mHashAlgorithm = (Spinner) view.findViewById(R.id.api_app_settings_hash_algorithm); mCompression = (Spinner) view.findViewById(R.id.api_app_settings_compression); + mPackageName = (TextView) view.findViewById(R.id.api_app_settings_package_name); + mPackageSignature = (TextView) view.findViewById(R.id.api_app_settings_package_signature); AlgorithmNames algorithmNames = new AlgorithmNames(getActivity()); @@ -182,7 +203,7 @@ public class AppSettingsFragment extends Fragment { public void onClick(View v) { if (mAdvancedSettingsContainer.getVisibility() == View.VISIBLE) { mAdvancedSettingsContainer.startAnimation(invisibleAnimation); - mAdvancedSettingsContainer.setVisibility(View.INVISIBLE); + mAdvancedSettingsContainer.setVisibility(View.GONE); mAdvancedSettingsButton.setText(R.string.api_settings_show_advanced); } else { mAdvancedSettingsContainer.startAnimation(visibleAnimation); diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/RemoteService.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/RemoteService.java index 4e8c4678a..bc513d532 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/RemoteService.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/RemoteService.java @@ -18,18 +18,25 @@ package org.sufficientlysecure.keychain.service.remote; import java.util.ArrayList; +import java.util.Arrays; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.TimeUnit; import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.service.exception.WrongPackageSignatureException; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.PausableThreadPoolExecutor; import android.app.Service; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.Signature; import android.net.Uri; import android.os.Binder; import android.os.Bundle; @@ -38,7 +45,7 @@ import android.os.Message; import android.os.Messenger; /** - * Abstract service for remote APIs that handle app registration and user input. + * Abstract service class for remote APIs that handle app registration and user input. */ public abstract class RemoteService extends Service { Context mContext; @@ -98,32 +105,61 @@ public abstract class RemoteService extends Service { * @param r */ protected void checkAndEnqueue(Runnable r) { - if (isCallerAllowed(false)) { - mThreadPool.execute(r); - - Log.d(Constants.TAG, "Enqueued runnable…"); - } else { - String[] callingPackages = getPackageManager() - .getPackagesForUid(Binder.getCallingUid()); - - Log.e(Constants.TAG, "Not allowed to use service! Starting activity for registration!"); - Bundle extras = new Bundle(); - // TODO: currently simply uses first entry - extras.putString(RemoteServiceActivity.EXTRA_PACKAGE_NAME, callingPackages[0]); - - RegisterActivityCallback callback = new RegisterActivityCallback(); - - pauseAndStartUserInteraction(RemoteServiceActivity.ACTION_REGISTER, callback, extras); - - if (callback.isAllowed()) { + try { + if (isCallerAllowed(false)) { mThreadPool.execute(r); + Log.d(Constants.TAG, "Enqueued runnable…"); } else { - Log.d(Constants.TAG, "User disallowed app!"); + String[] callingPackages = getPackageManager().getPackagesForUid( + Binder.getCallingUid()); + // TODO: currently simply uses first entry + String packageName = callingPackages[0]; + + byte[] packageSignature; + try { + packageSignature = getPackageSignature(packageName); + } catch (NameNotFoundException e) { + Log.e(Constants.TAG, "Should not happen, returning!", e); + return; + } + Log.e(Constants.TAG, + "Not allowed to use service! Starting activity for registration!"); + Bundle extras = new Bundle(); + extras.putString(RemoteServiceActivity.EXTRA_PACKAGE_NAME, packageName); + extras.putByteArray(RemoteServiceActivity.EXTRA_PACKAGE_SIGNATURE, packageSignature); + RegisterActivityCallback callback = new RegisterActivityCallback(); + + pauseAndStartUserInteraction(RemoteServiceActivity.ACTION_REGISTER, callback, + extras); + + if (callback.isAllowed()) { + mThreadPool.execute(r); + Log.d(Constants.TAG, "Enqueued runnable…"); + } else { + Log.d(Constants.TAG, "User disallowed app!"); + } } + } catch (WrongPackageSignatureException e) { + Log.e(Constants.TAG, e.getMessage()); + + Bundle extras = new Bundle(); + extras.putString(RemoteServiceActivity.EXTRA_ERROR_MESSAGE, + getString(R.string.api_error_wrong_signature)); + pauseAndStartUserInteraction(RemoteServiceActivity.ACTION_ERROR_MESSAGE, null, extras); } } + private byte[] getPackageSignature(String packageName) throws NameNotFoundException { + PackageInfo pkgInfo = getPackageManager().getPackageInfo(packageName, + PackageManager.GET_SIGNATURES); + Signature[] signatures = pkgInfo.signatures; + // TODO: Only first signature?! + byte[] packageSignature = signatures[0].toByteArray(); + + return packageSignature; + } + /** * Locks current thread and pauses execution of runnables and starts activity for user input * @@ -200,15 +236,25 @@ public abstract class RemoteService extends Service { packageName = msg.getData().getString(PACKAGE_NAME); // resume threads - if (isPackageAllowed(packageName, false)) { - synchronized (userInputLock) { - userInputLock.notifyAll(); + try { + if (isPackageAllowed(packageName)) { + synchronized (userInputLock) { + userInputLock.notifyAll(); + } + mThreadPool.resume(); + } else { + // Should not happen! + Log.e(Constants.TAG, "Should not happen! Emergency shutdown!"); + mThreadPool.shutdownNow(); } - mThreadPool.resume(); - } else { - // Should not happen! - Log.e(Constants.TAG, "Should not happen! Emergency shutdown!"); - mThreadPool.shutdownNow(); + } catch (WrongPackageSignatureException e) { + Log.e(Constants.TAG, e.getMessage()); + + Bundle extras = new Bundle(); + extras.putString(RemoteServiceActivity.EXTRA_ERROR_MESSAGE, + getString(R.string.api_error_wrong_signature)); + pauseAndStartUserInteraction(RemoteServiceActivity.ACTION_ERROR_MESSAGE, null, + extras); } } else { allowed = false; @@ -230,15 +276,28 @@ public abstract class RemoteService extends Service { * @param allowOnlySelf * allow only Keychain app itself * @return true if process is allowed to use this service + * @throws WrongPackageSignatureException */ - private boolean isCallerAllowed(boolean allowOnlySelf) { - String[] callingPackages = getPackageManager().getPackagesForUid(Binder.getCallingUid()); + private boolean isCallerAllowed(boolean allowOnlySelf) throws WrongPackageSignatureException { + return isUidAllowed(Binder.getCallingUid(), allowOnlySelf); + } + + private boolean isUidAllowed(int uid, boolean allowOnlySelf) + throws WrongPackageSignatureException { + if (android.os.Process.myUid() == uid) { + return true; + } + if (allowOnlySelf) { // barrier + return false; + } + + String[] callingPackages = getPackageManager().getPackagesForUid(uid); // is calling package allowed to use this service? for (int i = 0; i < callingPackages.length; i++) { String currentPkg = callingPackages[i]; - if (isPackageAllowed(currentPkg, allowOnlySelf)) { + if (isPackageAllowed(currentPkg)) { return true; } } @@ -248,28 +307,39 @@ public abstract class RemoteService extends Service { } /** - * Checks if packageName is a registered app for the API. + * Checks if packageName is a registered app for the API. Does not return true for own package! * * @param packageName - * @param allowOnlySelf - * allow only Keychain app itself * @return + * @throws WrongPackageSignatureException */ - private boolean isPackageAllowed(String packageName, boolean allowOnlySelf) { + private boolean isPackageAllowed(String packageName) throws WrongPackageSignatureException { Log.d(Constants.TAG, "packageName: " + packageName); - ArrayList<String> allowedPkgs = ProviderHelper.getRegisteredApiApps(mContext); + ArrayList<String> allowedPkgs = ProviderHelper.getRegisteredApiApps(this); Log.d(Constants.TAG, "allowed: " + allowedPkgs); // check if package is allowed to use our service - if (allowedPkgs.contains(packageName) && (!allowOnlySelf)) { + if (allowedPkgs.contains(packageName)) { Log.d(Constants.TAG, "Package is allowed! packageName: " + packageName); - return true; - } else if (Constants.PACKAGE_NAME.equals(packageName)) { - Log.d(Constants.TAG, "Package is OpenPGP Keychain! -> allowed!"); + // check package signature + byte[] currentSig; + try { + currentSig = getPackageSignature(packageName); + } catch (NameNotFoundException e) { + throw new WrongPackageSignatureException(e.getMessage()); + } - return true; + byte[] storedSig = ProviderHelper.getApiAppSignature(this, packageName); + if (Arrays.equals(currentSig, storedSig)) { + Log.d(Constants.TAG, + "Package signature is correct! (equals signature from database)"); + return true; + } else { + throw new WrongPackageSignatureException( + "PACKAGE NOT ALLOWED! Signature wrong! (Signature not equals signature from database)"); + } } return false; diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/RemoteServiceActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/RemoteServiceActivity.java index 2c4bb4e97..de07989d8 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/RemoteServiceActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/RemoteServiceActivity.java @@ -48,6 +48,8 @@ public class RemoteServiceActivity extends SherlockFragmentActivity { + "API_ACTIVITY_CACHE_PASSPHRASE"; public static final String ACTION_SELECT_PUB_KEYS = Constants.INTENT_PREFIX + "API_ACTIVITY_SELECT_PUB_KEYS"; + public static final String ACTION_ERROR_MESSAGE = Constants.INTENT_PREFIX + + "API_ACTIVITY_ERROR_MESSAGE"; public static final String EXTRA_MESSENGER = "messenger"; @@ -55,10 +57,13 @@ public class RemoteServiceActivity extends SherlockFragmentActivity { public static final String EXTRA_SECRET_KEY_ID = "secret_key_id"; // register action public static final String EXTRA_PACKAGE_NAME = "package_name"; + public static final String EXTRA_PACKAGE_SIGNATURE = "package_signature"; // select pub keys action public static final String EXTRA_SELECTED_MASTER_KEY_IDS = "master_key_ids"; public static final String EXTRA_MISSING_USER_IDS = "missing_user_ids"; public static final String EXTRA_DUBLICATE_USER_IDS = "dublicate_user_ids"; + // error message + public static final String EXTRA_ERROR_MESSAGE = "error_message"; private Messenger mMessenger; @@ -110,6 +115,7 @@ public class RemoteServiceActivity extends SherlockFragmentActivity { */ if (ACTION_REGISTER.equals(action)) { final String packageName = extras.getString(EXTRA_PACKAGE_NAME); + final byte[] packageSignature = extras.getByteArray(EXTRA_PACKAGE_SIGNATURE); // Inflate a "Done"/"Cancel" custom action bar view ActionBarHelper.setDoneCancelView(getSupportActionBar(), R.string.api_register_allow, @@ -166,7 +172,7 @@ public class RemoteServiceActivity extends SherlockFragmentActivity { mSettingsFragment = (AppSettingsFragment) getSupportFragmentManager().findFragmentById( R.id.api_app_settings_fragment); - AppSettings settings = new AppSettings(packageName); + AppSettings settings = new AppSettings(packageName, packageSignature); mSettingsFragment.setAppSettings(settings); } else if (ACTION_CACHE_PASSPHRASE.equals(action)) { long secretKeyId = extras.getLong(EXTRA_SECRET_KEY_ID); @@ -269,6 +275,27 @@ public class RemoteServiceActivity extends SherlockFragmentActivity { getSupportFragmentManager().beginTransaction() .add(R.id.api_select_pub_keys_fragment_container, mSelectFragment).commit(); } + } else if (ACTION_ERROR_MESSAGE.equals(action)) { + String errorMessage = intent.getStringExtra(EXTRA_ERROR_MESSAGE); + + String text = new String(); + text += "<font color=\"red\">" + errorMessage + "</font>"; + + // Inflate a "Done" custom action bar view + ActionBarHelper.setDoneView(getSupportActionBar(), R.string.btn_okay, + new View.OnClickListener() { + + @Override + public void onClick(View v) { + finish(); + } + }); + + setContentView(R.layout.api_app_error_message); + + // set text on view + HtmlTextView textView = (HtmlTextView) findViewById(R.id.api_app_error_message_text); + textView.setHtmlFromString(text); } else { Log.e(Constants.TAG, "Wrong action!"); finish(); diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EditKeyActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EditKeyActivity.java index 1e62d06e3..7abee78f3 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EditKeyActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/EditKeyActivity.java @@ -58,10 +58,8 @@ import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.LinearLayout; -import android.widget.TextView; import android.widget.Toast; -import com.actionbarsherlock.app.ActionBar; import com.actionbarsherlock.app.SherlockFragmentActivity; public class EditKeyActivity extends SherlockFragmentActivity { @@ -81,8 +79,6 @@ public class EditKeyActivity extends SherlockFragmentActivity { public static final String RESULT_EXTRA_MASTER_KEY_ID = "master_key_id"; public static final String RESULT_EXTRA_USER_ID = "user_id"; - private ActionBar mActionBar; - private PGPSecretKeyRing mKeyRing = null; private SectionView mUserIdsView; @@ -107,26 +103,15 @@ public class EditKeyActivity extends SherlockFragmentActivity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - // Inflate a "Done"/"Cancel" custom action bar view - final LayoutInflater inflater = (LayoutInflater) getSupportActionBar().getThemedContext() - .getSystemService(LAYOUT_INFLATER_SERVICE); - final View customActionBarView = inflater.inflate( - R.layout.actionbar_custom_view_done_cancel, null); - - ((TextView) customActionBarView.findViewById(R.id.actionbar_done_text)) - .setText(R.string.btn_save); - customActionBarView.findViewById(R.id.actionbar_done).setOnClickListener( + // Inflate a "Done"/"Cancel" custom action bar + ActionBarHelper.setDoneCancelView(getSupportActionBar(), R.string.btn_save, new View.OnClickListener() { @Override public void onClick(View v) { // save saveClicked(); } - }); - ((TextView) customActionBarView.findViewById(R.id.actionbar_cancel_text)) - .setText(R.string.btn_do_not_save); - customActionBarView.findViewById(R.id.actionbar_cancel).setOnClickListener( - new View.OnClickListener() { + }, R.string.btn_do_not_save, new View.OnClickListener() { @Override public void onClick(View v) { // cancel @@ -134,21 +119,8 @@ public class EditKeyActivity extends SherlockFragmentActivity { } }); - // Show the custom action bar view and hide the normal Home icon and title. - final ActionBar actionBar = getSupportActionBar(); - actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM, ActionBar.DISPLAY_SHOW_CUSTOM - | ActionBar.DISPLAY_SHOW_HOME | ActionBar.DISPLAY_SHOW_TITLE); - actionBar.setCustomView(customActionBarView, new ActionBar.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); - setContentView(R.layout.edit_key); - mActionBar = getSupportActionBar(); - mActionBar.setDisplayShowTitleEnabled(true); - - // set actionbar without home button if called from another app - ActionBarHelper.setBackButton(this); - // find views mChangePassPhrase = (Button) findViewById(R.id.edit_key_btn_change_pass_phrase); mNoPassphrase = (CheckBox) findViewById(R.id.edit_key_no_passphrase); @@ -201,8 +173,6 @@ public class EditKeyActivity extends SherlockFragmentActivity { private void handleActionCreateKey(Intent intent) { Bundle extras = intent.getExtras(); - mActionBar.setTitle(R.string.title_create_key); - mCurrentPassPhrase = ""; if (extras != null) { @@ -330,8 +300,6 @@ public class EditKeyActivity extends SherlockFragmentActivity { private void handleActionEditKey(Intent intent) { Bundle extras = intent.getExtras(); - mActionBar.setTitle(R.string.title_edit_key); - if (extras != null) { if (extras.containsKey(EXTRA_MASTER_CAN_SIGN)) { masterCanSign = extras.getBoolean(EXTRA_MASTER_CAN_SIGN); @@ -9,36 +9,27 @@ see http://sufficientlysecure.org/keychain Translations are managed at Transifex, please contribute there at https://www.transifex.com/projects/p/openpgp-keychain/ -# Build +## Code Contributions + +Fork OpenPGP Keychain and do a pull request. I will help with occuring problems and merge your changes back into the main project. +I am happy about every code contribution and appreciate your effort to help us developing OpenPGP Keychain :) ## Build with Gradle 1. Have Android SDK "tools", "platform-tools", and "build-tools" directories in your PATH (http://developer.android.com/sdk/index.html) 2. Export ANDROID_HOME pointing to your Android SDK -3. Install gradle -4. Execute ``gradle wrapper`` (http://www.gradle.org/docs/current/userguide/gradle_wrapper.html) -5. Execute ``./gradlew build`` - -## Build with Ant - -1. Have Android SDK "tools" directory in your PATH (http://developer.android.com/sdk/index.html) -2. Execute ``android update project -p OpenPGP-Keychain`` -3. Execute ``android update project -p libraries/ActionBarSherlock`` -3. Execute ``android update project -p libraries/HtmlTextView`` -3. Execute ``cd OpenPGP-Kechain``, ``ant debug`` - -# Contribute - -Fork OpenPGP Keychain and do a merge request. I will merge your changes back into the main project. +3. Download Android Support Repository, and Google Repository using Android SDK Manager +4. Execute ``./gradlew build`` ## Development with Eclipse Android Studio is currently not supported or recommended! 1. File -> Import -> Android -> Existing Android Code Into Workspace, choose "libraries/ActionBarSherlock" -1. File -> Import -> Android -> Existing Android Code Into Workspace, choose "libraries/HtmlTextView" -2. File -> Import -> Android -> Existing Android Code Into Workspace, choose "OpenPGP-Keychain" -3. OpenPGP-Kechain can now be build +2. File -> Import -> Android -> Existing Android Code Into Workspace, choose "libraries/HtmlTextView" +3. File -> Import -> Android -> Existing Android Code Into Workspace, choose "libraries/pinned-section-listview/library" +4. File -> Import -> Android -> Existing Android Code Into Workspace, choose "OpenPGP-Keychain" +5. OpenPGP-Kechain can now be build # Keychain API @@ -220,6 +211,10 @@ Some parts (older parts and some libraries are Apache License v2, MIT X11 Licens * ZXing QRCode Integration http://code.google.com/p/zxing/ Apache License v2 + +* pinned-section-listview + https://github.com/beworker/pinned-section-listview + Apache License v2 ## Images diff --git a/Resources/Graphics/icon_googlecode.png b/Resources/Graphics/icon_googlecode.png Binary files differdeleted file mode 100644 index 33acccfd3..000000000 --- a/Resources/Graphics/icon_googlecode.png +++ /dev/null diff --git a/Resources/Graphics/dashboard_decrypt_default.svg b/Resources/graphics/dashboard_decrypt_default.svg index 1b934251f..1b934251f 100644 --- a/Resources/Graphics/dashboard_decrypt_default.svg +++ b/Resources/graphics/dashboard_decrypt_default.svg diff --git a/Resources/Graphics/dashboard_decrypt_pressed.svg b/Resources/graphics/dashboard_decrypt_pressed.svg index 1795a58ed..1795a58ed 100644 --- a/Resources/Graphics/dashboard_decrypt_pressed.svg +++ b/Resources/graphics/dashboard_decrypt_pressed.svg diff --git a/Resources/Graphics/dashboard_encrypt_default.svg b/Resources/graphics/dashboard_encrypt_default.svg index 13ba746d3..13ba746d3 100644 --- a/Resources/Graphics/dashboard_encrypt_default.svg +++ b/Resources/graphics/dashboard_encrypt_default.svg diff --git a/Resources/Graphics/dashboard_encrypt_pressed.svg b/Resources/graphics/dashboard_encrypt_pressed.svg index c0e58d848..c0e58d848 100644 --- a/Resources/Graphics/dashboard_encrypt_pressed.svg +++ b/Resources/graphics/dashboard_encrypt_pressed.svg diff --git a/Resources/Graphics/dashboard_help_default.svg b/Resources/graphics/dashboard_help_default.svg index 9031729a3..9031729a3 100755 --- a/Resources/Graphics/dashboard_help_default.svg +++ b/Resources/graphics/dashboard_help_default.svg diff --git a/Resources/Graphics/dashboard_help_pressed.svg b/Resources/graphics/dashboard_help_pressed.svg index 1e22f4679..1e22f4679 100644 --- a/Resources/Graphics/dashboard_help_pressed.svg +++ b/Resources/graphics/dashboard_help_pressed.svg diff --git a/Resources/Graphics/dashboard_import_default.svg b/Resources/graphics/dashboard_import_default.svg index f59856e13..f59856e13 100644 --- a/Resources/Graphics/dashboard_import_default.svg +++ b/Resources/graphics/dashboard_import_default.svg diff --git a/Resources/Graphics/dashboard_import_pressed.svg b/Resources/graphics/dashboard_import_pressed.svg index 34cba7aab..34cba7aab 100644 --- a/Resources/Graphics/dashboard_import_pressed.svg +++ b/Resources/graphics/dashboard_import_pressed.svg diff --git a/Resources/Graphics/dashboard_manage_keys_default.svg b/Resources/graphics/dashboard_manage_keys_default.svg index b292673da..b292673da 100644 --- a/Resources/Graphics/dashboard_manage_keys_default.svg +++ b/Resources/graphics/dashboard_manage_keys_default.svg diff --git a/Resources/Graphics/dashboard_manage_keys_pressed.svg b/Resources/graphics/dashboard_manage_keys_pressed.svg index a8eeb8cff..a8eeb8cff 100644 --- a/Resources/Graphics/dashboard_manage_keys_pressed.svg +++ b/Resources/graphics/dashboard_manage_keys_pressed.svg diff --git a/Resources/Graphics/dashboard_my_keys_default.svg b/Resources/graphics/dashboard_my_keys_default.svg index 3f509c6f8..3f509c6f8 100644 --- a/Resources/Graphics/dashboard_my_keys_default.svg +++ b/Resources/graphics/dashboard_my_keys_default.svg diff --git a/Resources/Graphics/dashboard_my_keys_pressed.svg b/Resources/graphics/dashboard_my_keys_pressed.svg index 5d84e1131..5d84e1131 100644 --- a/Resources/Graphics/dashboard_my_keys_pressed.svg +++ b/Resources/graphics/dashboard_my_keys_pressed.svg diff --git a/Resources/Graphics/dashboard_scan_qrcode_default.svg b/Resources/graphics/dashboard_scan_qrcode_default.svg index bc49aa6a6..bc49aa6a6 100644 --- a/Resources/Graphics/dashboard_scan_qrcode_default.svg +++ b/Resources/graphics/dashboard_scan_qrcode_default.svg diff --git a/Resources/Graphics/dashboard_scan_qrcode_pressed.svg b/Resources/graphics/dashboard_scan_qrcode_pressed.svg index c1bd869ac..c1bd869ac 100644 --- a/Resources/Graphics/dashboard_scan_qrcode_pressed.svg +++ b/Resources/graphics/dashboard_scan_qrcode_pressed.svg diff --git a/Resources/Graphics/icon_google_play.png b/Resources/graphics/icon.png Binary files differindex d5d86ebbc..d5d86ebbc 100644 --- a/Resources/Graphics/icon_google_play.png +++ b/Resources/graphics/icon.png diff --git a/Resources/Graphics/icon.svg b/Resources/graphics/icon.svg index f07999465..f07999465 100644 --- a/Resources/Graphics/icon.svg +++ b/Resources/graphics/icon.svg diff --git a/Resources/Graphics/icon_sizes.txt b/Resources/graphics/icon_sizes.txt index 2e960f6fd..2e960f6fd 100644 --- a/Resources/Graphics/icon_sizes.txt +++ b/Resources/graphics/icon_sizes.txt diff --git a/Resources/Graphics/key.svg b/Resources/graphics/key.svg index 0fc167869..0fc167869 100644 --- a/Resources/Graphics/key.svg +++ b/Resources/graphics/key.svg diff --git a/Resources/Graphics/kgpg_key2_kopete.svgz b/Resources/graphics/kgpg_key2_kopete.svgz Binary files differindex 2d43afb83..2d43afb83 100644 --- a/Resources/Graphics/kgpg_key2_kopete.svgz +++ b/Resources/graphics/kgpg_key2_kopete.svgz diff --git a/Resources/graphics/update-icon.sh b/Resources/graphics/update-icon.sh new file mode 100755 index 000000000..307541f2c --- /dev/null +++ b/Resources/graphics/update-icon.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +APP_DIR=../../OpenPGP-Keychain +LDPI_DIR=$APP_DIR/res/drawable-ldpi +MDPI_DIR=$APP_DIR/res/drawable-mdpi +HDPI_DIR=$APP_DIR/res/drawable-hdpi +XDPI_DIR=$APP_DIR/res/drawable-xhdpi +XXDPI_DIR=$APP_DIR/res/drawable-xxhdpi +XXXDPI_DIR=$APP_DIR/res/drawable-xxxhdpi +PLAY_DIR=./ + + +# Launcher Icon: +# ----------------------- +# ldpi: 36x36 +# mdpi: 48x48 +# hdpi: 72x72 +# xhdpi: 96x96 +# xxhdpi: 144x144. +# xxxhdpi 192x192. +# google play: 512x512 + +NAME="icon" + +inkscape -w 36 -h 36 -e "$LDPI_DIR/$NAME.png" $NAME.svg +inkscape -w 48 -h 48 -e "$MDPI_DIR/$NAME.png" $NAME.svg +inkscape -w 72 -h 72 -e "$HDPI_DIR/$NAME.png" $NAME.svg +inkscape -w 96 -h 96 -e "$XDPI_DIR/$NAME.png" $NAME.svg +inkscape -w 144 -h 144 -e "$XXDPI_DIR/$NAME.png" $NAME.svg +inkscape -w 192 -h 192 -e "$XXXDPI_DIR/$NAME.png" $NAME.svg +inkscape -w 512 -h 512 -e "$PLAY_DIR/$NAME.png" $NAME.svg + diff --git a/Resources/Screenshots/screenshot1.png b/Resources/screenshots/screenshot1.png Binary files differindex 9a546d45b..9a546d45b 100644 --- a/Resources/Screenshots/screenshot1.png +++ b/Resources/screenshots/screenshot1.png diff --git a/Resources/Screenshots/screenshot2.png b/Resources/screenshots/screenshot2.png Binary files differindex e9fa49d45..e9fa49d45 100644 --- a/Resources/Screenshots/screenshot2.png +++ b/Resources/screenshots/screenshot2.png diff --git a/Resources/Screenshots/screenshot3.png b/Resources/screenshots/screenshot3.png Binary files differindex aaec9cdb7..aaec9cdb7 100644 --- a/Resources/Screenshots/screenshot3.png +++ b/Resources/screenshots/screenshot3.png diff --git a/Resources/Screenshots/screenshot4.png b/Resources/screenshots/screenshot4.png Binary files differindex efe44a396..efe44a396 100644 --- a/Resources/Screenshots/screenshot4.png +++ b/Resources/screenshots/screenshot4.png diff --git a/Resources/Screenshots/screenshot5.png b/Resources/screenshots/screenshot5.png Binary files differindex 9356ca106..9356ca106 100644 --- a/Resources/Screenshots/screenshot5.png +++ b/Resources/screenshots/screenshot5.png diff --git a/build.gradle b/build.gradle index 63ba66abf..06c57cd0b 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:0.5.+' + classpath 'com.android.tools.build:gradle:0.6.3' } } @@ -15,5 +15,5 @@ allprojects { } task wrapper(type: Wrapper) { - gradleVersion = '1.6' + gradleVersion = '1.8' } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar Binary files differnew file mode 100644 index 000000000..667288ad6 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.jar diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..f984ebc0a --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Mon Dec 30 23:22:47 CET 2013 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=http\://services.gradle.org/distributions/gradle-1.8-bin.zip diff --git a/gradlew b/gradlew new file mode 100755 index 000000000..91a7e269e --- /dev/null +++ b/gradlew @@ -0,0 +1,164 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# For Cygwin, ensure paths are in UNIX format before anything is touched. +if $cygwin ; then + [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` +fi + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >&- +APP_HOME="`pwd -P`" +cd "$SAVED" >&- + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 000000000..aec99730b --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/libraries/HtmlTextView/build.gradle b/libraries/HtmlTextView/build.gradle index 40a586dab..1fd554404 100644 --- a/libraries/HtmlTextView/build.gradle +++ b/libraries/HtmlTextView/build.gradle @@ -3,7 +3,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:0.5.+' + classpath 'com.android.tools.build:gradle:0.6.3' } } diff --git a/settings.gradle b/settings.gradle index 08454c958..2e582798c 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,3 +1,4 @@ include ':OpenPGP-Keychain' include ':libraries:ActionBarSherlock' -include ':libraries:HtmlTextView'
\ No newline at end of file +include ':libraries:HtmlTextView' +include ':libraries:pinned-section-listview:library'
\ No newline at end of file |