implement combined EXTRA_STREAM/EXTRA_TEXT Intents for createChooser()

An app can create an `ACTION_SEND Intent` to share a file and/or text
to another app.  This `Intent` can provide an `InputStream` to get the
actual file via `EXTRA_STREAM`.  This `Intent` can also include
`EXTRA_TEXT` to describe what the shared file is.  Apps like K-9Mail,
Gmail, Signal, etc. correctly handle this case and include both the
file itself and the related text in the draft message.

This is used in F-Droid to share apps.  The text is the
name/description of the app and the URL that points to the app's page
on f-droid.org.  The `EXTRA_STREAM` is the actual APK if available.
Having all together means that the user can choose to share a message
or the actual APK, depending on the receiving app.

Unfortunately, not all apps handle this well.  WhatsApp and Element
only attach the file and ignore the text.
https://github.com/vector-im/element-android/issues/3637
This commit is contained in:
Hans-Christoph Steiner
2021-06-29 10:56:24 +02:00
parent 29a1869818
commit 402cbcc3c2
3 changed files with 115 additions and 42 deletions

View File

@@ -3,7 +3,9 @@ package org.fdroid.fdroid.nearby;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.provider.MediaStore;
import org.apache.commons.io.FileUtils;
import org.junit.Before;
@@ -19,6 +21,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
@RunWith(AndroidJUnit4.class)
@@ -65,4 +68,30 @@ public class PublicSourceDirProviderTest {
}
}
}
/**
* Test whether querying the custom {@link android.content.ContentProvider}
* for installed APKs returns the right kind of data.
*/
@Test
public void testQuery() throws IOException {
PackageManager pm = context.getPackageManager();
List<PackageInfo> packageInfoList = pm.getInstalledPackages(0);
for (PackageInfo packageInfo : packageInfoList) {
File apk = new File(packageInfo.applicationInfo.publicSourceDir);
if (apk.getCanonicalPath().startsWith("/system")) {
continue;
}
Uri uri = PublicSourceDirProvider.getUri(context, packageInfo.packageName);
Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
assertNotNull(cursor);
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
assertNotNull(cursor.getString(cursor.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME)));
cursor.moveToNext();
}
cursor.close();
}
}
}