mirror of
https://github.com/moparisthebest/open-keychain
synced 2024-12-25 08:28:50 -05:00
Merge branch 'master' of github.com:open-keychain/open-keychain
This commit is contained in:
commit
a50fe142e4
11
CHANGELOG
11
CHANGELOG
@ -1,3 +1,14 @@
|
|||||||
|
## 3.0
|
||||||
|
* Fix Yubikey signature generation and decryption
|
||||||
|
* Propose installable compatible apps in apps list
|
||||||
|
* New design for decryption screens
|
||||||
|
* Many fixes for key import, also fixes stripped keys
|
||||||
|
* Honor and display key authenticate flags
|
||||||
|
* User interface to generate custom keys
|
||||||
|
* Fixing user id revocation certificates
|
||||||
|
* New cloud search (searches over traditional keyservers and keybase.io)
|
||||||
|
* Support to strip keys inside OpenKeychain
|
||||||
|
|
||||||
## 2.9.2
|
## 2.9.2
|
||||||
* Fix keys broken in 2.9.1
|
* Fix keys broken in 2.9.1
|
||||||
* Yubikey decryption now working via API
|
* Yubikey decryption now working via API
|
||||||
|
@ -17,13 +17,14 @@
|
|||||||
|
|
||||||
package org.sufficientlysecure.keychain.remote.ui;
|
package org.sufficientlysecure.keychain.remote.ui;
|
||||||
|
|
||||||
|
import android.content.ActivityNotFoundException;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
|
import android.database.CursorJoiner;
|
||||||
import android.database.MatrixCursor;
|
import android.database.MatrixCursor;
|
||||||
import android.database.MergeCursor;
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.v4.app.ListFragment;
|
import android.support.v4.app.ListFragment;
|
||||||
@ -56,11 +57,23 @@ public class AppsListFragment extends ListFragment implements
|
|||||||
getListView().setOnItemClickListener(new OnItemClickListener() {
|
getListView().setOnItemClickListener(new OnItemClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
|
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
|
||||||
|
boolean isInstalled = mAdapter.getItemIsInstalled(position);
|
||||||
String selectedPackageName = mAdapter.getItemPackageName(position);
|
String selectedPackageName = mAdapter.getItemPackageName(position);
|
||||||
|
|
||||||
|
if (isInstalled) {
|
||||||
// edit app settings
|
// edit app settings
|
||||||
Intent intent = new Intent(getActivity(), AppSettingsActivity.class);
|
Intent intent = new Intent(getActivity(), AppSettingsActivity.class);
|
||||||
intent.setData(KeychainContract.ApiApps.buildByPackageNameUri(selectedPackageName));
|
intent.setData(KeychainContract.ApiApps.buildByPackageNameUri(selectedPackageName));
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
startActivity(new Intent(Intent.ACTION_VIEW,
|
||||||
|
Uri.parse("market://details?id=" + selectedPackageName)));
|
||||||
|
} catch (ActivityNotFoundException anfe) {
|
||||||
|
startActivity(new Intent(Intent.ACTION_VIEW,
|
||||||
|
Uri.parse("http://play.google.com/store/apps/details?id=" + selectedPackageName)));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -80,12 +93,22 @@ public class AppsListFragment extends ListFragment implements
|
|||||||
getLoaderManager().initLoader(0, null, this);
|
getLoaderManager().initLoader(0, null, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final String TEMP_COLUMN_INSTALLED = "INSTALLED";
|
||||||
|
private static final String TEMP_COLUMN_NAME = "NAME";
|
||||||
|
|
||||||
// These are the Contacts rows that we will retrieve.
|
// These are the Contacts rows that we will retrieve.
|
||||||
static final String[] PROJECTION = new String[]{
|
static final String[] PROJECTION = new String[]{
|
||||||
ApiApps._ID, // 0
|
ApiApps._ID, // 0
|
||||||
ApiApps.PACKAGE_NAME // 1
|
ApiApps.PACKAGE_NAME, // 1
|
||||||
|
"0 as " + TEMP_COLUMN_INSTALLED, // changed later in cursor joiner
|
||||||
|
"null as " + TEMP_COLUMN_NAME // installed apps can retrieve app name from Android OS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private static final int INDEX_ID = 0;
|
||||||
|
private static final int INDEX_PACKAGE_NAME = 1;
|
||||||
|
private static final int INDEX_INSTALLED = 2;
|
||||||
|
private static final int INDEX_NAME = 3;
|
||||||
|
|
||||||
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
|
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
|
||||||
// This is called when a new Loader needs to be created. This
|
// This is called when a new Loader needs to be created. This
|
||||||
// sample only has one Loader, so we don't care about the ID.
|
// sample only has one Loader, so we don't care about the ID.
|
||||||
@ -100,18 +123,89 @@ public class AppsListFragment extends ListFragment implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
|
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
|
||||||
MatrixCursor matrixCursor = new MatrixCursor(
|
MatrixCursor availableAppsCursor = new MatrixCursor(new String[]{
|
||||||
new String[]{ApiApps._ID, ApiApps.PACKAGE_NAME, ApiApps.PACKAGE_SIGNATURE}
|
ApiApps._ID,
|
||||||
);
|
ApiApps.PACKAGE_NAME,
|
||||||
matrixCursor.addRow(new Object[]{200, "com.fsck.k9", new byte[]{}});
|
TEMP_COLUMN_INSTALLED,
|
||||||
|
TEMP_COLUMN_NAME
|
||||||
|
});
|
||||||
|
availableAppsCursor.addRow(new Object[]{1, "com.fsck.k9", 0, "K-9 Mail"});
|
||||||
|
availableAppsCursor.addRow(new Object[]{1, "eu.siacs.conversations", 0, "Conversations (Instant Messaging)"});
|
||||||
|
// availableAppsCursor.addRow(new Object[]{1, "org.sufficientlysecure.keychain.demo", 0, "API Example"});
|
||||||
|
|
||||||
|
MatrixCursor mergedCursor = new MatrixCursor(new String[]{
|
||||||
|
ApiApps._ID,
|
||||||
|
ApiApps.PACKAGE_NAME,
|
||||||
|
TEMP_COLUMN_INSTALLED,
|
||||||
|
TEMP_COLUMN_NAME
|
||||||
|
});
|
||||||
|
|
||||||
|
CursorJoiner joiner = new CursorJoiner(
|
||||||
|
availableAppsCursor,
|
||||||
|
new String[]{ApiApps.PACKAGE_NAME},
|
||||||
|
data,
|
||||||
|
new String[]{ApiApps.PACKAGE_NAME});
|
||||||
|
for (CursorJoiner.Result joinerResult : joiner) {
|
||||||
|
switch (joinerResult) {
|
||||||
|
case LEFT: {
|
||||||
|
// handle case where a row in cursorA is unique
|
||||||
|
mergedCursor.addRow(new Object[]{
|
||||||
|
availableAppsCursor.getLong(INDEX_ID),
|
||||||
|
availableAppsCursor.getString(INDEX_PACKAGE_NAME),
|
||||||
|
availableAppsCursor.getInt(INDEX_INSTALLED),
|
||||||
|
availableAppsCursor.getString(INDEX_NAME)
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case RIGHT: {
|
||||||
|
// handle case where a row in cursorB is unique
|
||||||
|
String packageName = data.getString(INDEX_PACKAGE_NAME);
|
||||||
|
int installed;
|
||||||
|
try {
|
||||||
|
getActivity().getPackageManager().getApplicationInfo(packageName, 0);
|
||||||
|
installed = 1;
|
||||||
|
} catch (final PackageManager.NameNotFoundException e) {
|
||||||
|
installed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
mergedCursor.addRow(new Object[]{
|
||||||
|
data.getLong(INDEX_ID),
|
||||||
|
packageName,
|
||||||
|
installed,
|
||||||
|
null
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BOTH: {
|
||||||
|
// handle case where a row with the same key is in both cursors
|
||||||
|
String packageName = data.getString(INDEX_PACKAGE_NAME);
|
||||||
|
String name;
|
||||||
|
int installed;
|
||||||
|
try {
|
||||||
|
getActivity().getPackageManager().getApplicationInfo(packageName, 0);
|
||||||
|
installed = 1;
|
||||||
|
name = data.getString(INDEX_NAME);
|
||||||
|
} catch (final PackageManager.NameNotFoundException e) {
|
||||||
|
installed = 0;
|
||||||
|
// if not installed take name from available apps list
|
||||||
|
name = availableAppsCursor.getString(INDEX_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
mergedCursor.addRow(new Object[]{
|
||||||
|
data.getLong(INDEX_ID),
|
||||||
|
packageName,
|
||||||
|
installed,
|
||||||
|
name
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MergeCursor mergeCursor = new MergeCursor(
|
|
||||||
new Cursor[]{matrixCursor, data}
|
|
||||||
);
|
|
||||||
|
|
||||||
// Swap the new cursor in. (The framework will take care of closing the
|
// Swap the new cursor in. (The framework will take care of closing the
|
||||||
// old cursor once we return.)
|
// old cursor once we return.)
|
||||||
mAdapter.swapCursor(mergeCursor);
|
mAdapter.swapCursor(mergedCursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onLoaderReset(Loader<Cursor> loader) {
|
public void onLoaderReset(Loader<Cursor> loader) {
|
||||||
@ -143,7 +237,7 @@ public class AppsListFragment extends ListFragment implements
|
|||||||
public String getItemPackageName(int position) {
|
public String getItemPackageName(int position) {
|
||||||
if (mDataValid && mCursor != null) {
|
if (mDataValid && mCursor != null) {
|
||||||
if (mCursor.moveToPosition(position)) {
|
if (mCursor.moveToPosition(position)) {
|
||||||
return mCursor.getString(1);
|
return mCursor.getString(INDEX_PACKAGE_NAME);
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -152,14 +246,29 @@ public class AppsListFragment extends ListFragment implements
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean getItemIsInstalled(int position) {
|
||||||
|
if (mDataValid && mCursor != null) {
|
||||||
|
if (mCursor.moveToPosition(position)) {
|
||||||
|
return (mCursor.getInt(INDEX_INSTALLED) == 1);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void bindView(View view, Context context, Cursor cursor) {
|
public void bindView(View view, Context context, Cursor cursor) {
|
||||||
TextView text = (TextView) view.findViewById(R.id.api_apps_adapter_item_name);
|
TextView text = (TextView) view.findViewById(R.id.api_apps_adapter_item_name);
|
||||||
ImageView icon = (ImageView) view.findViewById(R.id.api_apps_adapter_item_icon);
|
ImageView icon = (ImageView) view.findViewById(R.id.api_apps_adapter_item_icon);
|
||||||
|
ImageView installIcon = (ImageView) view.findViewById(R.id.api_apps_adapter_install_icon);
|
||||||
|
|
||||||
String packageName = cursor.getString(cursor.getColumnIndex(ApiApps.PACKAGE_NAME));
|
String packageName = cursor.getString(INDEX_PACKAGE_NAME);
|
||||||
if (packageName != null) {
|
int installed = cursor.getInt(INDEX_INSTALLED);
|
||||||
// get application name
|
String name = cursor.getString(INDEX_NAME);
|
||||||
|
|
||||||
|
// get application name and icon
|
||||||
try {
|
try {
|
||||||
ApplicationInfo ai = mPM.getApplicationInfo(packageName, 0);
|
ApplicationInfo ai = mPM.getApplicationInfo(packageName, 0);
|
||||||
|
|
||||||
@ -167,11 +276,17 @@ public class AppsListFragment extends ListFragment implements
|
|||||||
icon.setImageDrawable(mPM.getApplicationIcon(ai));
|
icon.setImageDrawable(mPM.getApplicationIcon(ai));
|
||||||
} catch (final PackageManager.NameNotFoundException e) {
|
} catch (final PackageManager.NameNotFoundException e) {
|
||||||
// fallback
|
// fallback
|
||||||
|
if (name == null) {
|
||||||
text.setText(packageName);
|
text.setText(packageName);
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// fallback
|
text.setText(name);
|
||||||
text.setText("No Name");
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (installed == 1) {
|
||||||
|
installIcon.setVisibility(View.GONE);
|
||||||
|
} else {
|
||||||
|
installIcon.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,4 +23,15 @@
|
|||||||
android:layout_centerVertical="true"
|
android:layout_centerVertical="true"
|
||||||
android:layout_toRightOf="@+id/api_apps_adapter_item_icon" />
|
android:layout_toRightOf="@+id/api_apps_adapter_item_icon" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/api_apps_adapter_install_icon"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:src="@drawable/ic_action_download"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_alignParentRight="true"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
android:padding="8dp" />
|
||||||
|
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
@ -7,7 +7,7 @@ And don't add newlines before or after p tags because of transifex -->
|
|||||||
<body>
|
<body>
|
||||||
<h2>How to receive keys</h2>
|
<h2>How to receive keys</h2>
|
||||||
<ol>
|
<ol>
|
||||||
<li>Go to your partners contacts and open the contact you want to share.</li>
|
<li>Go to your partners keys and open the key you want to share.</li>
|
||||||
<li>Hold the two devices back to back (they have to be almost touching) and you’ll feel a vibration.</li>
|
<li>Hold the two devices back to back (they have to be almost touching) and you’ll feel a vibration.</li>
|
||||||
<li>After it vibrates you’ll see the content on your partners device turn into a card-like object with Star Trek warp speed-looking animation in the background.</li>
|
<li>After it vibrates you’ll see the content on your partners device turn into a card-like object with Star Trek warp speed-looking animation in the background.</li>
|
||||||
<li>Tap the card and the content will then load on the your device.</li>
|
<li>Tap the card and the content will then load on the your device.</li>
|
||||||
|
@ -6,15 +6,9 @@ And don't add newlines before or after p tags because of transifex -->
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h2>Getting started</h2>
|
<h2>Getting started</h2>
|
||||||
<p>First you need a personal secret key. Create one via the option menus in "Keys" or import existing secret keys. Afterwards, you can download your friends' keys or exchange them via QR Codes or NFC.</p>
|
<p>First you need a personal key. Create one via the menu in "Keys" or import existing secret keys. Afterwards, you can download your friends' keys or exchange them via QR Codes or NFC.</p>
|
||||||
|
|
||||||
<p>It is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection and <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> to scan generated QR Codes. Clicking on the links will open Google Play Store or F-Droid for installation.</p>
|
<p>On Android lower 4.4, it is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection. To share via QR Codes install <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a>. Clicking on the links will open Google Play Store or F-Droid for installation.</p>
|
||||||
|
|
||||||
<h2>Applications</h2>
|
|
||||||
<p>Several applications support OpenKeychain to encrypt/sign your private communication:
|
|
||||||
<br/><img src="apps_k9"/><br/>K-9 Mail: OpenKeychain support available in current <a href="https://github.com/k9mail/k-9/releases/tag/4.904">alpha build</a>!
|
|
||||||
<br/><a href="market://details?id=eu.siacs.conversations"><img src="apps_conversations"/><br/>Conversations</a>: Jabber/XMPP client
|
|
||||||
<br/><a href="market://details?id=org.lf_net.pgpunlocker"><img src="apps_pgpauth"/><br/>PGPAuth</a>: App to send a PGP-signed request to a server to open or close something, e.g. a door</p>
|
|
||||||
|
|
||||||
<h2>I found a bug in OpenKeychain!</h2>
|
<h2>I found a bug in OpenKeychain!</h2>
|
||||||
<p>Please report the bug using the <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">issue tracker of OpenKeychain</a>.</p>
|
<p>Please report the bug using the <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">issue tracker of OpenKeychain</a>.</p>
|
||||||
|
Loading…
Reference in New Issue
Block a user