Sharing image using intent with Glide library- Image is null always - android

I have a custom listview which is working good, now i want to share the image and text from the list. I have found a step how to do it from SO but image is always null when i click on Share button.
The imageview loading images using Glide.
if (!Patterns.WEB_URL.matcher(Limage).matches()) {
viewholder.iview.setVisibility(View.GONE);
} else {
Glide.with(convertView.getContext()).load(Limage).centerCrop()
.diskCacheStrategy(DiskCacheStrategy.ALL).listener(new RequestListener<String, GlideDrawable>() {
#Override
public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) {
return false;
}
#Override
public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
// viewholder.progress.setVisibility(View.GONE);
return false;
}
}).into(viewholder.iview);
viewholder.iview.setVisibility(View.VISIBLE);
}
I have created a Share button and inside onclick i am passing the below code.
viewholder.share.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Uri bmpUri = getLocalBitmapUri(viewholder.iview);
if (bmpUri != null) {
// Construct a ShareIntent with link to image
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.putExtra(Intent.EXTRA_STREAM, bmpUri);
shareIntent.setType("image/*");
// Launch sharing dialog for image
listdisplay.startActivity(Intent.createChooser(shareIntent, "Share Image"));
} else {
// ...sharing failed, handle error
}
}
});
To get image from Imageview i am using the below code.
private Uri getLocalBitmapUri(ImageView iview) {
Drawable drawable = iview.getDrawable();
Bitmap bmp = null;
if (drawable instanceof BitmapDrawable){
bmp = ((BitmapDrawable) iview.getDrawable()).getBitmap();
Log.e("Shiva","Came inside drawable");
} else {
Log.e("Shiva","drawable is null"+drawable);
return null;
}
Uri bmpUri = null;
File file = new File(listdisplay.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "share_image_" + System.currentTimeMillis() + ".png");
FileOutputStream out = null;
try {
out = new FileOutputStream(file);
bmp.compress(Bitmap.CompressFormat.PNG, 90, out);
out.close();
bmpUri = Uri.fromFile(file);
} catch (IOException e) {
e.printStackTrace();
}
// **Warning:** This will fail for API >= 24, use a FileProvider as shown below instead.
return bmpUri;
}
So, what happened now is in the if step where it is checking "drawable instanceof BitmapDrawable" is always returns null. whats wrong here?
Note: Above code are inside the adapter.

You can load image using this :
Glide.with(this)
.load("https://cdn-images-1.medium.com/max/1200/1*hcfIq_37pabmAOnw3rhvGA.png")
.asBitmap()
.diskCacheStrategy(DiskCacheStrategy.SOURCE)
.into(new SimpleTarget<Bitmap>() {
#Override
public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {
Log.d("Size ", "width :"+resource.getWidth() + " height :"+resource.getHeight());
imageView.setImageBitmap(resource);
storeImage(resource);
}
});
And store bitmap to external storage and then share it.
private void storeImage(Bitmap image) {
File pictureFile = getOutputMediaFile();
if (pictureFile == null) {
Log.d(TAG,
"Error creating media file, check storage permissions: ");// e.getMessage());
return;
}
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
image.compress(Bitmap.CompressFormat.PNG, 90, fos);
fos.close();
Log.d(TAG, "img dir: " + pictureFile);
} catch (FileNotFoundException e) {
Log.d(TAG, "File not found: " + e.getMessage());
} catch (IOException e) {
Log.d(TAG, "Error accessing file: " + e.getMessage());
}
}
private File getOutputMediaFile(){
// To be safe, you should check that the SDCard is mounted
// using Environment.getExternalStorageState() before doing this.
File mediaStorageDir = new File(Environment.getExternalStorageDirectory()
+ "/Android/data/"
+ getApplicationContext().getPackageName()
+ "/Files");
if (! mediaStorageDir.exists()){
if (! mediaStorageDir.mkdirs()){
return null;
}
}
File mediaFile;
Random generator = new Random();
int n = 1000;
n = generator.nextInt(n);
String mImageName = "Image-"+ n +".jpg";
mediaFile = new File(mediaStorageDir.getPath() + File.separator + mImageName);
return mediaFile;
}

iview.getDrawable() will return null when using Glide.
You can set:
public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
viewholder.iview.setDrawable(resource);
return true;
}
then iview.getDrawable() will return drawable

// Pass the Activity Context, ImageView, Image path which is located inside sdcard,And default Image you want to display to
loadImageWithGlide Method.
loadImageWithGlide(this,imageView,imagePath,R.drawable.damaged_image,R.drawable.damaged_image);
// Method to Load Image from Sdcard to ImageView With Using Glide Library
public static void loadImageWithGlide(final Context context, ImageView theImageViewToLoadImage,
String theLoadImagePath, int theDefaultImagePath, int tehErrorImagePath) {
if (context == null) return;
Glide.with(context) //passing context
.load(theLoadImagePath) //passing your url to load image.
.placeholder(theDefaultImagePath) //this would be your default image (like default profile or logo etc). it would be loaded at initial time and it will replace with your loaded image once glide successfully load image using url.
.error(tehErrorImagePath)//in case of any glide exception or not able to download then this image will be appear . if you won't mention this error() then nothing to worry placeHolder image would be remain as it is.
.diskCacheStrategy(DiskCacheStrategy.ALL) //using to load into cache then second time it will load fast.
//.animate(R.anim.fade_in) // when image (url) will be loaded by glide then this face in animation help to replace url image in the place of placeHolder (default) image.
.fitCenter()//this method help to fit image into center of your ImageView
.into(theImageViewToLoadImage); //pass imageView reference to appear the image.
}
// Bellow is Code to share Image
// Note: The image needed to located inside Sdcard. Pass that path inside Share Method.
public static void share(Context theCtx, String theImagePath, String theText) {
File myImageFile = new File(theImagePath);
String shareBody = theText; //"Here is the share content body " ;
Intent sharingIntent = new Intent(Intent.ACTION_SEND);
if (myImageFile.exists()) {
sharingIntent.setType("image/jpeg");
sharingIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("file://" + myImageFile.getAbsolutePath()));
} else if (!theText.isEmpty()) {
sharingIntent.setType("text/*");
}
sharingIntent.putExtra(Intent.EXTRA_SUBJECT, ""); //"Subject here"
sharingIntent.putExtra(Intent.EXTRA_TEXT, shareBody);
sharingIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
theCtx.startActivity(Intent.createChooser(sharingIntent, "Share via"));
}

You need to create a cache in memory with your image than you can extract it, otherwise is null, may be destroyed.
imageView.setDrawingCacheEnabled(true);
imageView.buildDrawingCache();
Bitmap bitmap = imageView.getDrawingCache();

Related

Any Android libraries to resize images in place?

Are there any Android libraries to resize images and save it in place? I'm using Jetpack Compose and Kotlin in my project. My app has a feature for taking photos and choosing an image from the gallery. And I need to resize the captured or selected image and create their thumbnails. I looked into Picasso, and Glide, etc. But, it seems like they only resize the image in memory for display.
HI You can use Glide for resize,
but again you can use it to save as image too
for eg use this to store in bitmap,
Glide.with(getApplicationContext())
.load("https://i.stack.imgur.com/quwoe.jpg")
.asBitmap()
.into(new SimpleTarget<Bitmap>() {
#Override
public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {
saveImage(resource);
}
});
//code to save the image
private void saveImage(Bitmap resource) {
String savedImagePath = null;
String imageFileName = "image" + ".jpg";
final File storageDir = new File(Environment.getExternalStorageDirectory().getAbsolutePath() +
"/Pics");
boolean success = true;
if(!storageDir.exists()){
success = storageDir.mkdirs();
}
if(success){
File imageFile = new File(storageDir, imageFileName);
savedImagePath = imageFile.getAbsolutePath();
try {
OutputStream fOut = new FileOutputStream(imageFile);
resource.compress(Bitmap.CompressFormat.JPEG, 100, fOut);
fOut.close();
} catch (Exception e) {
e.printStackTrace();
}
// Add the image to the system gallery
galleryAddPic(savedImagePath);
Toast.makeText(this, "IMAGE SAVED", Toast.LENGTH_LONG).show();
}
}
// Add the image to the system gallery
private void galleryAddPic(String imagePath) {
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
File f = new File(imagePath);
Uri contentUri = Uri.fromFile(f);
mediaScanIntent.setData(contentUri);
sendBroadcast(mediaScanIntent);
}
Resize with glide
save with Glide

Android File Not Found Exception, though the image is saved

I am making an app which utilizes the camera, and has the ability to take a picture to use a simple image recognition API on it. I can use the gallery just fine to upload images, but straight from the camera is giving me massive issues. I have basically just copied the android dev documentation for most of the image creation, though may have needed to change some items here and there.
Here is the total code:
private File createImageFile() throws IOException {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "JPEG_" + "Image_for_Stack" + "_";
File storageDir = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DCIM), "Camera");
File image = File.createTempFile(
imageFileName, /* prefix */
".jpg", /* suffix */
storageDir /* directory */
);
// Save a file: path for use with ACTION_VIEW intents
currentPhotoPath = "file: " + image.getAbsolutePath();
return image;
}
private void dispatchTakePictureIntent() {
try {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Ensure that there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(getActivity().getPackageManager()) != null) {
// Create the File where the photo should go
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException ex) {
Log.v(TAG, "IO Exception " + ex);
}
// Continue only if the File was successfully created
if (photoFile != null) {
photoURI = FileProvider.getUriForFile(getContextOfApplication(),
BuildConfig.APPLICATION_ID + ".provider",
photoFile);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
startActivityForResult(takePictureIntent, IMAGE_CAPTURE);
}
}
} catch (Exception e) {
Log.v(TAG, "Exception in dispatch " + e);
}
}
private void galleryAddPic() {
try {
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
File f = new File(currentPhotoPath);
Uri contentUri = Uri.fromFile(f);
mediaScanIntent.setData(contentUri);
getContextOfApplication().sendBroadcast(mediaScanIntent);
} catch (Exception e) {
Log.v(TAG, "Exception " + e);
}
}
And in a separate class, this is called:
public static byte[] getByteArrayFromIntentData(#NonNull Context context, #NonNull Intent data) {
InputStream inStream = null;
Bitmap bitmap = null;
try {
inStream = context.getContentResolver().openInputStream(data.getData());
Log.v(TAG, "Instream works");
bitmap = BitmapFactory.decodeStream(inStream);
final ByteArrayOutputStream outStream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outStream);
return outStream.toByteArray();
} catch (FileNotFoundException e) {
Log.v("FileOP Debug", "Exception " + e);
return null;
} finally {
if (inStream != null) {
try {
inStream.close();
} catch (IOException ignored) {
}
}
if (bitmap != null) {
bitmap.recycle();
}
}
}
Now, the image is created without issue. I can go to the emulator, look through the photo's app, and get:
.
However, I get this error when the code gets to giving inStream a value:
java.io.FileNotFoundException: /file:
/storage/emulated/0/DCIM/Camera/JPEG_Image_for_Stack_3248071614992872091.jpg
(No such file or directory) .
I don't exactly understand how this could be. The item clearly exists, and is saved on the phone. The app does request and is given the permission to write to external storage, and I have checked in the emulator permissions that it is given. Write also comes with read, so that shouldn't be an issue as far as I'm aware either.
Edit
To show where this code is being called from.
else if (requestCode == IMAGE_CAPTURE) {
galleryAddPic();
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
File f = new File(currentPhotoPath);
Uri contentUri = Uri.fromFile(f);
mediaScanIntent.setData(contentUri);
final ProgressDialog progress = new ProgressDialog(getContextOfApplication());
progress.setTitle("Loading");
progress.setMessage("Identify your flower..");
progress.setCancelable(false);
progress.show();
if (!CheckNetworkConnection.isInternetAvailable(getContextOfApplication())) {
progress.dismiss();
Toast.makeText(getContextOfApplication(),
"Internet connection unavailable.",
Toast.LENGTH_SHORT).show();
return;
}
client = ClarifaiClientGenerator.generate(API_KEY);
final byte[] imageBytes = FileOp.getByteArrayFromIntentData(getContextOfApplication(), mediaScanIntent);
As of right now, imageBytes will be null as the the FileNotFound exception is thrown on that method call.
You can try this code...
public class Images extends Activity
{
private Uri[] mUrls;
String[] mFiles=null;
public void onCreate(Bundle icicle)
{
super.onCreate(icicle);
setContentView(R.layout.images);
File images = Environment.getDataDirectory();
File[] imagelist = images.listFiles(new FilenameFilter(){
#override
public boolean accept(File dir, String name)
{
return ((name.endsWith(".jpg"))||(name.endsWith(".png"))
}
});
mFiles = new String[imagelist.length];
for(int i= 0 ; i< imagelist.length; i++)
{
mFiles[i] = imagelist[i].getAbsolutePath();
}
mUrls = new Uri[mFiles.length];
for(int i=0; i < mFiles.length; i++)
{
mUrls[i] = Uri.parse(mFiles[i]);
}
Gallery g = (Gallery) findViewById(R.id.gallery);
g.setAdapter(new ImageAdapter(this));
g.setFadingEdgeLength(40);
}
public class ImageAdapter extends BaseAdapter{
int mGalleryItemBackground;
public ImageAdapter(Context c) {
mContext = c;
}
public int getCount(){
return mUrls.length;
}
public Object getItem(int position){
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent){
ImageView i = new ImageView(mContext);
i.setImageURI(mUrls[position]);
i.setScaleType(ImageView.ScaleType.FIT_XY);
i.setLayoutParams(new Gallery.LayoutParams(260, 210));
return i;
}
private Context mContext;
}
}

How to cache images to specific folder just like whatsapp

i am building a chat application using firebase. I am using Glide to display images
Glide.with(getApplicationContext())
.load(imageUrl)
.crossFade()
.fitCenter()
.placeholder(R.drawable.loading)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(imageView);
I want to save the images to a specific folder in Internal Storage just like whatsapp does and load images from there after it has been saved.Images are uploaded on Firebase Storage and its URL is saved in Firebase Database and i load them in a imageView with the url using Glide
private static final String IMAGE_DIRECTORY = "/yourfoldername/images";
//this method return your folder image path
public String saveImage(Bitmap myBitmap) {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
myBitmap.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
File wallpaperDirectory = new File(
Environment.getExternalStorageDirectory() + IMAGE_DIRECTORY);
// have the object build the directory structure, if needed.
if (!wallpaperDirectory.exists()) {
wallpaperDirectory.mkdirs();
}
try {
File f = new File(wallpaperDirectory, Calendar.getInstance().getTimeInMillis() + ".jpg");
f.createNewFile();
FileOutputStream fo = new FileOutputStream(f);
fo.write(bytes.toByteArray());
MediaScannerConnection.scanFile(this,
new String[]{f.getPath()},
new String[]{"image/jpeg"}, null);
fo.close();
Log.d("TAG", "File Saved::--->" + f.getAbsolutePath());
return f.getAbsolutePath();
} catch (IOException e1) {
e1.printStackTrace();
}
return "";
}
// glide load image
Glide.with(this)
.load(imageUrl)
.asBitmap()
.into(new SimpleTarget<Bitmap>() {
#Override
public void onResourceReady(Bitmap resource, GlideAnimation glideAnimation) {
String imagepath = saveImage(resource);
// Parse the gallery image url to uri
Uri savedImageURI = Uri.parse(imagepath);
// Display the saved image to ImageView
iv_saved.setImageURI(savedImageURI);
}
});

ImageView from Uri only appearing after rotating the screen

I've an app that displays a picture to its users. It sounds really simple, but I've been at it for days now trying to troubleshoot the exact problem. So what'll happen is that user will:
Click an image;
The image will be saved to the user's External Storage;
The image's Uri will be taken;
An ImageView will open the image with this Uri;
No image appeared, throws java.io.FileNotFoundException: /storage/emulated/....jpg: open failed: ENOENT (No such file or directory).
So I thought I didn't really pass the correct Uri and tried to troubleshoot from there. Then I accidentally rotated the screen and hey - my image is there! The the log file showed this when I rotated it a few times:
android.graphics.Bitmap#49361a20
android.graphics.Bitmap#495c42c8
android.graphics.Bitmap#496ac1e0
android.graphics.Bitmap#495b2b28
Is this displaying the memory location? Is it supposed to be different even after screen rotation?
With this information, is there anywhere else I should look into to solve this problem? I could rule out that the Uri is invalid, as it is showing the correct image after rotating the screen.
This is the code (of a utility class) involved to download the image clicked;
This method seems to work well and the image is saved to the correct directory.
public void downloadFile(String url) {
File folder = new File(Environment.getExternalStorageDirectory() + directory);
String fileName = url.substring(url.lastIndexOf("/") + 1);
String filePath = folder.getPath() + "/" + fileName;
File file = new File(filePath);
fileUri = Uri.fromFile(file);
if (!folder.exists()) {
Log.i(TAG, "Worka folder is not found, creating one now");
folder.mkdir();
} else {
Log.i(TAG, "Worka folder is found");
if (file.exists()) {
Log.i(TAG, "Found a file with the same name, deleting/replacing it now");
file.delete();
}
}
DownloadManager downloadManager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
Uri downloadUri = Uri.parse(url);
DownloadManager.Request request = new DownloadManager.Request(downloadUri);
request.setAllowedNetworkTypes(
DownloadManager.Request.NETWORK_MOBILE | DownloadManager.Request.NETWORK_WIFI)
//.setAllowedOverRoaming(false).setTitle("Roaming is not available")
.setDestinationInExternalPublicDir(directory, fileName);
downloadManager.enqueue(request);
Log.i(TAG, "downloadFile() is successful, " + fileName + " is saved to Worka directory");
}
public Uri getFilePath() {
return fileUri;
}
To make sure it gets passed from an activity to another activity;
FileDownload fileDownload = new FileDownload(getApplicationContext());
fileDownload.downloadFile(conversation.getMessage());
Uri fileUri = fileDownload.getFilePath();
if (fileUri != null) {
Log.i(TAG, "fileUri: " + fileUri.toString());
Intent intent = new Intent(BulletinPostActivity.this, ImageViewingActivity.class);
intent.putExtra("imageUri", fileUri.toString());
startActivity(intent);
Finally, getting Bitmap from the passed Uri:
I then tried using AsyncTask here, to make sure the bitmap gets loaded properly... but I'm unsure what to code to accomplish this.
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
String imagePath = getIntent().getStringExtra("imageUri");
imageUri = Uri.parse(imagePath);
touchImageView = (TouchImageView) findViewById(R.id.image_viewing_image_view);
if (imageUri != null) {
new loadBitmap(imageUri).execute();
}
}
public class loadBitmap extends AsyncTask<Void, Integer, Bitmap> {
Uri uri;
public loadBitmap(Uri uri) {
this.uri = uri;
}
#Override
protected Bitmap doInBackground(Void... params) {
getBitmap();
return bitmap;
}
public Bitmap getBitmap() {
try {
Log.i(TAG, "Attempting to get the bitmap from imageUri");
bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), imageUri);
Log.i(TAG, "Successfully gotten the bitmap from imageUri: " + bitmap);
} catch (IOException e) {
e.printStackTrace();
}
return bitmap;
}
#Override
protected void onPostExecute(Bitmap bitmap) {
if (bitmap == null) {
getBitmap();
} else {
touchImageView.setImageBitmap(bitmap);
}
}
}

How to take a screenshot of a current Activity and then share it?

I need to take a screenshot of Activity (without the title bar, and the user should NOT see that a screenshot has actually been taken) and then share it via an action menu button "share". I have already tried some solutions, but they didn't work for me. Any ideas?
This is how I captured the screen and shared it.
First, get root view from current activity:
View rootView = getWindow().getDecorView().findViewById(android.R.id.content);
Second, capture the root view:
public static Bitmap getScreenShot(View view) {
View screenView = view.getRootView();
screenView.setDrawingCacheEnabled(true);
Bitmap bitmap = Bitmap.createBitmap(screenView.getDrawingCache());
screenView.setDrawingCacheEnabled(false);
return bitmap;
}
Third, store the Bitmap into the SDCard:
public static void store(Bitmap bm, String fileName){
final static 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();
}
}
At last, share the screenshot of current Activity:
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(context, "No App Available", Toast.LENGTH_SHORT).show();
}
}
I hope you will be inspired by my code.
UPDATE:
Add below permissions into your AndroidManifest.xml:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Because it creates and accesses files in external storage.
UPDATE:
Starting from Android 7.0 Nougat sharing file links are forbiden. To deal with this you have to implement FileProvider and share "content://" uri not "file://" uri.
Here is a good description how to do it.
create share button with click on listener
share = (Button)findViewById(R.id.share);
share.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Bitmap bitmap = takeScreenshot();
saveBitmap(bitmap);
shareIt();
}
});
Add two methods
public Bitmap takeScreenshot() {
View rootView = findViewById(android.R.id.content).getRootView();
rootView.setDrawingCacheEnabled(true);
return rootView.getDrawingCache();
}
public void saveBitmap(Bitmap bitmap) {
imagePath = new File(Environment.getExternalStorageDirectory() + "/screenshot.png");
FileOutputStream fos;
try {
fos = new FileOutputStream(imagePath);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
fos.flush();
fos.close();
} catch (FileNotFoundException e) {
Log.e("GREC", e.getMessage(), e);
} catch (IOException e) {
Log.e("GREC", e.getMessage(), e);
}
}
Share screen shot. sharing implementation here
private void shareIt() {
Uri uri = Uri.fromFile(imagePath);
Intent sharingIntent = new Intent(android.content.Intent.ACTION_SEND);
sharingIntent.setType("image/*");
String shareBody = "In Tweecher, My highest score with screen shot";
sharingIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, "My Tweecher score");
sharingIntent.putExtra(android.content.Intent.EXTRA_TEXT, shareBody);
sharingIntent.putExtra(Intent.EXTRA_STREAM, uri);
startActivity(Intent.createChooser(sharingIntent, "Share via"));
}
This Method Doesn't Need to Store and Retrieve Screenshot for Sharing Again.
On just Method Call you will Able to Share Screenshot.
private Bitmap screenShot(View view) {
Bitmap bitmap = Bitmap.createBitmap(view.getWidth(),view.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
view.draw(canvas);
return bitmap;
}
private void share(Bitmap bitmap){
String pathofBmp=
MediaStore.Images.Media.insertImage(ctx.getContentResolver(),
bitmap,"title", null);
Uri uri = Uri.parse(pathofBmp);
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("image/*");
shareIntent.putExtra(Intent.EXTRA_SUBJECT, "Star App");
shareIntent.putExtra(Intent.EXTRA_TEXT, "");
shareIntent.putExtra(Intent.EXTRA_STREAM, uri);
ctx.startActivity(Intent.createChooser(shareIntent, "hello hello"));
}
Called this Method like this
share(screenShot(view));
By using this Direct Share Screenshot without having READ & WRITE Permission
You can the below code to get the bitmap for the view you are seeing on screen You can specify which view to create bitmap.
public static Bitmap getScreenShot(View view) {
View screenView = view.getRootView();
screenView.setDrawingCacheEnabled(true);
Bitmap bitmap = Bitmap.createBitmap(screenView.getDrawingCache());
screenView.setDrawingCacheEnabled(false);
return bitmap;
}
I couldn't get Silent Knight's answer to work to work until I added
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
to my AndroidManifest.xml.
You can take screenshot of any portion of your view.You just need the reference of the layout of which you want the screenshot. for example in your case you want the screen shot of your activity. let assume that your activity root layout is Linear Layout .
// find the reference of the layout which screenshot is required
LinearLayout LL = (LinearLayout) findViewById(R.id.yourlayout);
Bitmap screenshot = getscreenshot(LL);
//use this method to get the bitmap
private Bitmap getscreenshot(View view) {
View v = view;
v.setDrawingCacheEnabled(true);
Bitmap bitmap = Bitmap.createBitmap(v.getDrawingCache());
return bitmap;
}
for taking screenshot
public Bitmap takeScreenshot() {
View rootView = findViewById(android.R.id.content).getRootView();
rootView.setDrawingCacheEnabled(true);
return rootView.getDrawingCache();
}
for saving screenshot
private void saveBitmap(Bitmap bitmap) {
imagePath = new File(Environment.getExternalStorageDirectory() + "/scrnshot.png"); ////File imagePath
FileOutputStream fos;
try {
fos = new FileOutputStream(imagePath);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
fos.flush();
fos.close();
} catch (FileNotFoundException e) {
Log.e("GREC", e.getMessage(), e);
} catch (IOException e) {
Log.e("GREC", e.getMessage(), e);
}
}
and for sharing
private void shareIt() {
Uri uri = Uri.fromFile(imagePath);
Intent sharingIntent = new Intent(android.content.Intent.ACTION_SEND);
sharingIntent.setType("image/*");
String shareBody = "My highest score with screen shot";
sharingIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, "My Catch score");
sharingIntent.putExtra(android.content.Intent.EXTRA_TEXT, shareBody);
sharingIntent.putExtra(Intent.EXTRA_STREAM, uri);
startActivity(Intent.createChooser(sharingIntent, "Share via"));
}
and simply in the onclick you can call these methods
shareScoreCatch.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Bitmap bitmap = takeScreenshot();
saveBitmap(bitmap);
shareIt();
}
});
as of 2021 here is complete answer you would only copy past this code and it should work fine with you, also it uses all the new API including permission launchers, and android q way of saving images
I will be adding one more functionality which is saving inside folder inside Picture folder like this
/Pictures/MyAppName/photos.png
also this code is supporting android < 10 as well as the newer one.
i am making a screen shoot and saving it to desk to get uri of the image, to be able to share it later.
first, permission launcher is required on android < 10
val requestStoragePermissionLauncher =
registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
) { permissions ->
var saveImageFlag = true
permissions.entries.forEach {
saveImageFlag = it.value
}
if (saveImageFlag) {
shareScreenShootResult()
} else {
showMessage(getString(R.string.cant_share_ScreenShoot))
}
}
val permissionListener: () -> Boolean = {
if (ContextCompat.checkSelfPermission(
requireContext(),
Manifest.permission.READ_EXTERNAL_STORAGE
) == PackageManager.PERMISSION_GRANTED &&
ContextCompat.checkSelfPermission(
requireContext(),
Manifest.permission.WRITE_EXTERNAL_STORAGE
) == PackageManager.PERMISSION_GRANTED
) {
true
} else {
requestStoragePermissionLauncher.launch(
arrayOf(
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
)
)
false
}
}
then the next method gives the image name and set the directory and then share the image
private fun shareScreenShootResult() {
val dateFormatter by lazy {
SimpleDateFormat(
"yyyy.MM.dd 'at' HH:mm:ss z", Locale.getDefault()
)
}
val filename = "${getString(R.string.my_ScreenShoot)}${dateFormatter.format(Date())}.png"
val ScreenShootFolderPath = File.separator + requireContext().getAppName()
val uri = binding.rootLayout.makeScreenShot()
.saveScreenShot(requireContext(), filename, ScreenShootFolderPath, permissionListener)
?: return
dispatchShareImageIntent(uri)
}
private fun dispatchShareImageIntent(screenShotUri: Uri) {
val intent = Intent(Intent.ACTION_SEND)
intent.type = "image/png"
intent.putExtra(Intent.EXTRA_STREAM, screenShotUri)
startActivity(Intent.createChooser(intent, "Share"))
}
getAppName is an extention funtion, you can add it anywhere in your project then call it on context, do not forget to import it.
fun Context.getAppName(): String {
var appName: String = ""
val applicationInfo = applicationInfo
val stringId = applicationInfo.labelRes
appName = if (stringId == 0) {
applicationInfo.nonLocalizedLabel.toString()
} else {
getString(stringId)
}
return appName
}
this method makeScreenShot is extension function on the View
you better add all extension functions in different file.
fun View.makeScreenShot(): Bitmap {
setBackgroundColor(Color.WHITE)
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmap)
draw(canvas)
return bitmap
}
it returns bitmap on which i am calling saveScreenShot which is another extenion function
fun Bitmap.saveScreenShot(
requireContext: Context,
filename: String,
ScreenShootFolderPath: String,
permissionListener: () -> Boolean,
): Uri? {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
saveImageInQ(this, filename, ScreenShootFolderPath, requireContext.contentResolver)
else
legacySave(this, filename, ScreenShootFolderPath, permissionListener)
}
private fun saveImageInQ(
bitmap: Bitmap,
filename: String,
parentFileName: String,
contentResolver: ContentResolver
): Uri? {
val fos: OutputStream?
val uri: Uri?
val contentValues = ContentValues()
contentValues.apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, filename)
put(MediaStore.Files.FileColumns.MIME_TYPE, "image/png")
put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + parentFileName)
put(MediaStore.MediaColumns.IS_PENDING, 1)
}
uri =
contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
uri?.let { contentResolver.openOutputStream(it) }.also { fos = it }
fos?.use { bitmap.compress(Bitmap.CompressFormat.PNG, 100, it) }
fos?.flush()
fos?.close()
contentValues.clear()
contentValues.put(MediaStore.MediaColumns.IS_PENDING, 0)
uri?.let {
contentResolver.update(it, contentValues, null, null)
}
return uri
}
private fun legacySave(
bitmap: Bitmap,
filename: String,
parentFileName: String,
permissionListener: () -> Boolean,
): Uri? {
val fos: OutputStream?
if (!permissionListener()) {
return null
}
val path =
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).toString() +
parentFileName + File.separator + filename
val imageFile = File(path)
if (imageFile.parentFile?.exists() == false) {
imageFile.parentFile?.mkdir()
}
imageFile.createNewFile()
fos = FileOutputStream(imageFile)
val uri: Uri = Uri.fromFile(imageFile)
fos.use { bitmap.compress(Bitmap.CompressFormat.PNG, 100, it) }
fos.flush()
fos.close()
return uri
}
For all the Xamarin Users:
Xamarin.Android Code:
Create an external Class (I have an interface for each platform, and I implemented those 3 below functions from android platform):
public static Bitmap TakeScreenShot(View view)
{
View screenView = view.RootView;
screenView.DrawingCacheEnabled = true;
Bitmap bitmap = Bitmap.CreateBitmap(screenView.DrawingCache);
screenView.DrawingCacheEnabled = false;
return bitmap;
}
public static Java.IO.File StoreScreenShot(Bitmap picture)
{
var folder = Android.OS.Environment.ExternalStorageDirectory + Java.IO.File.Separator + "MyFolderName";
var extFileName = Android.OS.Environment.ExternalStorageDirectory +
Java.IO.File.Separator +
Guid.NewGuid() + ".jpeg";
try
{
if (!Directory.Exists(folder))
Directory.CreateDirectory(folder);
Java.IO.File file = new Java.IO.File(extFileName);
using (var fs = new FileStream(extFileName, FileMode.OpenOrCreate))
{
try
{
picture.Compress(Bitmap.CompressFormat.Jpeg, 100, fs);
}
finally
{
fs.Flush();
fs.Close();
}
return file;
}
}
catch (UnauthorizedAccessException ex)
{
Log.Error(LogPriority.Error.ToString(), "-------------------" + ex.Message.ToString());
return null;
}
catch (Exception ex)
{
Log.Error(LogPriority.Error.ToString(), "-------------------" + ex.Message.ToString());
return null;
}
}
public static void ShareImage(Java.IO.File file, Activity activity, string appToSend, string subject, string message)
{
//Push to Whatsapp to send
Android.Net.Uri uri = Android.Net.Uri.FromFile(file);
Intent i = new Intent(Intent.ActionSendMultiple);
i.SetPackage(appToSend); // so that only Whatsapp reacts and not the chooser
i.AddFlags(ActivityFlags.GrantReadUriPermission);
i.PutExtra(Intent.ExtraSubject, subject);
i.PutExtra(Intent.ExtraText, message);
i.PutExtra(Intent.ExtraStream, uri);
i.SetType("image/*");
try
{
activity.StartActivity(Intent.CreateChooser(i, "Share Screenshot"));
}
catch (ActivityNotFoundException ex)
{
Toast.MakeText(activity.ApplicationContext, "No App Available", ToastLength.Long).Show();
}
}`
Now, from your Activity, you run the above code like this:
RunOnUiThread(() =>
{
//take silent screenshot
View rootView = Window.DecorView.FindViewById(Resource.Id.ActivityLayout);
Bitmap tmpPic = ShareHandler.TakeScreenShot(this.CurrentFocus); //TakeScreenShot(this);
Java.IO.File imageSaved = ShareHandler.StoreScreenShot(tmpPic);
if (imageSaved != null)
{
ShareHandler.ShareImage(imageSaved, this, "com.whatsapp", "", "ScreenShot Taken from: " + "Somewhere");
}
});
Hope it will be of use to anyone.
You can try the below code to capture the screenshot of current screen and share that image without any LIBRARY & PERMISSION. I have tested this its working perfectly.
Just copy paste this.
In MainAtivity.java
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button fullPageScreenshot, customPageScreenshot;
private LinearLayout rootContent;
private ImageView imageView;
private TextView hiddenText;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder(); StrictMode.setVmPolicy(builder.build());
findViews();
implementClickEvents();
}
/* Find all views Ids */
private void findViews() {
fullPageScreenshot = (Button) findViewById(R.id.full_page_screenshot);
customPageScreenshot = (Button) findViewById(R.id.custom_page_screenshot);
rootContent = (LinearLayout) findViewById(R.id.root_content);
imageView = (ImageView) findViewById(R.id.image_view);
hiddenText = (TextView) findViewById(R.id.hidden_text);
}
/* Implement Click events over Buttons */
private void implementClickEvents() {
fullPageScreenshot.setOnClickListener(this);
customPageScreenshot.setOnClickListener(this);
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.full_page_screenshot:
takeScreenshot(ScreenshotType.FULL);
break;
case R.id.custom_page_screenshot:
takeScreenshot(ScreenshotType.CUSTOM);
break;
}
}
/* Method which will take screenshot on Basis of Screenshot Type ENUM */
private void takeScreenshot(ScreenshotType screenshotType) {
Bitmap b = null;
switch (screenshotType) {
case FULL:
//If Screenshot type is FULL take full page screenshot i.e our root content.
b = ScreenshotUtils.getScreenShot(rootContent);
break;
case CUSTOM:
//If Screenshot type is CUSTOM
fullPageScreenshot.setVisibility(View.INVISIBLE);//set the visibility to INVISIBLE of first button
hiddenText.setVisibility(View.VISIBLE);//set the visibility to VISIBLE of hidden text
b = ScreenshotUtils.getScreenShot(rootContent);
//After taking screenshot reset the button and view again
fullPageScreenshot.setVisibility(View.VISIBLE);//set the visibility to VISIBLE of first button again
hiddenText.setVisibility(View.INVISIBLE);//set the visibility to INVISIBLE of hidden text
//NOTE: You need to use visibility INVISIBLE instead of GONE to remove the view from frame else it wont consider the view in frame and you will not get screenshot as you required.
break;
}
//If bitmap is not null
if (b != null) {
showScreenShotImage(b);//show bitmap over imageview
File saveFile = ScreenshotUtils.getMainDirectoryName(this);//get the path to save screenshot
File file = ScreenshotUtils.store(b, "screenshot" + screenshotType + ".jpg", saveFile);//save the screenshot to selected path
shareScreenshot(file);//finally share screenshot
} else
//If bitmap is null show toast message
Toast.makeText(this, R.string.screenshot_take_failed, Toast.LENGTH_SHORT).show();
}
/* Show screenshot Bitmap */
private void showScreenShotImage(Bitmap b) {
imageView.setImageBitmap(b);
}
/* Share Screenshot */
private void shareScreenshot(File file) {
Uri uri = Uri.fromFile(file);//Convert file path into Uri for sharing
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, getString(R.string.sharing_text));
intent.putExtra(Intent.EXTRA_STREAM, uri);//pass uri here
startActivity(Intent.createChooser(intent, getString(R.string.share_title)));
}
}
ScreenshotType.java
public enum ScreenshotType {
FULL, CUSTOM;
}
ScreenshotUtils.java
public class ScreenshotUtils {
/* Method which will return Bitmap after taking screenshot. We have to pass the view which we want to take screenshot. */
public static Bitmap getScreenShot(View view) {
View screenView = view.getRootView();
screenView.setDrawingCacheEnabled(true);
Bitmap bitmap = Bitmap.createBitmap(screenView.getDrawingCache());
screenView.setDrawingCacheEnabled(false);
return bitmap;
}
/* Create Directory where screenshot will save for sharing screenshot */
public static File getMainDirectoryName(Context context) {
//Here we will use getExternalFilesDir and inside that we will make our Demo folder
//benefit of getExternalFilesDir is that whenever the app uninstalls the images will get deleted automatically.
File mainDir = new File(
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "Demo");
//If File is not present create directory
if (!mainDir.exists()) {
if (mainDir.mkdir())
Log.e("Create Directory", "Main Directory Created : " + mainDir);
}
return mainDir;
}
/* Store taken screenshot into above created path */
public static File store(Bitmap bm, String fileName, File saveFilePath) {
File dir = new File(saveFilePath.getAbsolutePath());
if (!dir.exists())
dir.mkdirs();
File file = new File(saveFilePath.getAbsolutePath(), fileName);
try {
FileOutputStream fOut = new FileOutputStream(file);
bm.compress(Bitmap.CompressFormat.JPEG, 85, fOut);
fOut.flush();
fOut.close();
} catch (Exception e) {
e.printStackTrace();
}
return file;
}
}
4.activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/root_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="10dp"
tools:context="com.takescreenshot_demo.MainActivity">
<!-- Button which will take full page screenshot -->
<Button
android:id="#+id/full_page_screenshot"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/full_page_screenshot"
android:textColor="#android:color/white"
android:textSize="14sp" />
<!-- Hidden Text which will shown when taking screenshot from below Button -->
<TextView
android:id="#+id/hidden_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="#string/hidden_text"
android:textColor="#android:color/white"
android:textSize="14sp"
android:visibility="invisible" />
<!-- Button which will take screenshot after hiding some view and showing some view -->
<Button
android:id="#+id/custom_page_screenshot"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/custom_page_screenshot"
android:textColor="#android:color/white"
android:textSize="14sp" />
<!-- ImageView to show taken Screenshot -->
<ImageView
android:id="#+id/image_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitCenter"
android:src="#mipmap/ic_launcher" />
</LinearLayout>
A consolidated copy and paste code:
private void takeScreenshot() {
Date now = new Date();
android.text.format.DateFormat.format("yyyy-MM-dd_hh:mm:ss", now);
try {
// image naming and path to include sd card appending name you choose for file
String mPath = Environment.getExternalStorageDirectory().toString() + "/" + now + ".jpg";
String screenshotPath = mPath;
// create bitmap screen capture
View v1 = getWindow().getDecorView().getRootView();
v1.setDrawingCacheEnabled(true);
Bitmap bitmap = Bitmap.createBitmap(v1.getDrawingCache());
v1.setDrawingCacheEnabled(false);
File imageFile = new File(mPath);
FileOutputStream outputStream = new FileOutputStream(imageFile);
int quality = 100;
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, outputStream);
outputStream.flush();
outputStream.close();
// openScreenshot(imageFile);
} catch (Throwable e) {
// Several error may come out with file handling or DOM
e.printStackTrace();
}
}
//Function to share Screenshot
private void shareScreenshots(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();
}
}
//Function to open screenshot
private void openScreenshot(File imageFile) {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
Uri uri = Uri.fromFile(imageFile);
intent.setDataAndType(uri, "image/*");
startActivity(intent);
}
This is how I captured the screen and shared it. Take a look if you are interested.
public Bitmap takeScreenshot() {
View rootView = findViewById(android.R.id.content).getRootView();
rootView.setDrawingCacheEnabled(true);
return rootView.getDrawingCache();
}
And the method that saves the bitmap image to external storage:
public void saveBitmap(Bitmap bitmap) {
File imagePath = new File(Environment.getExternalStorageDirectory() + "/screenshot.png");
FileOutputStream fos;
try {
fos = new FileOutputStream(imagePath);
bitmap.compress(CompressFormat.JPEG, 100, fos);
fos.flush();
fos.close();
} catch (FileNotFoundException e) {
Log.e("GREC", e.getMessage(), e);
} catch (IOException e) {
Log.e("GREC", e.getMessage(), e);
}}
see more in : https://www.youtube.com/watch?v=LRCRNvzamwY&feature=youtu.be
If someone is getting an java.io.FileNotFoundException, following SilengKnight's solution, the problem is probably that writing in storage was not permited (Although we added the user-permission in the manifest). I solved it by adding this in the store function before making a new FileOutputStream.
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
//Permission was denied
//Request for permission
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
MY_PERMISSIONS_CODE_EXTERNAL_STORAGE);
}
Create helper class for creating and sharing screen shot
public class share {
private final Context c;
public share(Context c) {
this.c = c;
}
public void shareInt(Bitmap bitmap, String msg, String name) {
Uri uri = getmageToShare(bitmap, name);
Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_STREAM, uri);
intent.putExtra(Intent.EXTRA_TEXT, msg);
intent.setType("*/*");
c.startActivity(Intent.createChooser(intent, "Share Via").addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
}
// Retrieving the url to share
private Uri getmageToShare(Bitmap bitmap, String name) {
File imagefolder = new File(c.getCacheDir(), "images");
Uri uri = null;
try {
imagefolder.mkdirs();
File file = new File(imagefolder, name+".png");
FileOutputStream outputStream = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.PNG, 70, outputStream);
outputStream.flush();
outputStream.close();
uri = FileProvider.getUriForFile(c, "com.yourapp.fileprovider", file);
} catch (Exception e) {
Toast.makeText(c, "" + e.getMessage(), Toast.LENGTH_LONG).show();
}
return uri;
}
}
Now call this helper class from any activity you want to take screen shot and share
CardView mainView = findViewById(R.id.mainView);
new share(c).shareInt(new getBitmap().screenShot(mainView), "msg", "randomstring");
here mainView is that view which you want to take snap shot, jzt pass view reference.
No need of run time permission coz we are using cache dir
This is what I use to take a screenshot. The solutions described above work fine for API < 24, but for API 24 and greater another solution is needed. I've tested this method on API 15, 24, & 27.
I placed the following methods in MainActivity.java:
public class MainActivity {
...
String[] permissions = new String[]{"android.permission.READ_EXTERNAL_STORAGE", "android.permission.WRITE_EXTERNAL_STORAGE"};
View sshotView;
...
private boolean checkPermission() {
List arrayList = new ArrayList();
for (String str : this.permissions) {
if (ContextCompat.checkSelfPermission(this, str) != 0) {
arrayList.add(str);
}
}
if (arrayList.isEmpty()) {
return true;
}
ActivityCompat.requestPermissions(this, (String[]) arrayList.toArray(new String[arrayList.size()]), 100);
return false;
}
protected void onCreate(Bundle savedInstanceState) {
...
this.sshotView = getWindow().getDecorView().findViewById(R.id.parent);
...
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch (id) {
case R.id.action_shareScreenshot:
boolean checkPermission = checkPermission();
Bitmap screenShot = getScreenShot(this.sshotView);
if (!checkPermission) {
return true;
}
shareScreenshot(store(screenShot));
return true;
case R.id.option2:
...
return true;
}
return false;
}
private void shareScreenshot(File file) {
Parcelable fromFile = FileProvider.getUriForFile(MainActivity.this,
BuildConfig.APPLICATION_ID + ".com.redtiger.applehands.provider", file);
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setAction("android.intent.action.SEND");
intent.setType("image/*");
intent.putExtra("android.intent.extra.SUBJECT", XmlPullParser.NO_NAMESPACE);
intent.putExtra("android.intent.extra.TEXT", XmlPullParser.NO_NAMESPACE);
intent.putExtra("android.intent.extra.STREAM", fromFile);
try {
startActivity(Intent.createChooser(intent, "Share Screenshot"));
} catch (ActivityNotFoundException e) {
Toast.makeText(getApplicationContext(), "No Communication Platform Available", Toast.LENGTH_SHORT).show();
}
}
public static Bitmap getScreenShot(View view) {
View rootView = view.getRootView();
rootView.setDrawingCacheEnabled(true);
Bitmap createBitmap = Bitmap.createBitmap(rootView.getDrawingCache());
rootView.setDrawingCacheEnabled(false);
return createBitmap;
public File store(Bitmap bitmap) {
String str = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pictures/Screenshots";
File file = new File(str);
if (!file.exists()) {
file.mkdirs();
}
file = new File(str + "/sshot.png");
try {
OutputStream fileOutputStream = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.PNG, 80, fileOutputStream);
fileOutputStream.flush();
fileOutputStream.close();
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(), "External Storage Permission Is Required", Toast.LENGTH_LONG).show();
}
return file;
}
}
I placed the following permissions and provider in my AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.redtiger.applehands">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<application
...
<provider
android:name="com.redtiger.applehands.util.GenericFileProvider"
android:authorities="${applicationId}.com.redtiger.applehands.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_paths"/>
</provider>
...
</application>
</manifest>
I created a file called provider_paths.xml (please see below) to direct the FileProvider where to save the screenshot. The file contains a simple tag that points to the root of the external directory.
The File was placed in the resource folder res/xml (if you don't have an xml folder here, just create one and place your file there).
provider_paths.xml:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path name="external_files" path="."/>
</paths>

Categories

Resources