So I'm using the twitter api and I want to tweet with an image I use:
TweetUri = Uri.fromFile(saveIT);
TweetComposer.Builder builder = new TweetComposer.Builder(this)
.text("")
.image(TweetUri);
builder.show();
The original image is a bitmap, so what I did (not sure if this is the optimal way) was save in the internal storage:
private File saveToInternalStorage(Bitmap bitmapImage){
ContextWrapper cw = new ContextWrapper(getApplicationContext());
// path to /data/data/yourapp/app_data/imageDir
File directory = cw.getDir("imageDir", Context.MODE_PRIVATE);
// Create imageDir
String timeStamp = new SimpleDateFormat("ddMMyyyy_HHmmss").format(new Date());
String mImageName="MI_"+ timeStamp +".jpg";
File mypath=new File(directory,mImageName);
FileOutputStream fos = null;
try {
fos = new FileOutputStream(mypath);
// Use the compress method on the BitMap object to write image to the OutputStream
bitmapImage.compress(Bitmap.CompressFormat.PNG, 100, fos);
} catch (Exception e) {
e.printStackTrace();
} finally {
try
{
fos.close();
}
catch(Exception e)
{
e.printStackTrace();
}
}
return mypath;
}
The file it returns will be the "saveIT" in the TweetUri when it does the fromfile method. Of course this will overload the storage so what I plan to do is wipe the internal storage for the app when it is stopped (no other data is saved in the internal storage other than the temp images I save for the tweet):
#Override
protected void onStop() {
super.onStop();
File MSD = this.getApplicationContext().getFilesDir();
File [] lisFiles = MSD.listFiles();
for(int i=0;i<lisFiles.length;i++)
{
boolean deleted = lisFiles[i].delete();
}
}
None of this works... I can't seem to find any of the images when I save them to verify if the deleting is happening. Also, when the user clicks tweet no image is added to the tweet as well. No idea what I'm doing wrong here... In reality I don't want to save the image in the internal storage but I do because the tweet api uses a URI to tweet and not a bitmap.
I switched it to write to external storage and it worked fine. Also I switched it to delete at onDestroy. This is better because, when I invoke the Twitter API it switches activities so the onstop is invoked which would delete the temp picture too early. It's too early becuase if the user clicks cancel at the twitter api, comes back to my api and then invokes the twitter api again the uri will point to nothing since the picture was already deleted. THATS ALL FOLKS :)
Related
I've a strange (and oddly specific) issue with saving to the gallery on Android.
A bit of background: The app I'm developing needs to be able to save images to the gallery, which has been well discussed on here before. However, there's a specific requirement for this project which is I need to be able to tag it with a specific date/time.
I've tried several methods to get this to work correctly and so far the best I have is a workaround.
What I'm doing at the moment is generating the image, saving it to a file and setting the created date in the EXIF data. I then open the Google Photos app and it shows up in the gallery, showing the correct date and time and is in the correct place within the gallery.
The issue with this however, is that it doesn't automatically show in any other gallery software (for example, the OEM gallery apps that may be shipped with a given device), nor does it show if the Google Photos app is open at the time of saving; It must be closed and relaunched in order for it to show.
Now, if I run a media scan it ignores the EXIF data and the image shows up as the last image created.
Here's the code I'm currently using:
static class InsertImageObj{
public String url;
public long id;
}
public static InsertImageObj insertImage(Bitmap source,
String title, long time) {
String path = createDirectoryAndSaveFile(source, title, time);
String stringUrl = path;
InsertImageObj retVal = new InsertImageObj();
retVal.url = stringUrl;
return retVal;
}
private static String createDirectoryAndSaveFile(Bitmap imageToSave, String fileName, long dateTime) {
File directory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM); //DCIM = Digital Camera Image. This is where camera photos go!
if (!directory.exists()) {
directory.mkdirs();
}
File file = new File(directory, fileName);
if (file.exists()) {
file.delete();
}
try {
FileOutputStream out = new FileOutputStream(file);
imageToSave.compress(Bitmap.CompressFormat.JPEG, 100, out);
out.flush();
out.close();
ExifInterface ei = new ExifInterface(file.getAbsolutePath());
ei.setAttribute(ExifInterface.TAG_DATETIME, convertToExifDateTime(dateTime));
ei.setAttribute(ExifInterface.TAG_DATETIME_ORIGINAL, convertToExifDateTime(dateTime));
ei.setAttribute(ExifInterface.TAG_DATETIME_DIGITIZED, convertToExifDateTime(dateTime));
ei.saveAttributes();
} catch (Exception e) {
e.printStackTrace();
}
return file.getAbsolutePath();
}
private static String convertToExifDateTime(long timestamp) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss", Locale.getDefault());
return sdf.format(new Date(timestamp));
}
I've also tried running setLastModified on the file (which doesn't work, OS permissions or something or other) and using a MediaScannerConnection instance to scan the individual file once it has been saved. The latter, however causes the system to ignore the date/time tags in the Exif data.
I also tried inserting the image into the gallery via a ContentResolver instance and setting the DATE_ADDED and DATE_TAKEN fields, again to no avail.
Is there something really, really obvious I've missed here?
You need to save your image in the media store provider
Use this function
public static void imageToGallery(Context context, String fileName) {
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis());
values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
values.put(MediaStore.MediaColumns.DATA, fileName);
context.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
}
So, after saving your image, call imageToGallery.
Images are only visible in gallery apps if they are added to the android-media-db.
You can ask MediaScannerConnection.scanFile(...) to add the new photo-file to the android-media-db.
On some androiddevices (but not on all) the mediascanner starts automatically.
Also note: you should save the new photo as ".../DCIM/myApp/myPhotoName.jpg" instead of ".../DCIM/myPhotoName.jpg"
Use this function. Its working for me!
private void galleryAddPic() {
File f = new File(imageFilePath);
try {
MediaStore.Images.Media.insertImage(getActivity().getContentResolver(),
f.getAbsolutePath(), f.getName(), null);
getActivity().sendBroadcast(new Intent(
Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(f)));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
I have searched high and low for a way to do this and the best I could find involved saving the screenshot into the SD Card. What I want to do instead is to onclick(), take a screenshot of the current activity and saves it in the internal storage so that the user can view it in their gallery as and when they want.
Any help is greatly appreciated.
It is harder to post a whole code in here. I think you should follow some tutorials.
According to the your requirement what I got is, You need to take a screenshot using an your application and it should be stored in device SD card.
For that you should add proper permission to the manifest first,
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
and add following code to the activity:
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, you can change it to your path
String mPath = Environment.getExternalStorageDirectory().toString() + "/" + now + ".jpg";
// 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) {
e.printStackTrace();
}
}
this code will open the generated image(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 did for my project. Sometimes this might be not satisfied for you requirement. It it is not satisfied, please follow these tutorials, Thanks
Reference List : http://www.androhub.com/take-a-screenshot-programmatically-in-android/
http://devdeeds.com/take-screenshot-programmatically/
https://www.viralandroid.com/2016/01/how-to-take-screenshot-programmatically-in-android.html
if you want to check whether SD card is available or not. here is the way. If SD card is not available then you can use internal storage to store the image.
Boolean isSDPresent = android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED);
Boolean isSDSupportedDevice = Environment.isExternalStorageRemovable();
if(isSDSupportedDevice && isSDPresent)
{
// yes SD-card is present
}
else
{
// SD-card not available
}
My users make custom images on my app and I am unsure what directory I should use when they save. Should I use MediaStore.Images.Media.EXTERNAL_CONTENT_URI?
Basically MediaStore.Images.Media.EXTERNAL_CONTENT_URI is part of Content Resolver which allow you to read and write resource from your user device. You need to ask yourself wether it is good to save their image into device. You could save your image in private or public which still decided by you. There is internal and external storage, wether you need all image to be deleted when your app is deleted or you don't want other app access the photo you user created use internal storage otherwise use external storage.Take a look on this link which take you step by step to understand why, which,how to save file into your app.
You can make a directory of your own app in the internal storage of the device and store all the pictures made from your app there.
You can make the directory using
File directory = new File(Environment.getExternalStorageDirectory() + File.separator + "<app name>");
if(!directory.exists){
directory.mkdirs;
}
And then store the pictures in this path
Random generator = new Random();
int n = 10000;
n = generator.nextInt(n);
String name = "<image name>"+n+".jpg";
File pictureFile = new File(directory, name);
pictureFile.createNewFile();
try {
FileOutputStream out = new FileOutputStream(pictureFile);
finalBitmap.compress(Bitmap.CompressFormat.JPEG, 90, out);
out.close();
} catch (Exception e) {
e.printStackTrace();
}
Im new to android development and trying to get metadata of image using ExifInterface. I stored the image under drawable and trying to get the metadata but getting null values for all fields(date, imagelength, imagewidth). I tried to access image path as this :
String path = "drawable://" + R.drawable.testimage;
and provided this path to ExifInterface.
ExifInterface exif = new ExifInterface(path);
I dont know if storing image under drawable is correct or not because when I run the app in emulator I get something like this :
E/JHEAD﹕ can't open 'drawable://2130837561'
So if this is wrong then please tell me where should I store the image and how to provide image path to ExifInterface.
Thank you in advance.
To get a drawable, you can you this snippet:
Drawable drawable = getResources().getDrawable(android.R.drawable.your_drawable);
I'm not sure if your way is correct, as I've never seen it like that. Do you really need the path to your image to use it on that ExifInterface class?
Ok, I did some digging and found this question, which led me to this one. As it seems, you can not get an absolute path from a resource inside your apk. A good solution would be for you to save it as a file on the external memory, and then you can get the path you want.
First of all, add this to your AndroidManifest.xml, so your app can write to the cellphone memory:
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Ok, to save it you can try this, first create a bitmap from your drawable resource:
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.your_drawable);
After that get the path you want to save your images, and put it on a String. More info on that here.
The Android docs have a good example on how to get the path. You can see it here.
To keep it simple, I'll copy and paste the snippet from the docs.
void createExternalStoragePrivateFile() {
// Create a path where we will place our private file on external
// storage.
File file = new File(getExternalFilesDir(null), "DemoFile.jpg");
try {
// Very simple code to copy a picture from the application's
// resource into the external file. Note that this code does
// no error checking, and assumes the picture is small (does not
// try to copy it in chunks). Note that if external storage is
// not currently mounted this will silently fail.
InputStream is = getResources().openRawResource(R.drawable.balloons);
OutputStream os = new FileOutputStream(file);
byte[] data = new byte[is.available()];
is.read(data);
os.write(data);
is.close();
os.close();
} catch (IOException e) {
// Unable to create file, likely because external storage is
// not currently mounted.
Log.w("ExternalStorage", "Error writing " + file, e);
}
}
void deleteExternalStoragePrivateFile() {
// Get path for the file on external storage. If external
// storage is not currently mounted this will fail.
File file = new File(getExternalFilesDir(null), "DemoFile.jpg");
if (file != null) {
file.delete();
}
}
boolean hasExternalStoragePrivateFile() {
// Get path for the file on external storage. If external
// storage is not currently mounted this will fail.
File file = new File(getExternalFilesDir(null), "DemoFile.jpg");
if (file != null) {
return file.exists();
}
return false;
}
After that, get the path of the file you saved on the external memory, and do as you wish.
I'll keep the old example as well. You can use the method getExternalStorageDirectory() to get the path, or getExternalCacheDir(). After that, you can use File method called getAbsolutePath() to get your String.
String path = (...) // (you can choose where to save here.)
File file = new File(path, "your_drawable.png");
FileOutputStream out = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out); // You can change the quality from 0 to 100 here, and the format of the file. It can be PNG, JPEG or WEBP.
out.flush();
out.close();
For more info on the Bitmap class, check the docs.
If you need more info, let me know and I'll try to show more samples.
EDIT: I saw your link, and there was this snippet there:
//change with the filename & location of your photo file
String filename = "/sdcard/DSC_3509.JPG";
try {
ExifInterface exif = new ExifInterface(filename);
ShowExif(exif);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Toast.makeText(this, "Error!",
Toast.LENGTH_LONG).show();
}
As you can see, if you really want to see the exif data of a internal image resource, you'll have to save it somewhere else, and then you can try to get the absolute path for that File, then, call the method to show the exif.
I am trying to store my output file in internal memory.but it throws java.io.FileNotFoundException Access is denied
private boolean crop() {
try {
FileOutputStream fos = null;
String filePath = CustomVideoGalleryActivity.videoPath.get(0);
Movie originalMovie = MovieCreator.build(filePath);
Track track = originalMovie.getTracks().get(0);
Movie movie = new Movie();
movie.addTrack(new AppendTrack(new CroppedTrack(track, 200, 800)));
Container out = new DefaultMp4Builder().build(movie);
String outputFilePath = Environment.getDataDirectory()+ "/output_crop.mp4";
fos = new FileOutputStream(new File(outputFilePath)); //throws Exception
out.writeContainer(fos.getChannel());
fos.close();
mProgressDialog.dismiss();
finish();
} catch (Exception e) {
Log.v("ONMESSAGE", e.toString());
e.printStackTrace();
mProgressDialog.dismiss();
return false;
}
return true;
}
You need to ask for write permission in your AndroidManifest.xml. In particular, the following line must be present:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
You shouldn't be looking at the Data Directory. This is a system directory in the phone's storage - usually /data - and your application will never have permission to write to it.
The directory your application should write files to is returned by the Context.getFilesDir() method. It will be something like /data/data/com.yourdomain.YourApp/files.
If you want to write to a file in the phone's storage use the Context.openFileOutput() method.
If you want the path to the SDCard then use Environment.getExternalStorageDirectory() method. To write to the SDCard you'll need to give your application the appropriate permissions by adding the following to your Manifest:
If you're going to write to the SDCard you'll also need to check its state with the getExternalStorageState() method.
If you're storing small files to do with your application then these can go into the phone's storage and not the SD Card, so use the Context.openFileOutput() and Context.openFileInput() methods.
So in your code consider something like:
OutputStream os = openFileOutput("samplefile.txt", MODE_PRIVATE);
BufferedWriter lout = new BufferedWriter(new OutputStreamWriter(os));