Displaying Base64-Encoded String of raw PDF data using ThinkFree PDF Viewer - java

The problem:
I'm getting a Base64-Encoded String of raw PDF data from a web service (this data is housed in my String array pdfData). I have to use this data display the PDF in a PDF viewer (I happen to be using the included 'ThinkFree PDF Viewer' since I'm working on an Android application, but lets generalize and say any PDF viewer will do). Note that I'm accessing the 0th element of this array just for testing purposes (to make sure I can at least pull up 1 PDF before writing the code to pull up all the PDFs).
The code is within a class. First the method createFile is called, then intentOpenPDF:
import org.apache.commons.codec.binary.Base64;
File file;
FileOutputStream outputStream;
private byte[] decodedContent;
private String[] pdfData;
private String[] pdfFileName;
public void createFile() {
decodedContent = Base64.decodeBase64(pdfData[0].getBytes());
try {
File path = new File(getFilesDir(), "PDFs");
if (!path.exists()) {
path.mkdirs();
}
file = new File(path, pdfFileName[0]);
outputStream = new FileOutputStream(file);
outputStream.write(decodedContent);
outputStream.close();
}
catch (FileNotFoundException ex) {
ex.printStackTrace();
}
catch (IOException ex) {
ex.printStackTrace();
}
finally {
// Make absolutely certain the outputStream is closed
try {
if (outputStream != null) {
outputStream.close();
}
}
catch (IOException ex) {
ex.printStackTrace();
}
}
}
public void intentOpenPDF() {
// Make sure the file exists before accessing it:
if (file.exists()) {
Uri targetUri = Uri.fromFile(file);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(targetUri, "application/pdf");
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
}
}
The error:
Error opening file. It does not exist or cannot be read.
I have a break point set inside the conditional statement that checks if the file exists (within the intentOpenPDF method), and it IS passing this check.

The path produced by calling getFilesDir() leads a protected directory (file:///data/data/), where only files created with openFileOutput(String, int) are stored. I am not creating the file this way. The solution in my case is to use getExternalFilesDir(null).getAbsolutePath() instead, which will give you a path a directory internal to the application (/storage/emulated/0/Android/data/). No permissions are required to read or write to this path.

Considering your error message:
It does not exist or cannot be read.
as you verified it exists (first possible cause), it's certainly not readable (second possible cause).

Related

Application will take a picture, but will not save it

I'm trying to take a picture and save it as a jpeg. For your information, if it helps, this is the third activity in the program that the user would access, and I'm hoping to save the picture into the data/user/0/com.example.app/appdata/inv/inv_pics file. Here's what I have:
static String currentPhotoPath;
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 = new File (MainActivity.path+"/com.example.app/appdata/inv/inv_pics");
storageDir.mkdir();
File image = File.createTempFile(
imageFileName, /* prefix */
".jpg", /* suffix */
storageDir /* directory */
);
// Save a file: path for use with ACTION_VIEW intents
currentPhotoPath = image.getAbsolutePath();
return image;
}
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) {
ex.printStackTrace();
// Error occurred while creating the File
}
// Continue only if the File was successfully created
if (photoFile != null) {
Uri photoURI = Uri.parse((MainActivity.path+"/com.example.app/appdata/inv/inv_pics"));
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
}
}
}
I'm loosely following this tutorial. I've made the same in my Manifest file, and have created the additional file_paths xml file. I had the Uri in the second method (photoURI) set up exactly how the method had it, with the arguments as it was in the tutorial. This was just producing errors, and so I basically hard-coded the file path to my app in there (which I know isn't "OOP") and now the code almost works.
When I run the app, and get to the activity, it opens the camera. That's great. I click the button to take the picture and the screen freezes for a second, but does not give me the "Retry" or "Ok" buttons at the bottom - the expected result.
Ideal function (again, for your information) :
Get to this activity. It opens a camera. (I am here.) When I take the picture, it would ask me "Retry" or "Ok" (as mentioned above.) If I click "Ok" the file name would be written to a text file where it would later be read in order to set the picture as the image on an Image Button.
Thanks in advance!
Edit :
I don't believe it's a permissions problem, a) I have the permissions declared in the Manifest, and b) the first method does actually create the file, it's just blank, which lets me know the code runs until at least the photoFile = createImageFile(); in the second method.
Since I know you'll probably ask, here's the errors it gives me when I try to use the code provided by the tutorial:
Process: com.example.app, PID: 4700
java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/emulated/0/Android/data/com.example.app/files/Pictures/JPEG_20191201_235937_8382995102420149896.jpg
at androidx.core.content.FileProvider$SimplePathStrategy.getUriForFile(FileProvider.java:739)
at androidx.core.content.FileProvider.getUriForFile(FileProvider.java:418)
at com.erthad.boutique.InventoryActivity2.dispatchTakePictureIntent(InventoryActivity2.java:59)
at com.erthad.boutique.InventoryActivity2.access$000(InventoryActivity2.java:21)
at com.erthad.boutique.InventoryActivity2$1.onClick(InventoryActivity2.java:82)
at android.view.View.performClick(View.java:7341)
at android.view.View.performClickInternal(View.java:7307)
at android.view.View.access$3200(View.java:846)
at android.view.View$PerformClick.run(View.java:27796)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7156)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:975)```
Use Base64 to get the picture as a String:
Read from Internal
public StringBuilder fromInternal(String filename) {
StringBuilder sb = new StringBuilder();
try {
FileInputStream fileInputStream = context.openFileInput(filename);
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, "UTF-8");
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String line;
while ((line = bufferedReader.readLine()) != null) {
sb.append(line);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return sb;
}
Save file to Internal:
public void toInternal(String data,String sFileName){
File file = new File(Environment.getExternalStorageDirectory()+"/"+sFileName);
byte[] bytes = data.getBytes();
OutputStream outputStream = null;
try {
outputStream = new FileOutputStream(file);
outputStream.write(bytes);
outputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
and add this permissions in your AndroidManifest.xml
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
The answer came to me after reading into DoFlamingo's comments and answers, so partial credit to him.
The problem was in fact that I was not writing to the right storage. But the solution was something I didn't even think of initially. The tutorial was actually spot on. I tried editing the directory in the paths.xml file to point to a directory I was using when I began writing the code (namely data/data/user/0/com.example.app/appdata/inv/inv_pics) when it should have pointed to exactly what DoFlamingo was saying - and the tutorial (namely storage/emulated/XXX).
So, here's to making things a lot more complicated then they needed to be. I'll leave the post up in case it helps some one.

Read and write bitmap to android fails

I am trying to write and read a bitmap following the suggestions on other topics about this, the thing is i never get the bitmap when i try to read on the path where i saved the image:
So i have this to write the bitmap:
private String saveToInternalStorage(Bitmap bitmapImage){
ContextWrapper cw = new ContextWrapper(getApplicationContext());
// path to /data/data/yourapp/app_data/imageDir
File directory = cw.getDir("imageDir", Context.MODE_PRIVATE);
// Create imageDir
File mypath=new File(directory,"captured");
FileOutputStream fos = null;
try {
fos = new FileOutputStream(mypath);
// Use the compress method on the BitMap object to write image to the OutputStream
bitmapImage.compress(Bitmap.CompressFormat.JPEG, 100, fos);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return directory.getAbsolutePath();
}
}
i pass the returned path to another activity and then i pass it as parameter to get the bitmap like this:
private void loadImageFromStorage(String path)
{
try {
File f=new File(path, "captured.jpg");
Log.d("filehe",f.toString());
b = BitmapFactory.decodeStream(new FileInputStream(f));
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
}
i feel i am doing something wrong here, but can't figure out what, the b variavel has no value :/.
Any help?
Thanks
So i have this to write the bitmap:
The file that you save is named captured.
i pass the returned path to another activity and then i pass it as parameter to get the bitmap like this
Here, you are trying to load captured.jpg, which is not captured.
You could avoid this sort of problem by having the first method return the File that the second method then uses.
Also:
Use an image-loading library (e.g., Picasso, Glide) that has an in-memory cache, so you do not waste the user's time re-loading the same bitmap from disk
Get rid of ContextWrapper from the first method, as you do not need it

Android Studio - Read and Write to/from file in local storage within a folder

So I'm trying to read and write to and from a file that is inside a folder within the app's directory. So the path is something like "package/userFiles/'insert file name here'" but I can't find a way to do it anywhere.
I haven't been able to test this yet but the below is the code I've got for writing a quick and simple string to the file. If you could take a look over that I would be grateful, and if at all possibly give me some direction over how to read from the file.
FileOutputStream outputStream;
File path = new File(getFilesDir(),"userFiles");
path.mkdirs();
File mypath =new File(path,newFileNameText);
try {
FileOutputStream out = new FileOutputStream(mypath);
String defaultMessage = "Empty File";
out.write(defaultMessage.getBytes());
out.close();
Intent intent = new Intent(getApplicationContext(), EditFileContents.class);
intent.putExtra(EXTRA_MESSAGE,newFileNameText);
startActivity(intent);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
You can see the code starts a new activity, it is this activity from which I would like to be able to read the contents of the file.

New to Java. Problems reading from file using Context and openFileInput

I've been trying to do this on my own for the past couple hours and am kinda losing it a little.
All I want to do is open a file, read it and display it to the console; that's it.
I'm using eclipse to develop for android 2.3.3.
I have tried using a bunch of different ways with code that I have found here, and on other sites. Here is what I have now and how its all called:
In the OnCreate function:
setContentView(new TestMap(this));
The testMap class:
TestMap(Context context){
super(context);
// might need to be on the panel class
loadTileFile("worldonelayout.txt", context);
in the same class:
private void loadTileFile (String filename, Context context){
FileInputStream input = null;
InputStreamReader reader = null;
char[] inputBuffer = new char[256];
String data = null;
try {
input = context.openFileInput("worldonelayout.txt");
reader = new InputStreamReader(input);
reader.read(inputBuffer);
data = new String(inputBuffer);
System.out.println(data);
Toast.makeText(context, "Text read", Toast.LENGTH_SHORT).show();
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(context, "Text not read", Toast.LENGTH_SHORT).show();
} finally {
try {
input.close();
reader.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
This code doesnt work. It always hits the exception.
"/data/data/com.name.somethingiremoved/files/worldonelayout.txt (No such file or directory)".
This happens at the first CATCH. BTW my file is in the root directory: Documents\Eclipse\workspace\project\worldonelayout.txt. I can also see the file in the browser on the left
From what I have seen here and on other sites, it is something to do with the Context class being derived from the Activity? I don't want to have this code in the same class as my activity. Is there a way round this?
If you need anything more from me, let me know.
The open file is looking for a file on the phone's file system, not on the computer's. Its telling you exactly where it expects to find it - on the phone under /data/data/com.name.somethingiremoved/files/worldonelayout.txt

Why do I get FileNotFoundException when I create and try to write to file on Android emulator?

First off, I am not trying to write to the SDCard. I want to write some information to a file that persists between uses of the app. It is essentially a file to hold favorites of the particular user. Here is what the code looks like:
try {
File file = new File("favorites.txt");
if (file.exists()) {
Log.d(TAG, "File does exist.");
fis = new FileInputStream(file);
br = new BufferedReader(new InputStreamReader(fis));
}
else {
Log.d(TAG, "File does not exist.");
return favDests;
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
When running this code, we always get the "File does not exist." message in our DDMS log.
We have also tried the following code to no avail:
try {
File file = new File(GoLincoln.FAV_DEST_FILE);
fis = new FileInputStream(file);
br = new BufferedReader(new InputStreamReader(fis));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
It is this second portion of code that results in the FileNotFoundException.
I have read multiple tutorials on writing and reading files on Android and I believe I am following them pretty closely, so I am not sure why this code doesn't work successfully. I appreciate any help!
You shouldn't use the File class directly. Use Activity.getCacheDir() to get the cache dir which is specific to your application. Then use new File(cachedir, "filename.tmp") to create the file.
Preferences and SQLLite will both allow you to have persistent data without managing your own files.
To use shared preferences you grab it from your context, then you edit the values like so
mySharedPreferences = context.getSharedPreferences("DatabaseNameWhateverYouWant", 0);
mySharedPreferences.getEditor().putString("MyPreferenceName", "Value").commit();
To get a preference out
mySharedPreferences.getString("MyPreferenceName", "DefaultValue");
This is really the simplest way to do basic preferences, much easier then doing a file. More then strings are supported, most basic data types are available to be added to the Preferences class.

Categories