I have a button in my app, which when clicked on will open a PDF (the "Open with" prompt will show). The PDF file is in my assets folder of the app. I have written the code such that an AsyncTask carries out the operation of copying from the assets folder to external storage and then opening it. On running however, none of the methods of AsyncTask class execute as I can see from Logcat. I have seen other similar questions and tried their different answers:
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR) instead of .execute()
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[])null);
adding onPreExecute()
The error I get is NullPointerException in the onPostExecute(File file) method, i.e. file is not found. None of the logged statements in the three methods are in logcat.
I call this execute method below:
public void execute() {
Context context = contextWeakReference.get();
if (context != null) {
new CopyFileAsyncTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[])null);
}
}
private class CopyFileAsyncTask extends AsyncTask<Void, Void, File> {
final String appDirectoryName = BuildConfig.APPLICATION_ID;
final File fileRoot = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DOCUMENTS), appDirectoryName);
#Override
protected void onPreExecute() {
super.onPreExecute();
Log.e("AsyncTask", "onPreExecute");
}
#Override
protected File doInBackground(Void... params) {
Context context = contextWeakReference.get();
AssetManager assetManager = context.getAssets();
File file = new File(fileRoot, fileName);
InputStream in = null;
OutputStream out = null;
try {
file.mkdirs();
if (file.exists()) {
file.delete();
}
file.createNewFile();
in = assetManager.open(fileName);
Log.d(TAG, "In");
out = new FileOutputStream(file);
Log.d(TAG, "Out");
Log.d(TAG, "Copy file");
copyFile(in, out);
Log.d(TAG, "Close");
in.close();
out.flush();
out.close();
return file;
} catch (Exception e)
{
Log.e(TAG, e.getMessage());
}
return null;
}
private void copyFile(InputStream in, OutputStream out) throws IOException
{
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1)
{
out.write(buffer, 0, read);
}
}
#Override
protected void onPostExecute(File file) {
super.onPostExecute(file);
Context context = contextWeakReference.get();
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(
Uri.fromFile(file),
"application/pdf");
context.startActivity(intent);
}
}
You Always return null in doInBackground
so
protected void onPostExecute(File file) {
super.onPostExecute(file);
Context context = contextWeakReference.get();
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(
Uri.fromFile(file),
"application/pdf");
context.startActivity(intent);
}
File is Always Null
try to edit this
#Override
protected File doInBackground(Void... params) {
Context context = contextWeakReference.get();
AssetManager assetManager = context.getAssets();
File file = new File(fileRoot, fileName);
InputStream in = null;
OutputStream out = null;
try {
file.mkdirs();
if (file.exists()) {
file.delete();
}
file.createNewFile();
in = assetManager.open(fileName);
Log.d(TAG, "In");
out = new FileOutputStream(file);
Log.d(TAG, "Out");
Log.d(TAG, "Copy file");
copyFile(in, out);
Log.d(TAG, "Close");
in.close();
out.flush();
out.close();
} catch (Exception e)
{
Log.e(TAG, e.getMessage());
}
return file;
}
Problem solved!! Apparently Marshmallow does some secret behind the scenes work like not asking for permissions (while installing using android studio). I found that the answer here android mkdirs not working worked for me. You have to go to Settings > Apps > Your app > Turn on Storage permissions. It took me three days to solve this!
Related
I'm working on this Camera application but I'm having trouble displaying the image that the user takes. The camera, preview, and capture buttons work perfectly on the main activity. Right now, the application saves the photo to Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "MyCameraApp" But I DON'T want the images to save there. I just want to pass that image to the next activity, (Not save it to a public directory). Is there a way to do this? I've looked at the tutorials but can't figure out how to implement MODE.PRIVATE.
Here's where it is called:
#Override
public void onPictureTaken(final byte[] data, Camera camera) {
new AsyncTask<Void, Void, String>() {
#Override
protected String doInBackground(Void... params) {
File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
if (pictureFile == null){
Log.d(TAG, "Error creating media file, check storage permissions: ");
return null;
}
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(data);
fos.close();
return pictureFile.getPath();
} catch (FileNotFoundException e) {
Log.d(TAG, "File not found: " + e.getMessage());
return null;
} catch (IOException e) {
Log.d(TAG, "Error accessing file: " + e.getMessage());
return null;
}
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
if(result != null){
Intent intent = new Intent(mContext, ImageDisplayActivity.class);
intent.putExtra(ImageDisplayActivity.KEY_PATH, result);
startActivity(intent);
}
}
}.execute();
}
Here is the code for the method:
private static File getOutputMediaFile(int type){
// To be safe, you should check that the SDCard is mounted
// using Environment.getExternalStorageState() before doing this.
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "MyCameraApp");
// This location works best if you want the created images to be shared
// between applications and persist after your app has been uninstalled.
// Create the storage directory if it does not exist
if (! mediaStorageDir.exists()){
if (! mediaStorageDir.mkdirs()){
Log.d("MyCameraApp", "failed to create directory");
return null;
}
}
// Create a media file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
File mediaFile;
if (type == MEDIA_TYPE_IMAGE){
mediaFile = new File(mediaStorageDir.getPath() + File.separator +
"IMG_"+ timeStamp + ".jpg");
} else {
return null;
}
return mediaFile;
}
Try this one ,
ActivityOne.Java
try {
//Write file
String filename = "photo.png";
FileOutputStream stream = this.openFileOutput(filename, Context.MODE_PRIVATE);
bmp.compress(Bitmap.CompressFormat.PNG, 200, stream);
//Cleanup
stream.close();
//Pop intent
Intent mIntent= new Intent(this, ActivityTwo.class);
in1.putExtra("bitmap", filename);
startActivity(mIntent);
} catch (Exception e) {
e.printStackTrace();
}
ActivityTwo.Java
Bitmap bmp = null;
String filename = getIntent().getStringExtra("bitmap");
try {
FileInputStream is = this.openFileInput(filename);
bmp = BitmapFactory.decodeStream(is);
is.close();
} catch (Exception e) {
e.printStackTrace();
}
and set Imageview with bitmap you can get your bitmap which you captured from camera
http://developer.android.com/guide/topics/data/data-storage.html#filesInternal
Look at the example :
String FILENAME = "hello_file";
String string = "hello world!";
FileOutputStream fos = openFileOutput(FILENAME, Context.MODE_PRIVATE);
fos.write(string.getBytes());
fos.close();
So basically, you just need to have a FILENAME to create a file on private mode.
Just keep the last part your method getOutputMediaFile(int type) it should be something like this :
private static File getOutputMediaFile(int type){
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss",
Locale.getDefault()).format(new Date());
if (type == MEDIA_TYPE_IMAGE) {
mediaFile = "IMG_"+ timeStamp + ".jpg";
} else {
return null;
}
return mediaFile;
}
and then just change this try of your doInBackground function :
try {
FileOutputStream fos = openFileOutput(pictureFile, Context.MODE_PRIVATE);
fos.write(data);
fos.close();
return pictureFile;
}
And just give the path to your other Activity and create a bmp
String filepath = intent.getStringExtra("EXTRA_FILE");
java.io.FileInputStream in = openFileInput(filepath);
Bitmap bmp = BitmapFactory.decodeStream(in)
I am using tesseract OCR in my app (Spl!t). When I launch the app from Eclipse to my phone, eng.traineddata is copied into /storage/emulated/0/Pictures/Receipts/tessdata/. But when I installed the app from the market, the eng.traineddata file is not copied into the folder. Is there something wrong with my code?
private File getOutputPhotoFile() {
directory = new File(
Environment
.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
"Receipts");
dataPath = directory.getAbsolutePath();
if (!directory.exists()) {
directory.mkdirs();
Toast.makeText(Trans_List.this, "Receipts Folder Created", Toast.LENGTH_SHORT).show();
File tessDir = new File(directory, "tessdata");
if (!tessDir.exists()) {
tessDir.mkdirs();
Toast.makeText(Trans_List.this, "Tessdata Folder Created", Toast.LENGTH_SHORT).show();
File trainingData = new File(tessDir, "eng.traineddata");
if(!trainingData.exists())
new CopyLibrary().execute(LANG);
}
}
String timeStamp = new SimpleDateFormat("yyyMMdd_HHmmss")
.format(new Date());
return new File(directory.getPath() + File.separator + "Receipt_"
+ timeStamp + ".jpg");
}
private class CopyLibrary extends AsyncTask<String, Void, Void> {
private void copyFile(InputStream in, OutputStream out)
throws IOException {
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1)
out.write(buffer, 0, read);
}
#Override
protected Void doInBackground(String... s) {
AssetManager assetManager = getAssets();
String[] files = null;
try {
files = assetManager.list("");
} catch (IOException e) {
Log.e("Spl!t", "Failed to get asset file list.");
}
for (String filename : files) {
InputStream in = null;
OutputStream out = null;
try {
in = assetManager.open(filename);
File outFile = new File(dataPath + File.separator
+ "tessdata" + File.separator, LANG
+ ".traineddata");
out = new FileOutputStream(outFile);
copyFile(in, out);
in.close();
in = null;
out.flush();
out.close();
Toast.makeText(Trans_List.this, "Tessdata copied", Toast.LENGTH_SHORT).show();
out = null;
} catch (IOException e) {
Log.e(TAG, "Failed to copy asset file");
}
}
return null;
}
}
I'm trying to wirte files to the internal storage actually to an other apps unprotected storage the code I'm using works it just doesn't work when I want to copy to /android/data/com.some.app can this be done or do I have to make the app use root access
Thanks
public class tools extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.tools);
}
public void installflat(View view)
{ Toast.makeText(tools.this, "This could take a long time", Toast.LENGTH_LONG).show();
File direct = new File(Environment.getExternalStorageDirectory() + "/android" + "/data" + "/com.some.app" +"/");
if (!direct.exists())
{
if (direct.mkdir())
{ //directory is created;
}}
installflat_pt2();
Toast.makeText(tools.this, "try it now", Toast.LENGTH_LONG).show();
}
private void installflat_pt2()
{
AssetManager assetManager = getAssets();
String[] files = null;
try
{
files = assetManager.list("tools");
}
catch (IOException e)
{
Log.e("tag", e.getMessage());
}
for (String filename : files)
{
System.out.println("File name => " + filename);
InputStream in = null;
OutputStream out = null;
try
{
in = assetManager.open("tools/" + filename); // if files resides inside the "Files" directory itself
out = new FileOutputStream(Environment.getExternalStorageDirectory().toString() + "/android" + "/data" + "/com.some.app" + filename);
copyFile(in, out);
in.close();
in = null;
out.flush();
out.close();
out = null;
}
catch (Exception e)
{
Log.e("tag", e.getMessage());
}
}
}
private void copyFile(InputStream in, OutputStream out) throws IOException
{
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1)
{
out.write(buffer, 0, read);
}
}
}
i need to make downloaded files such as mp3 picture etc, to be visible in Media apps like album or media player
is it of file chmod or is not readable ? every thing is ok in this class but its show downloaded files inside download folder only
this is my class
public class Download extends AsyncTask<String, Void, String> {
ProgressDialog mProgressDialog;
Context context;
String file_url,file_name;
public Download(Context context,String url , String file_name) {
this.context = context;
this.file_url = url;
this.file_name = file_name;
}
protected void onPreExecute() {
mProgressDialog = ProgressDialog.show(context, "",
"Please wait, Download …");
}
protected String doInBackground(String... params) {
// //////////////////////
try {
URL url = new URL(file_url);
HttpURLConnection c = (HttpURLConnection) url.openConnection();
c.setRequestMethod("GET");
c.setDoOutput(true);
c.connect();
String[] path = url.getPath().split("/");
String mp3 = path[path.length - 1];
int lengthOfFile = c.getContentLength();
String PATH = Environment.getExternalStorageDirectory()+ "/downloads/" ;
File file = new File(PATH);
file.mkdirs();
String fileName = file_name;
File outputFile = new File(file , fileName);
FileOutputStream fos = new FileOutputStream(outputFile);
InputStream is = c.getInputStream();
byte[] buffer = new byte[1024];
int len1 = 0;
while ((len1 = is.read(buffer)) != -1) {
fos.write(buffer, 0, len1);
}
fos.close();
is.close();
} catch (IOException e) {
e.printStackTrace();
}
return "done";
}
protected void onPostExecute(String result) {
if (result.equals("done")) {
mProgressDialog.dismiss();
}
}
}
any idea ??
You need to call the MediaScannerConnection and tell it to scan your file. Documentation here.
I have an Activity where the user can share an image from the raw folder.
The raw folder has 70 images, all named alphabetically. The first one is R.raw.recipe01 and the last is R.raw.recipe70.
I get the image int I would like to share from a Bundle and I have a method which copies the image from the raw folder to a accessible file.
I call startActivity(createShareIntent()); in the ActionBar MenuItem, which works successfully.
PROBLEM
The share intent will always select R.raw.recipe01 as the image, even if the int from the Bundle is for image for exmaple R.raw.recipe33.
I have shared my code below. Can anyone spot what I am doing wrong?
CODE:
private int rawphoto = 0;
private static final String SHARED_FILE_NAME = "shared.png";
#Override
public void onCreate(Bundle savedInstanceState) {
Bundle bundle = getIntent().getExtras();
rawphoto = bundle.getInt("rawphoto");
int savedphoto = rawphoto;
// COPY IMAGE FROM RAW
copyPrivateRawResourceToPubliclyAccessibleFile(savedphoto);
private Intent createShareIntent() {
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("image/*");
shareIntent.putExtra(Intent.EXTRA_TEXT, "IMAGE TO SHARE: ");
Uri uri = Uri.fromFile(getFileStreamPath("shared.png"));
shareIntent.putExtra(Intent.EXTRA_STREAM, uri);
return shareIntent;
}
private void copyPrivateRawResourceToPubliclyAccessibleFile(int photo) {
System.out.println("INT PHOTO: " +photo);
InputStream inputStream = null;
FileOutputStream outputStream = null;
try {
inputStream = getResources().openRawResource(photo);
outputStream = openFileOutput(SHARED_FILE_NAME,
Context.MODE_WORLD_READABLE | Context.MODE_APPEND);
byte[] buffer = new byte[1024];
int length = 0;
try {
while ((length = inputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, length);
}
} catch (IOException ioe) {
/* ignore */
}
} catch (FileNotFoundException fnfe) {
/* ignore */
}
finally {
try {
inputStream.close();
} catch (IOException ioe) {
}
try {
outputStream.close();
} catch (IOException ioe) {
}
}
}
Remove Context.MODE_APPEND so that the file gets overwritten if it already exists.