i've a pdf file in my app assets directory that i want open using an external app, so wrote my content provider and i'm tryng to make it work but nothing...
here is the code:
Content Provider:
package package.name;
import java.io.File;
import java.io.FileNotFoundException;
import java.net.URI;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
public class FileContentProvider extends ContentProvider {
private static final String URI_PREFIX = "content://package.name.filecontentprovider";
public static String constructUri(String url) {
Uri uri = Uri.parse(url);
return uri.isAbsolute() ? url : URI_PREFIX + url;
}
@Override
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
URI uri1 = URI.create("file:///data/data/package.name/"+uri.getPath());
File file = new File(uri1.getPath());
ParcelFileDescriptor parcel = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
return parcel;
}
@Override
public boolean onCreate() {
return true;
}
@Override
public int delete(Uri uri, String s, String[] as) {
throw new UnsupportedOperationException("Not supported by this provider");
}
@Override
public String getType(Uri uri) {
throw new UnsupportedOperationException("Not supported by this provider");
}
@Override
public Uri insert(Uri uri, ContentValues contentvalues) {
throw new UnsupportedOperationException("Not supported by this provider");
}
@Override
public Cursor query(Uri uri, String[] as, String s, String[] as1, String s1) {
throw new UnsupportedOperationException("Not supported by this provider");
}
@Override
public int update(Uri uri, ContentValues contentvalues, String s, String[] as) {
throw new UnsupportedOperationException("Not supported by this provider");
}
}
and here how i call the opening of the file:
File pdf = new File("assets/prova.pdf");
Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse("content://package.name/" + pdf));
i.setType("application/pdf");
startActivity(i);
i've added the following line in the android manifest, inside the tag:
<provider android:name=".FileContentProvider" android:authorities="package.name" />
this is the logcat output:
02-26 19:47:44.938: ERROR/AndroidRuntime(6494): Uncaught handler: thread main exiting due to uncaught exception
02-26 19:47:44.953: ERROR/AndroidRuntime(6494): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.tf.thinkdroid.samsung/com.tf.thinkdroid.pdf.app.PdfRenderScreen}: java.lang.NullPointerException
02-26 19:47:44.953: ERROR/AndroidRuntime(6494): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2496)
02-26 19:47:44.953: ERROR/AndroidRuntime(6494): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2512)
02-26 19:47:44.953: ERROR/AndroidRuntime(6494): at android.app.ActivityThread.access$2200(ActivityThread.java:119)
02-26 19:47:44.953: ERROR/AndroidRuntime(6494): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1863)
02-26 19:47:44.953: ERROR/AndroidRuntime(6494): at android.os.Handler.dispatchMessage(Handler.java:99)
02-26 19:47:44.953: ERROR/AndroidRuntime(6494): at android.os.Looper.loop(Looper.java:123)
02-26 19:47:44.953: ERROR/AndroidRuntime(6494): at android.app.ActivityThread.main(ActivityThread.java:4363)
02-26 19:47:44.953: ERROR/AndroidRuntime(6494): at java.lang.reflect.Method.invokeNative(Native Method)
02-26 19:47:44.953: ERROR/AndroidRuntime(6494): at java.lang.reflect.Method.invoke(Method.java:521)
02-26 19:47:44.953: ERROR/AndroidRuntime(6494): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:862)
02-26 19:47:44.953: ERROR/AndroidRuntime(6494): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:620)
02-26 19:47:44.953: ERROR/AndroidRuntime(6494): at dalvik.system.NativeStart.main(Native Method)
02-26 19:47:44.953: ERROR/AndroidRuntime(6494): Caused by: java.lang.NullPointerException
02-26 19:47:44.953: ERROR/AndroidRuntime(6494): at com.tf.thinkdroid.pdf.app.RenderScreen.onNewIntent(Unknown Source)
02-26 19:47:44.953: ERROR/AndroidRuntime(6494): at com.tf.thinkdroid.pdf.app.RenderScreen.onCreate(Unknown Source)
02-26 19:47:44.953: ERROR/AndroidRuntime(6494): at com.tf.thinkdroid.pdf.app.PdfRenderScreen.onCreate(Unknown Source)
02-26 19:47:44.953: ERROR/AndroidRuntime(6494): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
02-26 19:47:44.953: ERROR/AndroidRuntime(6494): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2459)
02-26 19:47:44.953: ERROR/AndroidRuntime(6494): ... 11 more
don't understand where the problem is, seem that the external application can't get the file.
thanks for any help!
My implementation is below. Note that if your filename is MyPdf.pdf, the file should be assets/public_pdfs/MyPdf.pdf.mp3. The path public_pdfs is to only export the pdfs you really want to export, and the .mp3 extension is to prevent compression.
AndroidManifest.xml
<provider android:authorities="my.app.PdfContentProvider" android:enabled="true" android:exported="true" android:name="my.app.PdfContentProvider">
</provider>
Opening a PDF
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
Uri uri = Uri.parse("content://my.app.PdfContentProvider/" + filename);
intent.setDataAndType(uri, "application/pdf");
startActivity(intent);
PdfContentProvider.java
public class PdfContentProvider extends ContentProvider
{
private static final String PDFPATH = "public_pdfs/";
@Override
public String getType(Uri uri)
{
return "application/pdf";
}
@Override
public AssetFileDescriptor openAssetFile(Uri uri, String mode) throws FileNotFoundException
{
AssetManager am = getContext().getAssets();
String file_name = uri.getLastPathSegment();
if (file_name == null) throw new FileNotFoundException();
AssetFileDescriptor afd = null;
try
{
afd = am.openFd(PDFPATH + file_name + ".mp3");
}
catch (IOException e)
{
e.printStackTrace();
}
return afd;
}
private final static String[] COLUMNS = {OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE};
@Override
/**
* This function is required for it to work on the Quickoffice at Android 4.4 (KitKat)
*/
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
{
if (projection == null)
{
projection = COLUMNS;
}
String[] cols = new String[projection.length];
Object[] values = new Object[projection.length];
int i = 0;
for (String col : projection)
{
if (OpenableColumns.DISPLAY_NAME.equals(col))
{
cols[i] = OpenableColumns.DISPLAY_NAME;
values[i++] = uri.getLastPathSegment();
}
else if (OpenableColumns.SIZE.equals(col))
{
cols[i] = OpenableColumns.SIZE;
values[i++] = AssetFileDescriptor.UNKNOWN_LENGTH;
}
}
cols = copyOf(cols, i);
values = copyOf(values, i);
final MatrixCursor cursor = new MatrixCursor(cols, 1);
cursor.addRow(values);
return cursor;
}
private static String[] copyOf(String[] original, int newLength)
{
final String[] result = new String[newLength];
System.arraycopy(original, 0, result, 0, newLength);
return result;
}
private static Object[] copyOf(Object[] original, int newLength)
{
final Object[] result = new Object[newLength];
System.arraycopy(original, 0, result, 0, newLength);
return result;
}
@Override
public boolean onCreate()
{
return true;
}
@Override
public Uri insert(Uri uri, ContentValues values)
{
return null;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs)
{
return 0;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
{
return 0;
}
}
setType()
resets your Uri
to null
. Try skipping the Uri
in the constructor and using setDataAndType()
instead.
I am new to android development and spent the whole day looking for the reason that my locally stored PDF could not be opened by external apps. I am glad having found this thread.
In the meantime Marco got it working and describes it here. Beware: Italian language- Google translation service might help ;-)
http://www.marcofaion.it/?p=7
http://web.archive.org/web/20111020204554/http://www.marcofaion.it/?p=7
Additional notes to his howto for beginners:
The line Marco mentions to be inserted in the Manifest.xml
<provider android:name=".FileContentProvider" android:authorities="package.name" />
should be inserted within the <application ...></application>
tag.
And if you plan to have custom filenames you should exchange
InputStream is = am.open("file.pdf");
with
InputStream is = am.open(uri.getLastPathSegment());
PDF files have to be put into already existing folder assets in your project (especially not in any newly added folder res/assets or sth.)! =)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.