propose apps in apps list

This commit is contained in:
Dominik Schürmann 2014-09-24 14:45:51 +02:00
parent 5b0cc1fab4
commit e3a185f698
4 changed files with 157 additions and 37 deletions

View File

@ -17,13 +17,14 @@
package org.sufficientlysecure.keychain.remote.ui;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.database.CursorJoiner;
import android.database.MatrixCursor;
import android.database.MergeCursor;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
@ -56,11 +57,23 @@ public class AppsListFragment extends ListFragment implements
getListView().setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
boolean isInstalled = mAdapter.getItemIsInstalled(position);
String selectedPackageName = mAdapter.getItemPackageName(position);
// edit app settings
Intent intent = new Intent(getActivity(), AppSettingsActivity.class);
intent.setData(KeychainContract.ApiApps.buildByPackageNameUri(selectedPackageName));
startActivity(intent);
if (isInstalled) {
// edit app settings
Intent intent = new Intent(getActivity(), AppSettingsActivity.class);
intent.setData(KeychainContract.ApiApps.buildByPackageNameUri(selectedPackageName));
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);
}
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.
static final String[] PROJECTION = new String[]{
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) {
// 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.
@ -100,18 +123,89 @@ public class AppsListFragment extends ListFragment implements
}
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
MatrixCursor matrixCursor = new MatrixCursor(
new String[]{ApiApps._ID, ApiApps.PACKAGE_NAME, ApiApps.PACKAGE_SIGNATURE}
);
matrixCursor.addRow(new Object[]{200, "com.fsck.k9", new byte[]{}});
MatrixCursor availableAppsCursor = new MatrixCursor(new String[]{
ApiApps._ID,
ApiApps.PACKAGE_NAME,
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
// old cursor once we return.)
mAdapter.swapCursor(mergeCursor);
mAdapter.swapCursor(mergedCursor);
}
public void onLoaderReset(Loader<Cursor> loader) {
@ -143,7 +237,7 @@ public class AppsListFragment extends ListFragment implements
public String getItemPackageName(int position) {
if (mDataValid && mCursor != null) {
if (mCursor.moveToPosition(position)) {
return mCursor.getString(1);
return mCursor.getString(INDEX_PACKAGE_NAME);
} else {
return null;
}
@ -152,26 +246,47 @@ 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
public void bindView(View view, Context context, Cursor cursor) {
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 installIcon = (ImageView) view.findViewById(R.id.api_apps_adapter_install_icon);
String packageName = cursor.getString(cursor.getColumnIndex(ApiApps.PACKAGE_NAME));
if (packageName != null) {
// get application name
try {
ApplicationInfo ai = mPM.getApplicationInfo(packageName, 0);
String packageName = cursor.getString(INDEX_PACKAGE_NAME);
int installed = cursor.getInt(INDEX_INSTALLED);
String name = cursor.getString(INDEX_NAME);
text.setText(mPM.getApplicationLabel(ai));
icon.setImageDrawable(mPM.getApplicationIcon(ai));
} catch (final PackageManager.NameNotFoundException e) {
// fallback
text.setText(packageName);
}
} else {
// get application name and icon
try {
ApplicationInfo ai = mPM.getApplicationInfo(packageName, 0);
text.setText(mPM.getApplicationLabel(ai));
icon.setImageDrawable(mPM.getApplicationIcon(ai));
} catch (final PackageManager.NameNotFoundException e) {
// fallback
text.setText("No Name");
if (name == null) {
text.setText(packageName);
} else {
text.setText(name);
}
}
if (installed == 1) {
installIcon.setVisibility(View.GONE);
} else {
installIcon.setVisibility(View.VISIBLE);
}
}

View File

@ -23,4 +23,15 @@
android:layout_centerVertical="true"
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>

View File

@ -7,7 +7,7 @@ And don't add newlines before or after p tags because of transifex -->
<body>
<h2>How to receive keys</h2>
<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 youll feel a vibration.</li>
<li>After it vibrates youll 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>

View File

@ -6,15 +6,9 @@ And don't add newlines before or after p tags because of transifex -->
</head>
<body>
<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>
<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>
<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>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>