I am using the MuPDF library to display pdf in my app..
It is possible to view PDFs saved in internal or external memories but the App doesn't show the pdf if they are stored in assets folder of the app...
How to view in app PDFs?
I've seen solutions which say thatbwe can copy our in app PDFs in app associated folder and then use them later on...
but I can't get that..
here's the code -
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button showPDFBtn = (Button)findViewById(R.id.btn_show_pdf);
showPDFBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Uri uri = Uri.parse("file:///android_asset/test.pdf");
Intent intent = new Intent(MainActivity.this, MuPDFActivity.class);
intent.setAction(Intent.ACTION_VIEW);
intent.setData(uri);
startActivity(intent);
}}
);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
}
Try below code
private void readAssetAndMakeCopy()
{
AssetManager assetManager = getAssets();
InputStream in = null;
OutputStream out = null;
File file = new File(getFilesDir(), "git.pdf");
try
{
in = assetManager.open("git.pdf");
out = openFileOutput(file.getName(), Context.MODE_WORLD_READABLE);
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(Intent.ACTION_VIEW);
intent.setDataAndType(
Uri.parse("file://" + getFilesDir() + "/git.pdf"),
"application/pdf");
startActivity(intent);
}
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);
}
}
Make sure to include
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
in manifest
Related
I read all of the solutions about this problem.Also I know it can be considered as duplicated but it is not.
I see Error: Try Again toast message and I see Update Error log message.
I think at android v26 changed somethings about intent.setDataAndType or I dont know why this is not working.
Also I get the permissions something like this code
ActivityCompat.requestPermissions(Update.this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
REQUEST_WRITE_STORAGE);
Problem can not be solved. I just want to do download and install apk file.
AndroidManifest.xml (I added write permission)
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Update.java
package com.my.testapp;
public class Update extends AppCompatActivity {
ProgressDialog bar;
private static String TAG = "Update";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new DownloadNewVersion().execute();
}
class DownloadNewVersion extends AsyncTask<String,Integer,Boolean> {
#Override
protected void onPreExecute() {
super.onPreExecute();
bar = new ProgressDialog(Update.this);
bar.setCancelable(false);
bar.setMessage("Downloading...");
bar.setIndeterminate(true);
bar.setCanceledOnTouchOutside(false);
bar.show();
}
protected void onProgressUpdate(Integer... progress) {
super.onProgressUpdate(progress);
bar.setIndeterminate(false);
bar.setMax(100);
bar.setProgress(progress[0]);
String msg = "";
if(progress[0]>99){
msg="Finishing... ";
}else {
msg="Downloading... "+progress[0]+"%";
}
bar.setMessage(msg);
}
#Override
protected void onPostExecute(Boolean result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
bar.dismiss();
if(result){
Toast.makeText(getApplicationContext(),"Update Done",
Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(getApplicationContext(),"Error: Try Again",
Toast.LENGTH_SHORT).show();
}
}
#Override
protected Boolean doInBackground(String... arg0) {
Boolean flag = false;
try {
URL url = new URL("http://mydownloadurl.com/_download/update.apk");
HttpURLConnection c = (HttpURLConnection) url.openConnection();
c.setRequestMethod("GET");
c.setDoOutput(true);
c.connect();
String PATH = Environment.getExternalStorageDirectory()+"/Download/";
File file = new File(PATH);
file.mkdirs();
File outputFile = new File(file,"app-debug.apk");
if(outputFile.exists()){
outputFile.delete();
}
FileOutputStream fos = new FileOutputStream(outputFile);
InputStream is = c.getInputStream();
int total_size = 277962;//size of apk
byte[] buffer = new byte[1024];
int len1 = 0;
int per = 0;
int downloaded=0;
while ((len1 = is.read(buffer)) != -1) {
fos.write(buffer, 0, len1);
downloaded +=len1;
per = (int) (downloaded * 100 / total_size);
publishProgress(per);
}
fos.close();
is.close();
OpenNewVersion(PATH);
flag = true;
} catch (Exception e) {
Log.e(TAG, "Update Error: " + e.getMessage());
flag = false;
}
return flag;
}
}
void OpenNewVersion(String location) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(new File(location + "app-debug.apk")),
"application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
}
Commonsware thanks a lot, I waste my 2-3 hours to do different ways.
Actually I added this code before but the problem was not solved.
I tried again and it worked, it might be lazy solution but it is working.
This url have more info about the problem ,other solutions can be applied,
but it is enough for me.
if(Build.VERSION.SDK_INT>=24){
try{
Method m = StrictMode.class.getMethod("disableDeathOnFileUriExposure");
m.invoke(null);
}catch(Exception e){
e.printStackTrace();
}
}
It is totally fixed thank you very much again.
Application also need this storage permission.
ActivityCompat.requestPermissions(Update.this,new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE
I have an application that saves data to a file called 'sensorLog.txt'. I am not sure where exactly this is stored but I know this is only accessible by the applicationand it is in the internal memory.
I want to be able to write a copy the current file to an external storage when I click on a button "export". I have pasted a small bit of my program, But i am not sure how to copy sensorLog.txt file to the external storage.
public class MainActivity extends Activity {
private static final String DEBUG_TAG = "MainActivity";
private Button buttonStartService;
private Button buttonStopService;
private Button buttonSettings;
private Button buttonExport;
private TextView textStatus;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Context context = getApplicationContext();
setContentView(R.layout.activity_main);
buttonStartService = (Button) findViewById(R.id.button_start_service);
buttonStopService = (Button) findViewById(R.id.button_stop_service);
buttonSettings = (Button) findViewById(R.id.button_settings);
buttonExport = (Button) findViewById(R.id.button_export);
textStatus = (TextView) findViewById(R.id.text_status);
buttonStartService.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
startSensorService();
}
});
buttonStopService.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
stopSensorService();
}
});
//export button listener
buttonExport.setOnClickListener(export_handler);
}
public void startSensorService() {
// Schedule
AlarmManager scheduler = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(getApplicationContext(), SensorService.class);
PendingIntent scheduledIntent = PendingIntent.getService(getApplicationContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
// 30 seconds
long interval = 30 * 1000;
scheduler.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), interval, scheduledIntent);
Log.d(DEBUG_TAG, "Service started");
}
public void stopSensorService() {
// Cancel
AlarmManager scheduler = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this, SensorService.class);
PendingIntent scheduledIntent = PendingIntent.getService(getApplicationContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
scheduler.cancel(scheduledIntent);
Log.d(DEBUG_TAG, "Service stopped");
}
View.OnClickListener export_handler = new View.OnClickListener() {
public void onClick(View v)
{
// Here is the part I am not sure what to do. I want to copy a file sensorLog.txt that has all my sensor information to sd card
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state))
{
Log.d(DEBUG_TAG, "SD card detected");
stopSensorService();
File file = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DOCUMENTS),"SensorLog.txt");
// delete file from the internal storage once exported
context.deleteFile("SensorLog.txt");
startSensorService();
}
else
{
Log.d(DEBUG_TAG, "No external storage detected(cannot copy file)");
}
}
};
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
Part where I create sensorLog.txt***(I dont think it is necessary to read for this question but just in case someone needs it)*:
private class SensorServiceLoggerTask extends AsyncTask<SensorFrame, Void, Void> {
#Override
protected Void doInBackground(SensorFrame... frames) {
SensorFrame frame = frames[0];
BufferedWriter bufWr = null;
try {
File file = new File(getApplicationContext().getFilesDir(), "SensorLog.txt");
if (file.exists()) {
// Write to new file
bufWr = new BufferedWriter(new FileWriter(file, true));
} else {
file.createNewFile();
Log.d(DEBUG_TAG, "New log file created");
// Append to existing file
bufWr = new BufferedWriter(new FileWriter(file, false));
// Write header
bufWr.append(sensorHeader.toString());
}
// Write frame
bufWr.append(sensorFrame.toString());
bufWr.flush();
Log.d(DEBUG_TAG, "Added frame to log");
} catch (IOException ex) {
// TODO: useful error handling
} finally {
// Cleanup
if (bufWr != null) {
try {
bufWr.close();
} catch (IOException ex) {
// TODO: useful error handling
}
}
}
return null;
}
}
I also have 2 more queries:
Lets say I want to append some information at the top of the file just before moving it how can I do that?
My aim is to transfer the sensorLog.txt file from internal to external storage when the export button is pressed. delete or empty the internal sensorLog.txt file and then the same thing happens again if i press export again, then I would have to rename my file when I export it right? would there not be a name clash? How do I handle that? could I give a name dynamically?
Thank you.
EDIT: Some corrections
View.OnClickListener export_handler = new View.OnClickListener() {
public void onClick(View v)
{
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state))
{
Log.d(DEBUG_TAG, "SD card detected");
stopSensorService();
Log.d(DEBUG_TAG, "stopSensorService for file transfer");
//make the timestamp the file name
long TS = System.currentTimeMillis();
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(TS);
stringBuilder.append(".txt");
String file_name = stringBuilder.toString();
//file name stored in file_name
File file_ext = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DOCUMENTS),file_name);
// attempt to create this new directory
//read from sensorLog.txt file
try
{
file_ext.createNewFile();
File file = getBaseContext().getFileStreamPath("sensorLog.txt");
if(file.exists())
{
FileInputStream read_file = openFileInput("sensorLog.txt");
//read contents of internal file
InputStreamReader inputStreamReader = new InputStreamReader(read_file);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
StringBuilder sb = new StringBuilder();
sb.append("Timestamp of export to SD"+TS+"/n");
String line;
while ((line = bufferedReader.readLine()) != null) {
sb.append(line);
}
BufferedWriter bufWr = null;
bufWr = new BufferedWriter(new FileWriter(file_ext, false));
// Write header
bufWr.append(sb.toString());
inputStreamReader.close();
bufWr.close();
read_file.close();
//delete sensor file once exported
getApplicationContext().deleteFile("sensorLog.txt");
}
}
catch(Exception e){}
But for some reason my file is not getting stored in the SD card.
Check out the Android documentation. If you can read your sensorLog.txt file, then you can save it in a String and then save the string to a file in the external storage.
I have 10 to 12 Activity, All Activity has Help Menu as an Option Menu.
I am succeed with following code to create it and showing help on click of them.
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(new File(cacheDir, "HELP.pdf")),"application/pdf");
context.startActivity(intent);
But I want to Reduce this code for all Activity, and for that i have created one class and make one method but still i want to reduce code.
I have searched and found that onClick attribute is available in OptionMenu but I didn't get how to use it.
Please Help..
Create a class, for example call it Helper, where you put a method called handleMenu(int id) and where you do all the work. Then, in every activity you call that method from onOptionsItemSelected(), passing the id of the item selected.
I have created following Class for openFile:
public class OpenHelpFile {
File cacheDir;
Context context;
/* Constructor */
public OpenHelpFile(Context context) {
this.context = context;
if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED))
cacheDir = new File(android.os.Environment.getExternalStorageDirectory(), "OOPS");
else
cacheDir = context.getCacheDir();
if (!cacheDir.exists())
cacheDir.mkdirs();
try {
File helpFile = new File(cacheDir, "OOPS.pdf");
if (!helpFile.exists()) {
InputStream in = context.getAssets().open("OOPS.pdf");
OutputStream out = new FileOutputStream(helpFile);
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
out.close();
Log.d(TAG, "File Copied...");
}
Log.d(TAG, "File exist...");
} catch (FileNotFoundException ex) {
Log.d(TAG, ex.getMessage() + " in the specified directory.");
System.exit(0);
} catch (IOException e) {
Log.d(TAG, e.getMessage());
}
}
public void openHelpFile() {
/* OPEN PDF File in Viewer */
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(new File(cacheDir, "OOPS.pdf")), "application/pdf");
context.startActivity(intent);
}
}
and I have call it from every OptionMenu like this:
new OpenHelpFile(context).openHelpFile();
I am downloading a file from ftp server. downloading code worked fine, however after download code screen doesn't show anything ,it gets black. Also download function is not returning true value, even the file is being saved in the specified directory.
public class FTPClass{
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_file_player);
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
Intent intent = getIntent();
dirname = intent.getStringExtra("currentDirName");
MyFTPClient mftp = new MyFTPClient();
createPath = mftp.getAppRootPath().concat("/"+ dirname);
mftp.setCurrentDir(createPath);
System.out.println(mftp.ftpChangeDirectory(createPath));
FTPFile[] farr = mftp.ftpListAllFiles();
System.out.println(farr.length);
for(int i = 0; i<farr.length;i++){
System.out.println("SRC: "+createPath+"/"+farr[i].getName());
String src = createPath+"/"+farr[i].getName();
System.out.println("DEST: "+"/data/data/com.example.ftpplayer" + "/app_"+dirname);
String dest ="/data/data/com.example.ftpplayer" + "/app_"+dirname+"/"+farr[i].getName();
System.out.println(mftp.downloadFile(src,dest));
}
}
}
public class CallingIntent extends Activity{
System.out.println("In item click ");
Intent intent = new Intent(getApplicationContext(), FTPClass.class);
String dir = ((TextView) view).getText().toString();
intent.putExtra("currentDirName", dir);
startActivity(intent);
}
public class MyFTPClient{
public boolean downloadFile(String srcPath , String destPath){
try {
FileOutputStream fos = new FileOutputStream(destPath);
System.out.println(mftp.retrieveFile(srcPath, fos)); // retrieve file doesn't return true
fos.flush();
fos.close();
return true;
} catch (FileNotFoundException e) {
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}
return false;
}
}
You need to run your code on the background thread, try using an asyncTask.
How can a file (SQLlite, Text, etc.) be loaded onto the SD card from the Assets folder and only at first run of the application?
Here is the methods I use. Have this as the main activity of your application and use it to start your real application activity.
public class StartUp extends Activity {
/**
* -- Called when the activity is first created.
* ==============================================================
**/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FirstRun();
}
private void FirstRun() {
SharedPreferences settings = this.getSharedPreferences("YourAppName", 0);
boolean firstrun = settings.getBoolean("firstrun", true);
if (firstrun) { // Checks to see if we've ran the application b4
SharedPreferences.Editor e = settings.edit();
e.putBoolean("firstrun", false);
e.commit();
// If not, run these methods:
SetDirectory();
Intent home = new Intent(StartUp.this, YourMainActivity.class);
startActivity(home);
} else { // Otherwise start the application here:
Intent home = new Intent(StartUp.this, YourMainActivity.class);
startActivity(home);
}
}
/**
* -- Check to see if the sdCard is mounted and create a directory w/in it
* ========================================================================
**/
private void SetDirectory() {
if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) {
extStorageDirectory = Environment.getExternalStorageDirectory().toString();
File txtDirectory = new File(extStorageDirectory + "/yourAppName/txtDirectory/");//Example name for txt files
// Create
// a
// File
// object
// for
// the
// parent
// directory
txtDirectory.mkdirs();// Have the object build the directory
// structure, if needed.
CopyAssets(); // Then run the method to copy the file.
} else if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED_READ_ONLY)) {
AlertsAndDialogs.sdCardMissing(this);//Or use your own method ie: Toast
}
}
/**
* -- Copy the file from the assets folder to the sdCard
* ===========================================================
**/
private void CopyAssets() {
AssetManager assetManager = getAssets();
String[] files = null;
try {
files = assetManager.list("");
} catch (IOException e) {
Log.e("tag", e.getMessage());
}
for (int i = 0; i < files.length; i++) {
InputStream in = null;
OutputStream out = null;
try {
in = assetManager.open(files[i]);
out = new FileOutputStream(extStorageDirectory + "/yourAppName/txt/" + files[i]);
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);
}
}