I've been working with this PDF library, trying to get the path to where the PDF file resides, but I keep getting an error. What am I missing here?
Checking my Android Device Monitor, i can see my db in that database folder which also reside in the assets folder but i can't find all the pdf files? please where are they? check the image below
Thanks friends, it was my mistake, i just discovered that i need to read the file from assets into file directory before opening it. Is working right now using the code below
`
private void CopyReadAssets(String fileName)
{
AssetManager assetManager = this.getAssets();
InputStream in = null;
OutputStream out = null;
File file = new File(this.getFilesDir(), fileName);
try
{
in = assetManager.open(fileName);
out = this.openFileOutput(file.getName(), Context.MODE_WORLD_READABLE);
Utility.copyFile(in, out);
in.close();
in = null;
out.flush();
out.close();
out = null;
} catch (Exception e)
{
Log.e("tag", e.getMessage());
}
Intent intent = new Intent(android.content.Intent.ACTION_VIEW);
File dir_file = new File(file.getAbsolutePath());
//<-- Get FileType
String mimeType = Utility.getFileMineType(dir_file);
intent.setDataAndType(Uri.fromFile(file), mimeType); //"file://" + getFilesDir() + "/abc.pdf"),"application/pdf"
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
if(mimeType.equals("application/pdf")){
Log.e(TAG, Uri.fromFile(file).toString()+" -- "+dir_file);
//mPDFView = new StudentPdfViewer();
// mPDFView.display("Symfony.pdf", false);
//handle it as activity
Intent intent1 = new Intent(this, PdfViewer.class);
intent1.putExtra(Config.COURSE_FILE, fileName);
//intent1.putExtra(SqliteDb.COURSE_NAME, listCategory.get(0).getCategory_name());
//intent1.putExtras(mBundle);
startActivity(intent1);
}else{
try {
startActivity(intent);
} catch (ActivityNotFoundException e) {
Toast.makeText(this, "Unable to load selected Course Material, Please check the Study Studio installation guide to install the required dependency softwares", Toast.LENGTH_LONG).show();
}
}
}
`
There is no "assets folder" on the device, and there is no "path to where the PDF file reside" on the device.
The contents of the assets/ folder(s) in your app's project are stored inside the APK. You can access assets via an AssetManager, and you get one of those by calling getAssets() on any handy Context, such as an Activity.
Related
I'm trying to implement the "share" button. It is necessary to send a picture.
That's what I'm doing:
Bitmap bitmap = ((BitmapDrawable) imageView.getDrawable()).getBitmap();
File outputDir = context.getCacheDir();
File outputFile = null;
try {
outputFile = File.createTempFile("temp_", ".jpg", outputDir);
} catch (IOException e) {
e.printStackTrace();
}
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream(outputFile);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fileOutputStream);
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(outputFile));
shareIntent.setType("image/jpeg");
startActivity(Intent.createChooser(shareIntent,
getResources().getText(R.string.send_via)));
but I get a message saying that it's impossible to upload an image. What's the matter?
First, third-party apps have no rights to access files in your portion of internal storage.
Second, on Android 7.0+, you cannot use file Uri values, such as those returned by Uri.fromFile().
To solve both problems, use FileProvider to make the image available to other apps. Use FileProvider.getUriForFile() instead of Uri.fromFile(), and be sure to add FLAG_GRANT_READ_URI_PERMISSION to the Intent.
This sample app demonstrates using FileProvider with third-party apps (for ACTION_IMAGE_CAPTURE and ACTION_VIEW, but the same technique will work for ACTION_SEND).
file = new File(getFilesDir(), "data.txt");
try {
FileOutputStream fos = openFileOutput(fileName, Context.MODE_APPEND);
fos.write(data.getBytes());
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
Is there a way to export this file so I can have access to it? I don't have a SD-card available btw.
File file = new File(Environment.getExternalStorageDirectory()+"/Download/", "yourFile.extension");
This is for downloads directory.
Then to open your file
Intent myIntent = new Intent(Intent.ACTION_VIEW);
myIntent.setData(Uri.fromFile(file));
Intent j = Intent.createChooser(myIntent, "Choose an application to open with:");
startActivity(j);
If you want to get your application path use getFilesDir() which will give you path /data/data/<your package>/files
So, you can find your file using android file manager in above mentioned directory.
From getFilesDir()
public void share(String song){
Uri uri = Uri.parse("android.resource://com.dsbsoft.myApp/raw/"+song+".mp3");
Intent share = new Intent(Intent.ACTION_SEND);
share.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
share.setType("audio/mp3");
share.putExtra(Intent.EXTRA_STREAM, uri);
this.startActivity(Intent.createChooser(share, "Send song"));
}
all works perfectly but at the time to send the file, i think, it's not exists...
In the void comes String variable song, that contains the name of file.
For example:
the call was: share("abc"); i want to send the mp3 file(it is in raw folder) abc.mp3
Apparently we can't send directly resourse files.
Thats why i do the following.
To send mp3 file, i burn it on a folder in the storage and share this new file.
the code:
public void makeOutSide(String song, InputStream ins){
// Create the directory
File dir = new File(Environment
.getExternalStorageDirectory() + "/.CSOUNDS/");
// If it does not exists, make it.
if (!dir.exists()) {
dir.mkdir(); // Generating the directory
}
try {
// Open the resource
byte[] buffer = new byte[ins.available()];
ins.read(buffer);
ins.close();
// Burn
String filename = Environment
.getExternalStorageDirectory().toString()
+ "/.CSOUNDS/"+song+".mp3";
FileOutputStream fos = new FileOutputStream(filename);
fos.write(buffer);
fos.close();
} catch (Exception e) { }
}
public void share(String song, InputStream ins){
makeOutSide(song,ins);
String rout = Environment.getExternalStorageDirectory().toString()+"/.CSOUNDS/"+song+".mp3";
Uri uri = Uri.parse(rout);
Intent share = new Intent(Intent.ACTION_SEND);
share.setType("audio/*");
share.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
share.putExtra(Intent.EXTRA_STREAM,uri);
startActivity(Intent.createChooser(share, "Share song"));
}
in the call of the share method comes an InputStream ins at this way:
InputStream ins = getResources().openRawResource(R.raw.abc);
share("abc",ins);
Try this:
public void share(String song){
File audio = new File("android.resource://com.dsbsoft.myApp/raw/+song+ ".mp3");
Intent share = new Intent(Intent.ACTION_SEND).setType("audio/*");
share.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(audio));
startActivity(Intent.createChooser(share, "Share song"));
}
I am trying to use this code to send my application apk file to another device:
public static void sendAppItself(Activity paramActivity) throws IOException {
PackageManager pm = paramActivity.getPackageManager();
ApplicationInfo appInfo;
try {
appInfo = pm.getApplicationInfo(paramActivity.getPackageName(),
PackageManager.GET_META_DATA);
Intent sendBt = new Intent(Intent.ACTION_SEND);
sendBt.setType("*/*");
sendBt.putExtra(Intent.EXTRA_STREAM,
Uri.parse("file://" + appInfo.publicSourceDir));
paramActivity.startActivity(Intent.createChooser(sendBt,
"Share it using"));
} catch (PackageManager.NameNotFoundException e1) {
e1.printStackTrace();
}
}
This code works very well.
But the name of the apk file shared with this code is base.apk
How can I change it?
Copy the file from the source directory to a new directory.
Rename the file while copying and share the copied file.
Delete the temp file after share is complete.
private void shareApplication() {
ApplicationInfo app = getApplicationContext().getApplicationInfo();
String filePath = app.sourceDir;
Intent intent = new Intent(Intent.ACTION_SEND);
// MIME of .apk is "application/vnd.android.package-archive".
// but Bluetooth does not accept this. Let's use "*/*" instead.
intent.setType("*/*");
// Append file and send Intent
File originalApk = new File(filePath);
try {
//Make new directory in new location
File tempFile = new File(getExternalCacheDir() + "/ExtractedApk");
//If directory doesn't exists create new
if (!tempFile.isDirectory())
if (!tempFile.mkdirs())
return;
//Get application's name and convert to lowercase
tempFile = new File(tempFile.getPath() + "/" + getString(app.labelRes).replace(" ","").toLowerCase() + ".apk");
//If file doesn't exists create new
if (!tempFile.exists()) {
if (!tempFile.createNewFile()) {
return;
}
}
//Copy file to new location
InputStream in = new FileInputStream(originalApk);
OutputStream out = new FileOutputStream(tempFile);
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
out.close();
System.out.println("File copied.");
//Open share dialog
intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(tempFile));
startActivity(Intent.createChooser(intent, "Share app via"));
} catch (IOException e) {
e.printStackTrace();
}
}
Update: this method does not work anymore and throws exception if you implement it. Since android N, we should use content providers if we want to have access to files in memory(like the apk file). For more information please visit this Guide. Although the whole idea of copying and renaming and sharing the copied version is still valid.
You can use this function, test on api 22 and 27
private void shareApplication() {
ApplicationInfo app = getApplicationContext().getApplicationInfo();
String filePath = app.sourceDir;
Intent intent = new Intent(Intent.ACTION_SEND);
// MIME of .apk is "application/vnd.android.package-archive".
// but Bluetooth does not accept this. Let's use "*/*" instead.
intent.setType("*/*");
// Append file and send Intent
File originalApk = new File(filePath);
try {
//Make new directory in new location=
File tempFile = new File(getExternalCacheDir() + "/ExtractedApk");
//If directory doesn't exists create new
if (!tempFile.isDirectory())
if (!tempFile.mkdirs())
return;
//Get application's name and convert to lowercase
tempFile = new File(tempFile.getPath() + "/" + getString(app.labelRes).replace(" ","").toLowerCase() + ".apk");
//If file doesn't exists create new
if (!tempFile.exists()) {
if (!tempFile.createNewFile()) {
return;
}
}
//Copy file to new location
InputStream in = new FileInputStream(originalApk);
OutputStream out = new FileOutputStream(tempFile);
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
out.close();
System.out.println("File copied.");
//Open share dialog
// intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(tempFile));
Uri photoURI = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".provider", tempFile);
// intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(tempFile));
intent.putExtra(Intent.EXTRA_STREAM, photoURI);
startActivity(Intent.createChooser(intent, "Share app via"));
} catch (IOException e) {
e.printStackTrace();
}
}
This only happens because it is saved by base.apk name.
To share it as per your need you have to just copy this file into another directory path and rename it over there. Then use new file to share.
This file path[file:///data/app/com.yourapppackagename/base.apk] in data folder is having only read permissions so you can't rename .apk file over there.
2021 Kotlin way
First we need to set a file provider
In AndroidManifest.xml create a File provider
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true"
>
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths"
/>
</provider>
If you don't have file_path.xml the create one in res/xml (create xml folder if it doesn't exist)
and in file_path.xml add
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-files-path
name="apk"
path="cache/ExtractedApk/" />
</paths>
Now add the code to share the apk
private fun shareAppAsAPK(context: Context) {
val app: ApplicationInfo = context.applicationInfo
val originalApk = app.publicSourceDir
try {
//Make new directory in new location
var tempFile: File = File(App.instance.getExternalCacheDir().toString() + "/ExtractedApk")
//If directory doesn't exists create new
if (!tempFile.isDirectory) if (!tempFile.mkdirs()) return
//rename apk file to app name
tempFile = File(tempFile.path + "/" + getString(app.labelRes).replace(" ", "") + ".apk")
//If file doesn't exists create new
if (!tempFile.exists()) {
if (!tempFile.createNewFile()) {
return
}
}
//Copy file to new location
val inp: InputStream = FileInputStream(originalApk)
val out: OutputStream = FileOutputStream(tempFile)
val buf = ByteArray(1024)
var len: Int
while (inp.read(buf).also { len = it } > 0) {
out.write(buf, 0, len)
}
inp.close()
out.close()
//Open share dialog
val intent = Intent(Intent.ACTION_SEND)
//MIME type for apk, might not work in bluetooth sahre as it doesn't support apk MIME type
intent.type = "application/vnd.android.package-archive"
intent.putExtra(
Intent.EXTRA_STREAM, FileProvider.getUriForFile(
context, BuildConfig.APPLICATION_ID + ".fileprovider", File(tempFile.path)
)
)
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
startActivity(intent)
} catch (e: IOException) {
e.printStackTrace()
}
}
If someone trying to generate apk from fragment they may need to change few lines from #sajad's answer as below
Replace
File tempFile = new File(getExternalCacheDir() + "/ExtractedApk");
with
File tempFile = new File(getActivity().getExternalCacheDir() + "/ExtractedApk");
2.while importing BuildConfig for below line
import androidx.multidex.BuildConfig // DO NOT DO THIS!!! , use your app BuildConfig.
and if you're getting below EXCEPTION
Couldn't find meta-data for provider with authority
Look for provider info in manifest file
then look for "provider"s name and authority in your manifest file and if it's androidx.core.content.FileProvider then
Replace
Uri photoURI = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".provider", tempFile);
With
Uri photoURI = FileProvider.getUriForFile(getActivity(), BuildConfig.APPLICATION_ID + ".fileprovider", tempFile);
I'm following the Google Camera Tutorial for an Android application. At this moment, I'm able to take a picture, save it, show the path and show the bitmap into an ImageView.
Here is an exemple of the logcat when I ask for the absolute path of a picture I just took :
D/PATH:: /storage/emulated/0/Pictures/JPEG_20160210_140144_217642556.jpg
Now, I would like to transfer it on a PC via USB. When I broswe into the device storage, I can see the public folder Picturethat I called earlier in my code with the variable Environment.DIRECTORY_PICTURES. However, there is nothing in this folder.
Screenshot of my device's folders
I can't insert a SD Card in my device to test. Also, I don't want to put the pictures into cache directory for preventing to be deleted.
Here is my permissions in Manifest :
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
When the user click on the camera buttons :
dispatchTakePictureIntent();
[...]
private void dispatchTakePictureIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Ensure that there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
// Create the File where the photo should go
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException ex) {
// Error occurred while creating the File
}
// Continue only if the File was successfully created
if (photoFile != null) {
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,
Uri.fromFile(photoFile));
startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
}
}
}
This is method creating the file
private File createImageFile() throws IOException {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
File image = File.createTempFile(
imageFileName, /* prefix */
".jpg", /* suffix */
storageDir /* directory */
);
// Save a file: path for use with ACTION_VIEW intents
mCurrentPhotoPath = "file:" + image.getAbsolutePath();
Log.d("PATH:", image.getAbsolutePath());
return image;
}
I guess I misunderstood something about the External Storage. Can someone explain me why I can't save a picture and access it on a PC ? Thank you !
-- EDIT --
After reading an answer below, I tried to get the file in OnActivityResult and to save it with Java IO. Unfortunately, there is no file in Pictures folder when I look with Explorer.
if (requestCode == REQUEST_TAKE_PHOTO) {
Log.d("AFTER", absolutePath);
// Bitmap bitmap = BitmapFactory.decodeFile(absolutePath);
// imageTest.setImageBitmap(Bitmap.createScaledBitmap(bitmap, 2100, 3100, false));
moveFile(absolutePath, Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).toString());
}
private void moveFile(String inputFile, String outputPath) {
InputStream in = null;
OutputStream out = null;
try {
//create output directory if it doesn't exist
File dir = new File (outputPath);
if (!dir.exists())
{
dir.mkdirs();
}
in = new FileInputStream(inputFile);
out = new FileOutputStream(outputPath + imageFileName + ".jpg");
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
in.close();
in = null;
// write the output file
out.flush();
out.close();
out = null;
// delete the original file
new File(inputFile).delete();
}
You're currently saving the file as a temporary file, so it won't persist on disk after the application lifecycle. Use something like:
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
imageBitmap.compress(Bitmap.CompressFormat.JPEG, 90, bytes);
File f = new File(Environment.getExternalStorageDirectory() + [filename])
And then create a FileOutputStream to write to it.
FileOutStream fo = new FileOutputStream(f);
fo.write(bytes.toByteArray());
To solve my problem, I had to write the file into the application's data folder and to user the MediaScannerConnection. I've put a .txt file for testing, but after it works you can put any other file.
I'll share the solution for those who have a similar problem :
try
{
// Creates a trace file in the primary external storage space of the
// current application.
// If the file does not exists, it is created.
File traceFile = new File(((Context)this).getExternalFilesDir(null), "TraceFile.txt");
if (!traceFile.exists())
traceFile.createNewFile();
// Adds a line to the trace file
BufferedWriter writer = new BufferedWriter(new FileWriter(traceFile, true /*append*/));
writer.write("This is a test trace file.");
writer.close();
// Refresh the data so it can seen when the device is plugged in a
// computer. You may have to unplug and replug the device to see the
// latest changes. This is not necessary if the user should not modify
// the files.
MediaScannerConnection.scanFile((Context)(this),
new String[] { traceFile.toString() },
null,
null);
}
catch (IOException e)
{
Log.d("FileTest", "Unable to write to the TraceFile.txt file.");
}