This code is working till android 10 but now I want to upgrade it to android 11. I can save the jpeg & even can read the directory but I can't save pdf in android 11. I tried everything on internet but can't find anything. Can someone help me.
My Manifest
<uses-permission android:name="com.samsung.android.providers.context.permission.WRITE_USE_APP_FEATURE_SURVEY" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_INTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<application
android:name=".MyApplication"
android:allowBackup="true"
android:requestLegacyExternalStorage="true"
android:preserveLegacyExternalStorage="true"
android:usesCleartextTraffic="true"
android:networkSecurityConfig="#xml/network_security_config"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher"
android:supportsRtl="true"
android:theme="#style/AppTheme">
My Bitmap function
#RequiresApi(api = Build.VERSION_CODES.KITKAT)
public void saveBitmap(Bitmap bmp) {
File filename;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R){
try {
String path1 = Environment.getExternalStorageDirectory().toString() + File.separator + "Documents";
Log.i("in save()", "after mkdir");
File file = new File(path1 + "/" + "Premium Scanner/IMAGES");
if (!file.exists())
file.mkdirs();
filename = new File(file.getAbsolutePath() + "/" + "IMG_" + timeStamp + ".jpg");
Log.i("in save()", "after file");
FileOutputStream out = new FileOutputStream(filename);
Log.i("in save()", "after outputstream");
bmp.compress(Bitmap.CompressFormat.JPEG, 90, out);
out.flush();
out.close();
ContentValues image = getImageContent(filename);
getActivity().getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, image);
createPdf(bmp);
Toast.makeText(getActivity().getApplicationContext(), "Image saved successfully", Toast.LENGTH_SHORT).show();
} catch (Exception e) {
e.printStackTrace();
}
}
}
My PDF Function
#RequiresApi(api = Build.VERSION_CODES.KITKAT)
private void createPdf(Bitmap bitmap) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R){
WindowManager wm = (WindowManager) getActivity().getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
DisplayMetrics displaymetrics = new DisplayMetrics();
getActivity().getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
float hight = displaymetrics.heightPixels;
float width = displaymetrics.widthPixels;
int convertHighet = (int) hight, convertWidth = (int) width;
PdfDocument document = new PdfDocument();
PdfDocument.PageInfo pageInfo = new PdfDocument.PageInfo.Builder(bitmap.getWidth(), bitmap.getHeight(), 1).create();
PdfDocument.Page page = document.startPage(pageInfo);
Canvas canvas = page.getCanvas();
Paint paint = new Paint();
paint.setColor(Color.parseColor("#ffffff"));
canvas.drawPaint(paint);
bitmap = Bitmap.createScaledBitmap(bitmap, bitmap.getWidth(), bitmap.getHeight(), true);
paint.setColor(Color.BLUE);
canvas.drawBitmap(bitmap, 0, 0, null);
document.finishPage(page);
// write the document content
String path1 = Environment.getExternalStorageDirectory().toString() + File.separator + "Documents";
Log.i("in save()", "after mkdir");
File file = new File(path1 + "/" + "Premium Scanner/PDF/");
if (!file.exists())
file.mkdirs();
File filepath = new File(file.getAbsolutePath() + "/" + "FILE_" + timeStamp + ".pdf");
Log.i("in save()", "after file");
try {
document.writeTo(new FileOutputStream(filepath));
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(getActivity(), "Something wrong: " + e.toString(), Toast.LENGTH_LONG).show();
}
document.close();
}
}
Image Content Function
public ContentValues getImageContent(File parent) {
ContentValues image = new ContentValues();
try{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R){
image.put(MediaStore.MediaColumns.TITLE, "IMG_" + timeStamp);
image.put(MediaStore.MediaColumns.DISPLAY_NAME, "IMG_" + timeStamp);
image.put(MediaStore.Images.Media.DESCRIPTION, "App Image");
image.put(MediaStore.MediaColumns.DATE_ADDED, System.currentTimeMillis());
image.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpg");
image.put(MediaStore.MediaColumns.ORIENTATION, 0);
image.put(MediaStore.MediaColumns.BUCKET_ID, parent.toString().toLowerCase().hashCode());
image.put(MediaStore.MediaColumns.BUCKET_DISPLAY_NAME, parent.getName().toLowerCase());
image.put(MediaStore.MediaColumns.SIZE, parent.length());
image.put(MediaStore.Images.Media.RELATIVE_PATH, parent.getAbsolutePath());
dismissDialog();
getActivity().finish();
}
} catch (Exception e){
Toast.makeText(getActivity(), "Image not saved \n" + e.getMessage(), Toast.LENGTH_SHORT).show();`
}
return image;
}
Related
I'm having a problem downloading and installing the app.
On android below 10 this code works.
I am trying to update my application from the server.
Manifest
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
...
<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/provider_paths" />
</provider>
Activity
If there is an update, then a snackbar appears and by clicking update the application should download and install
private void showSnackbar() {
Snackbar snackbar =
Snackbar.make(
findViewById(android.R.id.content),
"update available",
Snackbar.LENGTH_INDEFINITE);
snackbar.setAction("update", new View.OnClickListener() {
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
#Override
public void onClick(View v) {
try {
if (checkPermission()) {
UpdateApp atualizaApp = new UpdateApp();
atualizaApp.setContext(CommonListObjects.this);
atualizaApp.execute("http://195.200.000.000:0000/app.apk");
} else {
requestPermission();
}
} catch (android.content.ActivityNotFoundException anfe) {
}
}
});
snackbar.show();
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
if (requestCode == PERMISSION_REQUEST_CODE) {
if (grantResults.length > 0) {
boolean locationAccepted = grantResults[0] == PackageManager.PERMISSION_GRANTED;
boolean cameraAccepted = grantResults[1] == PackageManager.PERMISSION_GRANTED;
if (locationAccepted && cameraAccepted) {
UpdateApp updateApp = new UpdateApp();
updateApp.setContext(CommonListObjects.this);
updateApp.execute("http://195.200.000.000:0000/app.apk");
}
}
}
}
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
private boolean checkPermission() {
int result = ContextCompat.checkSelfPermission(getApplicationContext(), WRITE_EXTERNAL_STORAGE);
int result1 = ContextCompat.checkSelfPermission(getApplicationContext(), READ_EXTERNAL_STORAGE);
return result == PackageManager.PERMISSION_GRANTED && result1 == PackageManager.PERMISSION_GRANTED;
}
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
private void requestPermission() {
ActivityCompat.requestPermissions(this, new String[]{WRITE_EXTERNAL_STORAGE, READ_EXTERNAL_STORAGE}, PERMISSION_REQUEST_CODE);
}
this is how it loads
#Override
protected String doInBackground(String... arg0) {
try {
URL url = new URL(arg0[0]);
HttpURLConnection c = (HttpURLConnection) url.openConnection();
c.setRequestMethod("GET");
c.setDoOutput(true);
c.connect();
int lenghtOfFile = c.getContentLength();
String PATH = Environment.getExternalStorageDirectory() + "/" + "app.apk";
File file = new File(PATH);
boolean isCreate = file.mkdirs();
File outputFile = new File(file, "app.apk");
if (outputFile.exists()) {
boolean isDelete = outputFile.delete();
}
FileOutputStream fos = new FileOutputStream(outputFile);
InputStream is = c.getInputStream();
byte[] buffer = new byte[1024];
int len1;
long total = 0;
while ((len1 = is.read(buffer)) != -1) {
total += len1;
fos.write(buffer, 0, len1);
publishProgress((int) ((total * 100) / lenghtOfFile));
}
fos.close();
is.close();
if (mPDialog != null)
mPDialog.dismiss();
installApk();
} catch (Exception e) {
Log.e("UpdateAPP", "Update error! " + e.getMessage());
}
return null;
}
this is how the installation works
void installApk(){
String PATH = Environment.getExternalStorageDirectory() + "/" + "app.apk"+ "/" + "app.apk";
File file = new File(PATH);
if(file.exists()) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(uriFromFile(getApplicationContext(), new File(PATH)), "application/vnd.android.package-archive");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
try {
getApplicationContext().startActivity(intent);
} catch (ActivityNotFoundException e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(),"Error in opening the file!",Toast.LENGTH_LONG).show();
}
}else{
Toast.makeText(getApplicationContext(),"installing",Toast.LENGTH_LONG).show();
}
}
Uri uriFromFile(Context context, File file) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
return FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".provider", file);
} else {
return Uri.fromFile(file);
}
}
on android below 10 works, but in 10 and 11 does not work. even the file does not load.
Java code:
public void onClick(View v) {
switch (v.getId()){
case R.id.btn_camera:
if (i==21) {
Toast.makeText(FileUploadActivity.this,R.string.max_file_upload,Toast.LENGTH_SHORT).show();
}
else {
++i;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ActivityCompat.checkSelfPermission(FileUploadActivity.this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, MY_PERMISSIONS);
} else if (ActivityCompat.checkSelfPermission(FileUploadActivity.this, android.Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{android.Manifest.permission.CAMERA}, MY_PERMISSIONS);
} else {
openCamera();
}
} else {
openCamera();
}
}
break;
public void openCamera() {
File photoFile = null;
try {
photoFile = createTempFile("Images", "IMG_", ".jpg"); //error
Log.i(TAG, "openCamera: Camera access"+photoFile);
} catch (IOException e) {
e.printStackTrace();
}
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
takePictureIntent.putExtra("PhotoPath", mCameraPhotoPath);
if (photoFile != null) {
mCameraPhotoPath = photoFile.getAbsolutePath();
}else {
Toast.makeText(FileUploadActivity.this,"Unable to open",Toast.LENGTH_LONG).show();
}
// takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile));
// startActivityForResult(takePictureIntent, SELECT_PICTURE);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,Uri.fromFile(photoFile));
} else {
File file = new File(Uri.fromFile(photoFile).getPath());
Uri photoUri = FileProvider.getUriForFile(getApplicationContext(), getApplicationContext().getPackageName() + ".provider", file);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
}
takePictureIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
if (takePictureIntent.resolveActivity(getApplicationContext().getPackageManager()) != null) {
startActivityForResult(takePictureIntent, SELECT_PICTURE);
}
}
private File createTempFile(String storage,String fileName,String fileType) throws IOException {
File imageFile = null;
File folder = new File(Environment.getExternalStorageDirectory() +
File.separator + "CTrack" + File.separator + storage);
boolean success = true;
if (!folder.exists()) {
success = folder.mkdirs();
}
if (success) {
String timeStamp = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss").format(new Date());
String imageFileName = fileName + timeStamp + "_";
imageFile = File.createTempFile(imageFileName, fileType, folder);
}
return imageFile;
}
private String encodeImage(String path) {
File imagefile = new File(path);
FileInputStream fis = null;
String encodeResponse="";
try {
fis = new FileInputStream(imagefile);
Bitmap bm = BitmapFactory.decodeStream(fis);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.JPEG, 100, baos);
byte[] b = baos.toByteArray();
encodeResponse=Base64.encodeToString(b, Base64.DEFAULT);
} catch (FileNotFoundException e) {
e.printStackTrace();
encodeResponse="nofile";
}
catch (OutOfMemoryError e) {
e.printStackTrace();
encodeResponse="memory";
}
return encodeResponse;
}
Permissions:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
error:
2021-05-03 12:52:30.921 9669-9669/com.transasia.ctrack E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.transasia.ctrack, PID: 9669
android.os.FileUriExposedException: file:///storage/emulated/0/CTrack/Images/IMG_2021-05-03T12%3A52%3A30_6074100336714487332.jpg exposed beyond app through ClipData.Item.getUri()
at android.os.StrictMode.onFileUriExposed(StrictMode.java:2083)
at android.net.Uri.checkFileUriExposed(Uri.java:2388)
at android.content.ClipData.prepareToLeaveProcess(ClipData.java:977)
at android.content.Intent.prepareToLeaveProcess(Intent.java:10759)
at android.content.Intent.prepareToLeaveProcess(Intent.java:10744)
at android.app.Instrumentation.execStartActivity(Instrumentation.java:1703)
at android.app.Activity.startActivityForResult(Activity.java:5192)
at androidx.fragment.app.FragmentActivity.startActivityForResult(FragmentActivity.java:675)
at android.app.Activity.startActivityForResult(Activity.java:5150)
App is working in android 9 and below 9 but when it comes to android 10 and 11, app is crashing and getting file error. I thought problem with creating temp file because there it gives me an error.
Thank you,........................................................................Thanks...........................................................................................................
Try this
In Manifest file - add provider inside
<application android:requestLegacyExternalStorage="true">
<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/provider_paths" />
</provider>
create provider_path.xml (res -> xml -> provider_path.xml)
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path
name="external_files"
path="." />
</paths>
Add Camera permission
<uses-permission android:name="android.permission.CAMERA"/>
<uses-feature android:name="android.hardware.camera" />
As soon as the user clicks the button, I ask him to take a screenshot and send it to another friend.
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
View rootView = getWindow().getDecorView().findViewById(android.R.id.content);
Bitmap bitmap = getScreenShot(rootView);
File file = store(bitmap,"File-Name");
shareImage(file);
}
});
public static Bitmap getScreenShot(View view) {
View screenView = view.getRootView();
screenView.setDrawingCacheEnabled(true);
Bitmap bitmap = Bitmap.createBitmap(screenView.getDrawingCache());
screenView.setDrawingCacheEnabled(false);
return bitmap;
}
public static File store(Bitmap bm, String fileName){
final String dirPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Screenshots";
File dir = new File(dirPath);
if(!dir.exists())
dir.mkdirs();
File file = new File(dirPath, fileName);
try {
FileOutputStream fOut = new FileOutputStream(file);
bm.compress(Bitmap.CompressFormat.PNG, 85, fOut);
fOut.flush();
fOut.close();
} catch (Exception e) {
e.printStackTrace();
}
return file;
}
private void shareImage(File file){
Uri uri = Uri.fromFile(file);
Intent intent = new Intent();
intent.setAction(Intent.ACTION_SEND);
intent.setType("image/*");
intent.putExtra(android.content.Intent.EXTRA_SUBJECT, "");
intent.putExtra(android.content.Intent.EXTRA_TEXT, "");
intent.putExtra(Intent.EXTRA_STREAM, uri);
try {
startActivity(Intent.createChooser(intent, "Share Screenshot"));
} catch (ActivityNotFoundException e) {
Toast.makeText(this, "No App Available", Toast.LENGTH_SHORT).show();
}
}
I see that the bitmap value is "" when I debug. I also have these in my error message.
Error Log Image
I used them in my manifest file.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<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/provider_path" />
</provider>
Could you please help me?
You should use this code
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
View rootView = getWindow().getDecorView().findViewById(android.R.id.content);
Bitmap bitmap = getScreenShot(rootView);
File file = store(bitmap, "name.png");
if (file.exists()) {
shareImage(file);
} else {
Log.e("file exist", "NO");
}
}
});
public static Bitmap getScreenShot(View view) {
View screenView = view.getRootView();
screenView.setDrawingCacheEnabled(true);
Bitmap bitmap = Bitmap.createBitmap(screenView.getDrawingCache());
screenView.setDrawingCacheEnabled(false);
return bitmap;
}
public File store(Bitmap bm, String fileName) {
final String dirPath = getExternalCacheDir().getAbsolutePath() + "/Screenshots";
File dir = new File(dirPath);
if (!dir.exists())
dir.mkdirs();
File file = new File(dirPath, fileName);
try {
FileOutputStream fOut = new FileOutputStream(file);
bm.compress(Bitmap.CompressFormat.PNG, 85, fOut);
fOut.flush();
fOut.close();
} catch (Exception e) {
e.printStackTrace();
}
return file;
}
private void shareImage(File file) {
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse(file.getPath()));
shareIntent.setType("image/*");
startActivity(Intent.createChooser(shareIntent, "Share Screenshot"));
}
Use this to capture a bitmap from a view. Your method will not work anymore using the drawing cache.
public drawBitmap(View view, int width, int height) {
Bitmap bm = Bitmap.createBitmap(width,
height,
Bitmap.Config.ARGB_8888)
Canvas canvas = Canvas(bm)
canvas.drawColor(previewBgColor)
view.draw(canvas)
// Store bitmap in dest file,
File dstFile = File("path/to/file")
storeBitmap(dstFile, bm)
}
public String storeBitmap(File file, Bitmap bmp) {
FileOutputStream stream;
try {
stream = FileOutputStream(file, false)
bmp.compress(Bitmap.CompressFormat.JPEG,99,it)
} catch (e: Exception) {
} finally {
stream.close()
}
return file.path
}
If the file exception persists let us know. I am assuming it's giving that error because the bitmap file returns ""? The docs here should be enough to get you through.
I was able to solve the problem with such a structure. Thank you very much to P Fuster for all his help.
We add these permissions first to the manifests file.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
then we add them to the onCreate method in mainActivity.
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());
Now let's give the click effect of our button.
share_friends.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
View rootView = getWindow().getDecorView().findViewById(android.R.id.content);
Bitmap bitmap = getScreenShot(rootView);
File file = store(bitmap, "name.png");
if (file.exists()) {
shareImage(file);
System.out.println(file.getPath());
} else {
Log.e("file exist", "NO");
}
}
});
Functions used in the button
public static Bitmap getScreenShot(View view) {
View screenView = view.getRootView();
screenView.setDrawingCacheEnabled(true);
Bitmap bitmap = Bitmap.createBitmap(screenView.getDrawingCache());
screenView.setDrawingCacheEnabled(false);
return bitmap;
}
public File store(Bitmap bm, String fileName) {
final String dirPath = Environment.getExternalStorageDirectory().getPath() + "/Screenshots";
File dir = new File(dirPath);
if (!dir.exists())
dir.mkdirs();
File file = new File(dirPath, fileName);
try {
FileOutputStream fOut = new FileOutputStream(file);
bm.compress(Bitmap.CompressFormat.PNG, 85, fOut);
fOut.flush();
fOut.close();
} catch (Exception e) {
e.printStackTrace();
}
return file;
}
private void shareImage(File file) {
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.setType("image/*");
shareIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(file));
shareIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(Intent.createChooser(shareIntent, "Share Screenshot"));
}
the problem was solved like this.
In my App the user is able to save images from a pciture gallery to the local device by clicking on a DL Button.
The Code does work on old devices but on API 29 it has the following behaviour:
While saving I tried to open the Gallery to have a look what happens: the gallery gets updated and for 1 second an empty images appears and disappears immediately after. I get noticed, that the image got saved but it doesn't appear, not even in the device explorer.
//DEXTER HERE
Picasso.get().load(dummyimage.getLarge()).placeholder(R.drawable.ic_img_error).error(R.drawable.ic_red).into(saveImageToDirectory);
final Target saveImageToDirectory = new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
ProgressDialog mydialog = new ProgressDialog(getActivity());
mydialog.setMessage("saving Image to phone");
mydialog.show();
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());
try {
String fileName = "myApp_" + timeStamp + ".JPG";
String dirName= "/myApp";
File file = new File(requireActivity().getApplicationContext().getExternalFilesDir(null).getAbsolutePath() + dirName, fileName);
//new File(path for the file to be saved, saving file name)
if (!file.exists()) {
//check if the file already exist or if not create a new file
//if exist the file will be overwritten with the new image
File filedirectory = new File(requireActivity().getApplicationContext().getExternalFilesDir(null).getAbsolutePath() + dirName);
filedirectory.mkdirs();
}
if (file.exists()) {
file.delete();
}
FileOutputStream ostream = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, ostream);
Toast.makeText(getActivity(), "Picture saved to Gallery" + file.getAbsolutePath(), Toast.LENGTH_SHORT).show();
ostream.close();
mydialog.dismiss();
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.TITLE, "My Images");
values.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg");
values.put(MediaStore.MediaColumns.RELATIVE_PATH,"/myApp");
// API LEVEL Q: values.put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis());
values.put("_data", file.getAbsolutePath());
ContentResolver cr = getActivity().getContentResolver();
cr.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
} catch (Exception e) {
mydialog.dismiss();
Log.e("file creation error", e.toString());
}
}
#Override
public void onBitmapFailed(Exception e, Drawable errorDrawable) {
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
};
As you may see, instead of
File filedirectory = new File(Environment.getExternalStorageDirectory() + dirName);
I'm already using
File filedirectory = new File(requireActivity().getApplicationContext().getExternalFilesDir(null).getAbsolutePath() + dirName);
I hope this shouldn't be the problem, but I'm a little stuck on this strange behaviour.
This is the error I'm getting out of my Logcat:
E/file creation error: java.lang.IllegalArgumentException: Primary
directory (invalid) not allowed for
content://media/external/images/media; allowed directories are [DCIM,
Pictures]
PS: I'm using Dexter to avoid problems with the permissions
Try this
private Uri saveImage(Context context, Bitmap bitmap, #NonNull String folderName, #NonNull String fileName) throws IOException
{
OutputStream fos;
File imageFile = null;
Uri imageUri = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
ContentResolver resolver = context.getContentResolver();
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, fileName);
contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/png");
contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, "DCIM" + File.separator + folderName);
imageUri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
fos = resolver.openOutputStream(imageUri);
} else {
String imagesDir = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DCIM).toString() + File.separator + folderName;
imageFile = new File(imagesDir);
if (!imageFile.exists()) {
imageFile.mkdir();
}
imageFile = new File(imagesDir, fileName + ".png");
fos = new FileOutputStream(imageFile);
}
boolean saved = bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
fos.flush();
fos.close();
if (imageFile != null) // pre Q
{
MediaScannerConnection.scanFile(context, new String[]{imageFile.toString()}, null, null);
imageUri = Uri.fromFile(imageFile);
}
return imageUri;
}
And add requestLegacyExternalStorage in your Manifest file
<application
android:allowBackup="true"
android:icon="#drawable/icon"
android:requestLegacyExternalStorage="true"
android:label="#string/app_name"
android:roundIcon="#drawable/icon"
android:supportsRtl="true"
android:theme="#style/AppTheme">
...
...
...
</application>
Below is my code for MainActivity.java.The error according to toasts is in creating directory.
MainActivity.java
#Override
protected void onActivityResult(int requestcode,int resultcode,Intent data){
super.onActivityResult(requestcode,resultcode,data);
if (requestcode == TAKE_PICTURE)
{
if(resultcode== Activity.RESULT_OK){
ImageView imageHolder = (ImageView)findViewById(R.id.image_camera);
Bitmap bitmap = (Bitmap)data.getExtras().get("data");
String partFilename = currentDateFormat();
storeCameraPhotoInSDCard(bitmap, partFilename);
// display the image from SD Card to ImageView Control
String storeFilename = "photo_" + partFilename + ".jpg";
Bitmap mBitmap = getImageFileFromSDCard(storeFilename);
imageHolder.setImageBitmap(mBitmap);
}
}
}
private String currentDateFormat(){
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HH_mm_ss");
String currentTimeStamp = dateFormat.format(new Date(0));
return currentTimeStamp;
}
/* Checks if external storage is available for read and write */
public boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
Toast.makeText(MainActivity.this, "WriteMode ON", Toast.LENGTH_SHORT).show();
return true;
}
Toast.makeText(MainActivity.this, "WriteMode OFF", Toast.LENGTH_SHORT).show();
return false;
}
/* Checks if external storage is available to at least read */
public boolean isExternalStorageReadable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state) ||
Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
Toast.makeText(MainActivity.this, "Mounted or ReadMode", Toast.LENGTH_SHORT).show();
return true;
}
Toast.makeText(MainActivity.this, "no-Mounted or no-ReadMode", Toast.LENGTH_SHORT).show();
return false;
}
private void storeCameraPhotoInSDCard(Bitmap bitmap, String currentDate){
boolean isAvailable=isExternalStorageWritable();
if(isAvailable){
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG,90, bytes);
String imgUri = "photo_" + currentDate + ".jpg";
File appDirectory = new File(Environment.getExternalStorageDirectory(),"CountDotsAppImages");
boolean success = appDirectory.mkdirs();
if (success) {
Toast.makeText(MainActivity.this, "Directory Created", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(MainActivity.this, "Failed - Error", Toast.LENGTH_SHORT).show();
}
File destination = new File(Environment.getExternalStorageDirectory(),"CountDotsAppImages/"+imgUri);
FileOutputStream fo;
try {
destination.createNewFile();
fo = new FileOutputStream(destination);
fo.write(bytes.toByteArray());
fo.close();
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
private Bitmap getImageFileFromSDCard(String filename){
File storageDir = new File(Environment.getExternalStorageDirectory() + "/", "CountDotsAppImages");
Bitmap bitmap = null;
File imageFile = new File(storageDir.getPath()+File.separator + filename);
try {
FileInputStream fis = new FileInputStream(imageFile);
Toast.makeText(MainActivity.this, imageFile.toString() , Toast.LENGTH_LONG).show();
bitmap = BitmapFactory.decodeStream(fis);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return bitmap;
}
AndroidManifest.xml
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> permission is added
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.countdots"
android:versionCode="1"
android:versionName="1.0" android:installLocation="auto">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="23" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Toasts Output :
Mounted or ReadMode
WriteMode ON
Directory Does Not Exist, Create It
Failed -Error //Error in creating directory mkdir
I tried using both mkdir() and mkdirs()
Figured it out.
As, I was compiling with Android 6.0. It requires user to grant permission.
So,following code should be inserted and checked if user grants app permission or not.Then if user grants permission to read and write manifest will be updated and volia !!!
if (Build.VERSION.SDK_INT >= 23) {
if (ContextCompat.checkSelfPermission(MainActivity.this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(MainActivity.this, android.Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE, android.Manifest.permission.READ_EXTERNAL_STORAGE},
1);
} else {
//do something
}
} else {
//do something
}
This code works for me
try{
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG,90, bytes);
imgUri = "photo_" + System.currentTimeMillis() + ".jpg";
File appDirectory = new File(Environment.getExternalStorageDirectory(),"CountDotsAppImages");
appDirectory.mkdirs();
File destination = new File(Environment.getExternalStorageDirectory(),"CountDotsAppImages/"+imgUri);
FileOutputStream fo;
try {
destination.createNewFile();
fo = new FileOutputStream(destination);
fo.write(bytes.toByteArray());
fo.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
For adding directory you can use this method.
isAvailable=ExternalStorageChecker.isExternalStorageWritable();
if(isAvailable){
dir = new File(myContext.getExternalFilesDir(null), newAlbumDir.getText().toString().trim());
if(!dir.mkdirs()){
Log.e("++++++","Directoy Already Exist");
Log.e("External Directory Path","++++"+dir.getAbsolutePath());
}
else{
Log.e("++++","Directory Created");
Toast.makeText(myContext,"File Created on External",Toast.LENGTH_SHORT).show();
Log.e("Externa Directory Path","++++"+dir.getAbsolutePath());
}
}
else{
Toast.makeText(myContext,"File Created on Internal",Toast.LENGTH_SHORT).show();
Log.e("Internal Directory Path","++++"+myContext.getFilesDir().getPath());
dir=new File(myContext.getFilesDir(),newAlbumDir.getText().toString());
}
After it created the directory(dir) you can use to create the File.