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.pngBinary files differ index 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.pngBinary files differ new 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.pngBinary files differ new 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.pngBinary files differ deleted 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.pngBinary files differ index 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.svgzBinary files differ index 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.pngBinary files differ index 9a546d45b..9a546d45b 100644 --- a/Resources/Screenshots/screenshot1.png +++ b/Resources/screenshots/screenshot1.png diff --git a/Resources/Screenshots/screenshot2.png b/Resources/screenshots/screenshot2.pngBinary files differ index e9fa49d45..e9fa49d45 100644 --- a/Resources/Screenshots/screenshot2.png +++ b/Resources/screenshots/screenshot2.png diff --git a/Resources/Screenshots/screenshot3.png b/Resources/screenshots/screenshot3.pngBinary files differ index aaec9cdb7..aaec9cdb7 100644 --- a/Resources/Screenshots/screenshot3.png +++ b/Resources/screenshots/screenshot3.png diff --git a/Resources/Screenshots/screenshot4.png b/Resources/screenshots/screenshot4.pngBinary files differ index efe44a396..efe44a396 100644 --- a/Resources/Screenshots/screenshot4.png +++ b/Resources/screenshots/screenshot4.png diff --git a/Resources/Screenshots/screenshot5.png b/Resources/screenshots/screenshot5.pngBinary files differ index 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.jarBinary files differ new 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 | 
