create an tempDir and save it into an IFile with the external_drive_lib - android

Currently i am Getting from the IDrive an folder which has a file and i am copying this file into a tempfile which i am reading with the Streamreader, but is there a way to create this IFIle or i chnage the tempfile and save it into the IFile?
public IFolder TryToGetFolder(IDrive drive, string folderPath)
{
if (drive.is_connected())
{
try
{
return drive.try_parse_folder(folderPath);
}
catch
{
return null;
}
}
else
return null;
}
//Tries to get a file in a folder or returns null
public IFile TryToGetFile(IFolder folder, string filename)
{
return folder.files.Where(f => f.name == filename).FirstOrDefault();
}
//Tries to read the text of a file or returns null
public string TryToGetFileText(IFile file)
{
//Uses the tempDir to copy the file to it
string tempDir = _tempDir + "temp-" + DateTime.Now.Ticks;
Directory.CreateDirectory(tempDir);
file.copy_sync(tempDir);
//Read file from tempDir
StreamReader reader = new StreamReader(tempDir + "\\" + file.name);
return reader.ReadToEnd();
}
//Tries to delete a file
public void TryToDeleteFile(IFile file)
{
if(file != null)
{
if (file.exists)
file.delete_sync();
}
}
I tried this but this is using a Process Class, which i havent seen before.
//Tries to Send a file from the WPF to the Android Device
public bool SendFileToAndroid(AndroidDevice device, string filePath, CWCProduct cWCProduct)
{
if (!device.Drive.is_connected())
return false;
try
{
var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "adb",
Arguments = $"push {filePath} {cWCProduct}",
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true
}
};
process.Start();
process.WaitForExit();
return true;
}
catch
{
return false;
}
}

Related

Java.IO.FileNotFoundException: (No such file or directory) exception on saving pdf file to phone xamarin forms

On a click of a button I need to save pdf file.
Im using xf 4.6.1 and syncfusion component which has event - PdfViewerControl_DocumentSaveInitiated
In codebehind, when program should go to my renderer method Save() which is derivates from ISave class, it throws later on renderer method Save() => Java.IO.FileNotFoundException: 'Download/SavedDocument.pdf (No such file or directory)' exception.
COdebehind:
private void PdfViewerControl_DocumentSaveInitiated(object sender, Syncfusion.SfPdfViewer.XForms.DocumentSaveInitiatedEventArgs args)
{
Device.BeginInvokeOnMainThread(async () =>
{
var status = await CrossPermissions.Current.CheckPermissionStatusAsync<StoragePermission>();
if (status != PermissionStatus.Granted)
{
status = await Utils.CheckPermissions(new Plugin.Permissions.StoragePermission());
}
if (status == Plugin.Permissions.Abstractions.PermissionStatus.Granted)
{
string filePath = DependencyService.Get<ISave>().Save(args.SaveStream as MemoryStream);
string message = "The Kiid document has been saved to " + filePath;
DependencyService.Get<IAlertView>().Show(message);
}
});
}
Interface:
public interface ISave
{
string Save(MemoryStream fileStream);
}
AndroidRenderer:
public class SaveAndroid : ISave
{
public string Save(System.IO.MemoryStream stream)
{
string root = null;
string fileName = "SavedDocument.pdf";
if (Android.OS.Environment.IsExternalStorageEmulated)
{
root = Android.OS.Environment.DirectoryDownloads.ToString();
}
Java.IO.File myDir = new Java.IO.File(root + "/Syncfusion");
myDir.Mkdir();
Java.IO.File file = new Java.IO.File(myDir, fileName);
string filePath = file.Path;
if (file.Exists()) file.Delete();
Java.IO.FileOutputStream outs = new Java.IO.FileOutputStream(file);
outs.Write(stream.ToArray());
var ab = file.Path;
outs.Flush();
outs.Close();
return filePath;
}
}
On physical device, it goes to the method Save(), and it breaks on the line Java.IO.FileOutputStream outs = new Java.IO.FileOutputStream(file);
As you can see I added permission check for storage.
What could be?

store the Sugar ORM database in sd card rather than default path android

i am using sugar orm to store my data in sqlite database in android and it is working perfectly so now i want to store the data in the local storage rather than the default path so how can i achieve that and moreover that is it possible to do this
Thanks.
This is my mainactivity code
public class MainActivity extends AppCompatActivity {
EditText firstname;
EditText lastname;
Button button;
Note note;
public SQLiteDatabase database;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
firstname=findViewById(R.id.edit1);
lastname=findViewById(R.id.edit2);
button=findViewById(R.id.button);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
return id == R.id.action_settings || super.onOptionsItemSelected(item);
}
public void click(View view) {
String first = firstname.getText().toString();
String last = lastname.getText().toString();
note = new Note(first, last);
note.save();
if (note.getFirstname() != null && note.getLastname() != null) {
firstname.setText("");
lastname.setText("");
}
onShareDb();
//Log.e("Notes saved", String.valueOf(onShareDb()));
}
public void show(View view) {
String one=note.getFirstname();
String two=note.getLastname();
Log.e("firstName",one);
Log.e("lastName",two);
}
public void update(View view) {
note = Note.findById(Note.class, 4);
Log.e("firstName",note.getFirstname());
note.setFirstname("kullu");
Log.e("firstName",note.getFirstname());
note.save();
}
public void delete(View view) {
note = Note.findById(Note.class, 2);
if(note.getId()==null){
Toast.makeText(this,"there is no such data",Toast.LENGTH_SHORT).show();
}
Log.e("firstName",note.getFirstname());
note.delete();
Log.e("firstName",note.getFirstname());
}
public void onShareDb() {
#SuppressLint("SimpleDateFormat") SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
String output_name = "YourApp_" + df.format(new Date()) + ".db";
File output_file = new File(getExternalCacheDir() + File.separator + output_name);
try {
File file = new File(new SugarDb(MainActivity.this).getDB().getPath()); // get private db reference
if (!file.exists() || file.length() == 0) throw new Exception("Empty DB");
//IOUtils.copy(new FileInputStream(file), new FileOutputStream(output_file));
/* Intent i = new Intent(Intent.ACTION_SEND);
i.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(output_file));
startActivity(Intent.createChooser(i, "Send db"));*/
database = SQLiteDatabase.openDatabase(output_file
+ File.separator + "notes.db", null,
SQLiteDatabase.OPEN_READWRITE);
Log.e("storage", String.valueOf(database));
} catch (Exception e) {
Toast.makeText(getApplicationContext(), "Unable to export db: " + e.getMessage(), Toast.LENGTH_SHORT).show();
Log.e("storage", e.getMessage());
}
}
}
So, basically i m trying to get the path of stored images by using the shareDB() property of sugar orm and trying to overwrite the default path to my new path so how do i get it done, i m calling shareDB method in button click listener, the exception is something like unknown error: could not open database.
After a lot of research and trial error, I somehow manage to succeed in copying the sqllite file from one folder to another folder in the directory
Here is the code,
private void copyDatabase() throws IOException {
File actualFile = new File(new SugarDb(MainActivity.this).getDB().getPath());
File cuurentfile = new File(actualFile.toString());
Log.e("actualPath", actualFile.toString());
File newFile = createTempFile("sugarFiles",".db",Environment.getExternalStorageDirectory());
Log.e("newPath", newFile.toString());
boolean yes=FileUtils.copyFile(cuurentfile,newFile);
if(yes) {
Log.e("result", "" + true);
}
}
call this copydatabase function inside the click listener or wherever you are inserting into the database, make sure it is after you set the insertion values, in my case
public void click(View view) {
String first = firstname.getText().toString();
String last = lastname.getText().toString();
note = new Note(first, last);
note.save();
if (note.getFirstname() != null && note.getLastname() != null) {
firstname.setText("");
lastname.setText("");
}
try {
copyDatabase();
} catch (IOException e) {
e.printStackTrace();
}
}
FileUtils.java
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
public class FileUtils {
FileUtils instance = null;
public FileUtils getInstance() {
instance = new FileUtils();
return instance;
}
public static Boolean copyFile(File sourceFile, File destFile)
throws IOException {
// if (!destFile.exists()) {
destFile.createNewFile();
FileChannel source = null;
FileChannel destination = null;
try {
source = new FileInputStream(sourceFile).getChannel();
destination = new FileOutputStream(destFile).getChannel();
destination.transferFrom(source, 0, source.size());
} finally {
if (source != null)
source.close();
if (destination != null)
destination.close();
}
return true;
// }
// return false;
}
/**
* Read a text file into a String.
*
* #param file
* File to read (will not seek, so things like /proc files are
* OK).
* #return The contents of the file as a String.
* #throws IOException
*/
public static String readTextFile(File file) throws IOException {
byte[] buffer = new byte[(int) file.length()];
BufferedInputStream stream = new BufferedInputStream(
new FileInputStream(file));
stream.read(buffer);
stream.close();
return new String(buffer);
}
}
Hope it helps someone someday...Have a nice day

Unity3D, C# and uploading tracks to SoundCloud

I am working on an app in Unity3D which can upload tracks to SoundCloud. I have been working on this for a while but i can't get it to work. I am using HttpWebRequest for the request to SoundCloud and this works fine on Unity for Windows. But when i try it on my Android device i get the following message: 'Request entity contains invalid byte sequence. Please transmit valid UTF-8.'.
Below is the part of code that i use (got it from somewhere on the internet).
I made sure i was uploading the same file on Windows as on Android and did the request to RequestBin. Now, when i compared the two, i noticed that the raw data is almost completely identical except for the end:
Ending Windows: ÿàþ³þDþÿýëýÅýÙý
Ending Android: ÿàþ³þDþÿýëýÅýÙý[FF]þÞýþûýCþxþZþ{þ
So as you can see, on Android there is more data. Can someone explain to me what is going on here?
I started with posts on the Unity community, now trying it here. Here you can find my question on the unity website for more information.
public class SoundCloudScript {
//Enter app credentials from here http://soundcloud.com/you/apps
private const string _clientId = "xxx";
private const string _clientSecret = "xxx";
//enter username and password a soundcloud user, e.g. your own credentials
private const string _username = "xxx";
private const string _password = "xxx";
private string soundCloudToken;
//private WebClient _webclient = new WebClient();
public string Status { get; set; }
public IEnumerator GetTokenAndUploadFile(MonoBehaviour mono, FileInfo file)
{
Debug.Log ( "GetTokenAndUploadFile() started");
ServicePointManager.ServerCertificateValidationCallback = (p1, p2, p3, p4) => true;
var form = new WWWForm ();
form.AddField ("client_id", _clientId);
form.AddField ("client_secret", _clientSecret);
form.AddField ("grant_type", "password");
form.AddField ("username", _username);
form.AddField ("password", _password);
//Authentication
string soundCloudTokenRes = "https://api.soundcloud.com/oauth2/token";
Debug.Log ( "Try to get token");
WWW download = new WWW(soundCloudTokenRes, form);
yield return download;
if(!string.IsNullOrEmpty(download.error))
{
Debug.Log ( "Error downloading: " + download.error );
}
else
{
var tokenInfo = download.text;
tokenInfo = tokenInfo.Remove(0, tokenInfo.IndexOf("token\":\"") + 8);
soundCloudToken = tokenInfo.Remove(tokenInfo.IndexOf("\""));
Debug.Log(string.Format("Token set: {0}", soundCloudToken));
UploadFile(file);
}
}
public void UploadFile(FileInfo file)
{
Debug.Log ("Start uploading!");
ServicePointManager.Expect100Continue = false;
var request = WebRequest.Create("https://api.soundcloud.com/tracks/") as HttpWebRequest;
//some default headers
request.Accept = "*/*";
request.Headers.Add("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.3");
request.Headers.Add("Accept-Encoding", "gzip,deflate,sdch");
request.Headers.Add("Accept-Language", "en-US,en;q=0.8,ru;q=0.6");
//file array
var files = new UploadFile[]
{
new UploadFile(file.FullName, "track[asset_data]", "application/octet-stream")
};
//other form data
var form = new System.Collections.Specialized.NameValueCollection();
form.Add("track[title]", "Some title");
form.Add("track[sharing]", "private");
form.Add("oauth_token", soundCloudToken);
form.Add("format", "json");
try
{
using (var response = HttpUploadHelper.Upload(request, files, form))
{
using (var reader = new StreamReader(response.GetResponseStream()))
{
reader.ReadToEnd();
}
}
Debug.Log ("Upload success!");
}
catch (WebException wex) {
if (wex.Response != null) {
using (var errorResponse = (HttpWebResponse)wex.Response) {
using (var reader = new StreamReader(errorResponse.GetResponseStream())) {
string error = reader.ReadToEnd();
Debug.Log ("Error(1/2): Message: " + wex.Message);
Debug.Log ("Error(2/2): " + error);
//TODO: use JSON.net to parse this string and look at the error message
}
}
}
}
//return "Nothing...";
}
}
public class StreamMimePart : MimePart
{
Stream _data;
public void SetStream(Stream stream)
{
_data = stream;
}
public override Stream Data
{
get
{
return _data;
}
}
}
public abstract class MimePart
{
NameValueCollection _headers = new NameValueCollection();
byte[] _header;
public NameValueCollection Headers
{
get { return _headers; }
}
public byte[] Header
{
get { return _header; }
}
public long GenerateHeaderFooterData(string boundary)
{
StringBuilder sb = new StringBuilder();
sb.Append("--");
sb.Append(boundary);
sb.AppendLine();
foreach (string key in _headers.AllKeys)
{
sb.Append(key);
sb.Append(": ");
sb.AppendLine(_headers[key]);
}
sb.AppendLine();
_header = Encoding.UTF8.GetBytes(sb.ToString());
return _header.Length + Data.Length + 2;
}
public abstract Stream Data { get; }
}
public class StringMimePart : MimePart
{
Stream _data;
public string StringData
{
set
{
_data = new MemoryStream(Encoding.UTF8.GetBytes(value));
}
}
public override Stream Data
{
get
{
return _data;
}
}
}
public class HttpUploadHelper
{
private HttpUploadHelper()
{ }
public static string Upload(string url, UploadFile[] files, NameValueCollection form)
{
HttpWebResponse resp = Upload((HttpWebRequest)WebRequest.Create(url), files, form);
using (Stream s = resp.GetResponseStream())
using (StreamReader sr = new StreamReader(s))
{
return sr.ReadToEnd();
}
}
public static HttpWebResponse Upload(HttpWebRequest req, UploadFile[] files, NameValueCollection form)
{
List<MimePart> mimeParts = new List<MimePart>();
try
{
foreach (string key in form.AllKeys)
{
StringMimePart part = new StringMimePart();
part.Headers["Content-Disposition"] = "form-data; name=\"" + key + "\"";
part.StringData = form[key];
mimeParts.Add(part);
}
int nameIndex = 0;
foreach (UploadFile file in files)
{
StreamMimePart part = new StreamMimePart();
if (string.IsNullOrEmpty(file.FieldName))
file.FieldName = "file" + nameIndex++;
part.Headers["Content-Disposition"] = "form-data; name=\"" + file.FieldName + "\"; filename=\"" + file.FileName + "\"";
part.Headers["Content-Type"] = file.ContentType;
part.SetStream(file.Data);
mimeParts.Add(part);
}
string boundary = "----------" + DateTime.Now.Ticks.ToString("x");
req.ContentType = "multipart/form-data; boundary=" + boundary;
req.Method = "POST";
long contentLength = 0;
byte[] _footer = Encoding.UTF8.GetBytes("--" + boundary + "--\r\n");
foreach (MimePart part in mimeParts)
{
contentLength += part.GenerateHeaderFooterData(boundary);
}
req.ContentLength = contentLength + _footer.Length;
Debug.Log ("ContentLength: " + req.ContentLength);
byte[] buffer = new byte[8192];
byte[] afterFile = Encoding.UTF8.GetBytes("\r\n");
int read;
foreach(var header in req.Headers)
{
Debug.Log(header);
}
using (Stream s = req.GetRequestStream())
{
foreach (MimePart part in mimeParts)
{
s.Write(part.Header, 0, part.Header.Length);
while ((read = part.Data.Read(buffer, 0, buffer.Length)) > 0)
{
s.Write(buffer, 0, read);
Debug.Log ("Buffer: >>" + System.Text.Encoding.UTF8.GetString(buffer) + "<<");
}
//Debug.Log ("Buffer: " + System.Text.Encoding.UTF8.GetString(buffer));
part.Data.Dispose();
s.Write(afterFile, 0, afterFile.Length);
Debug.Log ("Buffer-End: >>" + System.Text.Encoding.UTF8.GetString(afterFile) + "<<");
}
s.Write(_footer, 0, _footer.Length);
Debug.Log ("Footer: >>" + System.Text.Encoding.UTF8.GetString(_footer) + "<<");
}
return (HttpWebResponse)req.GetResponse();
}
catch (Exception e)
{
Debug.Log ("Crash! Message: " + e.Message);
foreach (MimePart part in mimeParts)
if (part.Data != null)
part.Data.Dispose();
throw;
}
}
}
public class UploadFile
{
Stream _data;
string _fieldName;
string _fileName;
string _contentType;
public UploadFile(Stream data, string fieldName, string fileName, string contentType)
{
_data = data;
_fieldName = fieldName;
_fileName = fileName;
_contentType = contentType;
}
public UploadFile(string fileName, string fieldName, string contentType)
: this(File.OpenRead(fileName), fieldName, Path.GetFileName(fileName), contentType)
{ }
public UploadFile(string fileName)
: this(fileName, null, "application/octet-stream")
{ }
public Stream Data
{
get { return _data; }
set { _data = value; }
}
public string FieldName
{
get { return _fieldName; }
set { _fieldName = value; }
}
public string FileName
{
get { return _fileName; }
set { _fileName = value; }
}
public string ContentType
{
get { return _contentType; }
set { _contentType = value; }
}
}
It's working!! The problem was that at some point i used StringBuilder.AppendLine() to add a new line. This works fine on Windows, but on Android it didn't work... (i figured it out because the Content-Length was not the same for Windows and Android.)
I fixed it by instead of using 'StringBuilding.AppendLine()', i use 'StringBuilder.Append("\r\n")'

Saving and Reading Bitmaps/Images from Internal memory in Android

What I want to do, is to save an image to the internal memory of the phone (Not The SD Card).
How can I do it?
I have got the image directly from the camera to the image view in my app its all working fine.
Now what I want is to save this image from Image View to the Internal memory of my android device and also access it when required.
Can anyone please guide me how to do this?
I am a little new to android so please, I would appreciate if I can have a detailed procedure.
Use the below code to save the image to internal directory.
private String saveToInternalStorage(Bitmap bitmapImage){
ContextWrapper cw = new ContextWrapper(getApplicationContext());
// path to /data/data/yourapp/app_data/imageDir
File directory = cw.getDir("imageDir", Context.MODE_PRIVATE);
// Create imageDir
File mypath=new File(directory,"profile.jpg");
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 (IOException e) {
e.printStackTrace();
}
}
return directory.getAbsolutePath();
}
Explanation :
1.The Directory will be created with the given name. Javadocs is for to tell where exactly it will create the directory.
2.You will have to give the image name by which you want to save it.
To Read the file from internal memory. Use below code
private void loadImageFromStorage(String path)
{
try {
File f=new File(path, "profile.jpg");
Bitmap b = BitmapFactory.decodeStream(new FileInputStream(f));
ImageView img=(ImageView)findViewById(R.id.imgPicker);
img.setImageBitmap(b);
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
}
/**
* Created by Ilya Gazman on 3/6/2016.
*/
public class ImageSaver {
private String directoryName = "images";
private String fileName = "image.png";
private Context context;
private boolean external;
public ImageSaver(Context context) {
this.context = context;
}
public ImageSaver setFileName(String fileName) {
this.fileName = fileName;
return this;
}
public ImageSaver setExternal(boolean external) {
this.external = external;
return this;
}
public ImageSaver setDirectoryName(String directoryName) {
this.directoryName = directoryName;
return this;
}
public void save(Bitmap bitmapImage) {
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream(createFile());
bitmapImage.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (fileOutputStream != null) {
fileOutputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
#NonNull
private File createFile() {
File directory;
if(external){
directory = getAlbumStorageDir(directoryName);
}
else {
directory = context.getDir(directoryName, Context.MODE_PRIVATE);
}
if(!directory.exists() && !directory.mkdirs()){
Log.e("ImageSaver","Error creating directory " + directory);
}
return new File(directory, fileName);
}
private File getAlbumStorageDir(String albumName) {
return new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), albumName);
}
public static boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
return Environment.MEDIA_MOUNTED.equals(state);
}
public static boolean isExternalStorageReadable() {
String state = Environment.getExternalStorageState();
return Environment.MEDIA_MOUNTED.equals(state) ||
Environment.MEDIA_MOUNTED_READ_ONLY.equals(state);
}
public Bitmap load() {
FileInputStream inputStream = null;
try {
inputStream = new FileInputStream(createFile());
return BitmapFactory.decodeStream(inputStream);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (inputStream != null) {
inputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
}
Usage
To save:
new ImageSaver(context).
setFileName("myImage.png").
setDirectoryName("images").
save(bitmap);
To load:
Bitmap bitmap = new ImageSaver(context).
setFileName("myImage.png").
setDirectoryName("images").
load();
Edit:
Added ImageSaver.setExternal(boolean) to support saving to external storage based on googles example.
Came across this question today and this is how I do it.
Just call this function with the required parameters
public void saveImage(Context context, Bitmap bitmap, String name, String extension){
name = name + "." + extension;
FileOutputStream fileOutputStream;
try {
fileOutputStream = context.openFileOutput(name, Context.MODE_PRIVATE);
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fileOutputStream);
fileOutputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
Similarly, for reading the same, use this
public Bitmap loadImageBitmap(Context context,String name,String extension){
name = name + "." + extension
FileInputStream fileInputStream
Bitmap bitmap = null;
try{
fileInputStream = context.openFileInput(name);
bitmap = BitmapFactory.decodeStream(fileInputStream);
fileInputStream.close();
} catch(Exception e) {
e.printStackTrace();
}
return bitmap;
}
For Kotlin users, I created a ImageStorageManager class which will handle save, get and delete actions for images easily:
class ImageStorageManager {
companion object {
fun saveToInternalStorage(context: Context, bitmapImage: Bitmap, imageFileName: String): String {
context.openFileOutput(imageFileName, Context.MODE_PRIVATE).use { fos ->
bitmapImage.compress(Bitmap.CompressFormat.PNG, 25, fos)
}
return context.filesDir.absolutePath
}
fun getImageFromInternalStorage(context: Context, imageFileName: String): Bitmap? {
val directory = context.filesDir
val file = File(directory, imageFileName)
return BitmapFactory.decodeStream(FileInputStream(file))
}
fun deleteImageFromInternalStorage(context: Context, imageFileName: String): Boolean {
val dir = context.filesDir
val file = File(dir, imageFileName)
return file.delete()
}
}
}
Read more here
This code will support up Upto Android 11+.
Declare a permission result on Fragment / Activity
I am using a fragment
private val askPermissions =
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
val isGranted = permissions.entries.all {
it.value == true
}
if (isGranted) {
viewModel.saveImageToGallery(requireContext().contentResolver,
getString(R.string.my_deshi_qr_code),
bitmap)
} else {
askForWritePermission()
}
}
Trigger event
bindingView.downloadQrButton.setOnClickListener {
requestPermission()
}
private fun requestPermission() {
val minSDK = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
val isWritePermissionGranted = (ContextCompat.checkSelfPermission(requireContext(),
Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) || minSDK
if (!isWritePermissionGranted) {
askForWritePermission()
} else {
viewModel.saveImageToGallery(requireContext().contentResolver,
getString(R.string.my_deshi_qr_code),
bitmap)
}
}
private fun askForWritePermission() {
askPermissions.launch(listOf(Manifest.permission.WRITE_EXTERNAL_STORAGE).toTypedArray())
}
Viewmodel
fun saveImageToGallery(contentResolver: ContentResolver, imageName: String, bitmap: Bitmap?) {
val imageUri: Uri?
val contentValues = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, "$imageName.jpg")
put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
bitmap?.let {
put(MediaStore.Images.Media.WIDTH, bitmap.width)
put(MediaStore.Images.Media.HEIGHT, bitmap.height)
}
}
imageUri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH,
Environment.DIRECTORY_PICTURES + File.separator.toString() + "YourFolderName")
MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
} else {
MediaStore.Images.Media.EXTERNAL_CONTENT_URI
}
try {
val uri = contentResolver.insert(imageUri, contentValues)
val fos = uri?.let { contentResolver.openOutputStream(it) }
bitmap?.compress(Bitmap.CompressFormat.JPEG, 100, fos)
Objects.requireNonNull(fos)
_showMessage.postValue(Event("Image Saved"))
} catch (e: Exception) {
_showMessage.postValue(Event("Image Not Saved \n$e"))
}
}
// mutiple image retrieve
File folPath = new File(getIntent().getStringExtra("folder_path"));
File[] imagep = folPath.listFiles();
for (int i = 0; i < imagep.length ; i++) {
imageModelList.add(new ImageModel(imagep[i].getAbsolutePath(), Uri.parse(imagep[i].getAbsolutePath())));
}
imagesAdapter.notifyDataSetChanged();
if you want to follow Android 10 practices to write in storage, check here
and if you only want the images to be app specific, here
for example if you want to store an image just to be used by your app:
viewModelScope.launch(Dispatchers.IO) {
getApplication<Application>().openFileOutput(filename, Context.MODE_PRIVATE).use {
bitmap.compress(Bitmap.CompressFormat.PNG, 50, it)
}
}
getApplication is a method to give you context for ViewModel and it's part of AndroidViewModel
later if you want to read it:
viewModelScope.launch(Dispatchers.IO) {
val savedBitmap = BitmapFactory.decodeStream(
getApplication<App>().openFileInput(filename).readBytes().inputStream()
)
}
Make sure to use WEBP as your media format to save more space with same quality:
fun saveImage(context: Context, bitmap: Bitmap, name: String): String {
context.openFileOutput(name, Context.MODE_PRIVATE).use { fos ->
bitmap.compress(Bitmap.CompressFormat.WEBP, 25, fos)
}
return context.filesDir.absolutePath
}

How check if a DiskLruCache already exists? (Android)

I´m using that way of cache Bitmaps in my app Using DiskLruCache in android 4.0 does not provide for openCache method
Thing is that I´m using that line in onCreate()
DiskLruImageCache dlic=new DiskLruImageCache(getApplicationContext(),"bckgCache", CACHESIZE, CompressFormat.PNG, 70);
and I´m pretty sure that It is overwriting my DiskLruCache everytime the app is opened "as new", so I´m not being able to recover some Bitmaps I catch las time user opened the app. So here is the question
How can I check I there´s already a DislLruCache created for an specific App so I will only create It If It doesn´t exist?
That's the class I'm using from the above URL
public class DiskLruImageCache {
private DiskLruCache mDiskCache;
private CompressFormat mCompressFormat = CompressFormat.PNG;
private int mCompressQuality = 70;
private static final int APP_VERSION = 1;
private static final int VALUE_COUNT = 1;
private static final String TAG = "DiskLruImageCache";
public DiskLruImageCache( Context context,String uniqueName, int diskCacheSize,
CompressFormat compressFormat, int quality ) {
try {
final File diskCacheDir = getDiskCacheDir(context, uniqueName );
mDiskCache = DiskLruCache.open( diskCacheDir, APP_VERSION, VALUE_COUNT, diskCacheSize );
mCompressFormat = compressFormat;
mCompressQuality = quality;
} catch (IOException e) {
e.printStackTrace();
}
}
private boolean writeBitmapToFile( Bitmap bitmap, DiskLruCache.Editor editor )
throws IOException, FileNotFoundException {
BufferedOutputStream out = null;
try {
out = new BufferedOutputStream( editor.newOutputStream( 0 ), Utils.IO_BUFFER_SIZE );
return bitmap.compress( mCompressFormat, mCompressQuality, out );
} finally {
if ( out != null ) {
out.close();
}
}
}
private File getDiskCacheDir(Context context, String uniqueName) {
// Check if media is mounted or storage is built-in, if so, try and use external cache dir
// otherwise use internal cache dir
final String cachePath =
Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) ||
!Utils.isExternalStorageRemovable() ?
Utils.getExternalCacheDir(context).getPath() :
context.getCacheDir().getPath();
return new File(cachePath + File.separator + uniqueName);
}
public void put( String key, Bitmap data ) {
DiskLruCache.Editor editor = null;
try {
editor = mDiskCache.edit( key );
if ( editor == null ) {
return;
}
if( writeBitmapToFile( data, editor ) ) {
mDiskCache.flush();
editor.commit();
if ( BuildConfig.DEBUG ) {
Log.d( "cache_test_DISK_", "image put on disk cache " + key );
}
} else {
editor.abort();
if ( BuildConfig.DEBUG ) {
Log.d( "cache_test_DISK_", "ERROR on: image put on disk cache " + key );
}
}
} catch (IOException e) {
if ( BuildConfig.DEBUG ) {
Log.d( "cache_test_DISK_", "ERROR on: image put on disk cache " + key );
}
try {
if ( editor != null ) {
editor.abort();
}
} catch (IOException ignored) {
}
}
}
public Bitmap getBitmap( String key ) {
Bitmap bitmap = null;
DiskLruCache.Snapshot snapshot = null;
try {
snapshot = mDiskCache.get( key );
if ( snapshot == null ) {
return null;
}
final InputStream in = snapshot.getInputStream( 0 );
if ( in != null ) {
final BufferedInputStream buffIn =
new BufferedInputStream( in, Utils.IO_BUFFER_SIZE );
bitmap = BitmapFactory.decodeStream( buffIn );
}
} catch ( IOException e ) {
e.printStackTrace();
} finally {
if ( snapshot != null ) {
snapshot.close();
}
}
if ( BuildConfig.DEBUG ) {
Log.d( "cache_test_DISK_", bitmap == null ? "" : "image read from disk " + key);
}
return bitmap;
}
public boolean containsKey( String key ) {
boolean contained = false;
DiskLruCache.Snapshot snapshot = null;
try {
snapshot = mDiskCache.get( key );
contained = snapshot != null;
} catch (IOException e) {
e.printStackTrace();
} finally {
if ( snapshot != null ) {
snapshot.close();
}
}
return contained;
}
public void clearCache() {
if ( BuildConfig.DEBUG ) {
Log.d( "cache_test_DISK_", "disk cache CLEARED");
}
try {
mDiskCache.delete();
} catch ( IOException e ) {
e.printStackTrace();
}
}
public File getCacheFolder() {
return mDiskCache.getDirectory();
}
And this is what I'm doing into my Activity, wich doesn't works. If you try offline works the first time, second It doesn't (null pointer in OnPause because It can't find any Bitmap in the folder). If you try Online always works, but, if you try online, and then offline, instead load the previous downloaded image, is stops (null pointer), so, main problem is that It, for whatever reason, doesn't records or reads anything in the cache folder
public class Portada extends Activity {
private LinearLayout linearLayout;
private BitmapDrawable drawableBitmap;
private Bitmap b;
private DiskLruImageCache dlic;
private final String urlFondo="http://adapp.hostei.com/img/portada.jpg";
private final int MAXMEMORY = (int) (Runtime.getRuntime().maxMemory() / 1024);
private final int CACHESIZE = MAXMEMORY / 8;
private final String KEYPORTADA="bckportada";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_portada);
linearLayout=(LinearLayout)findViewById(R.id.fondoPortada);
Log.i("OnCreate","Starting");
File cacheDir=new File(android.os.Environment.getExternalStorageDirectory(),"bckgCache");
if(!cacheDir.exists()){ // check if it exits. if not create one
Log.i("OnCreate","Create not exsisting folder");
cacheDir.mkdirs();
dlic=new DiskLruImageCache(Portada.this,cacheDir.getName(), CACHESIZE, CompressFormat.PNG, 70);
}
else{
dlic=new DiskLruImageCache(Portada.this,cacheDir.getName(), CACHESIZE, CompressFormat.PNG, 70);
}
}
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
Log.i("OnResume","Starting");
//checks if there's already a background image on cache
boolean hayportada=comprobarSiHayPortadaEnCache();
//creates a bckImage from R.drawable image if there's any already in cache
//this should only occurs once, the very first time the App runs
if(!hayportada){
b=BitmapFactory.decodeResource(getResources(), R.drawable.portada);
dlic.put(KEYPORTADA, b);
Log.i("onResume","Creates bckgImage from R.drawable");
}
//checks if there's any connection and if yes, loads the url image into cache and puts It as background
//if not load the image of the previous if
if(CheckOnline.isOnline(Portada.this)){
cargarPortadaUrl(urlFondo);//loads image from url and stores in cache
cargarImagenPortada(b);//put image as layout background
Log.i("onResume","there is online, down img");
}
else{
b=dlic.getBitmap(KEYPORTADA);
cargarImagenPortada(b);
Log.i("onResume","there's not online ");
}
}
#Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
dlic.put(KEYPORTADA, b);//just in case, It's already done in OnResume;
Log.i("onPause","stores Bitmap");
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_portada, menu);
return true;
}
/**
* Takes an image from url and stores It in cache
*
*/
public void cargarPortadaUrl(String urlFondo){
DownloadImageTask dit=new DownloadImageTask();//Async task that downloads an img
try {
b=dit.execute(urlFondo).get();
dlic.put(KEYPORTADA, b);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//loads a Bitmap as Layout Background image
public void cargarImagenPortada(Bitmap bitm){
drawableBitmap=new BitmapDrawable(bitm);
linearLayout.setBackgroundDrawable(drawableBitmap);
}
//checks if there's any
public boolean comprobarSiHayPortadaEnCache(){
b=dlic.getBitmap(KEYPORTADA);
if(b==null)return false;
else return true;
}
}
Check if sd card is mounted. Get the path of the sdcard. Check if the folder under sdcard already exists, if not create one.
Remember to add permission in manifest file
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
if(android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED))
{
File cacheDir=new File(android.os.Environment.getExternalStorageDirectory(),"MyFolder");
if(!cacheDir.exists())
cacheDir.mkdirs();
}
You can use the below. Found this on developer site in the below link
File cacheDir = getDiskCacheDir(ActivityName.this, "thumbnails");
if(!cacheDir.exists()) // check if it exits. if not create one
{
cacheDir.mkdirs();
}
public static File getDiskCacheDir(Context context, String uniqueName) {
// Check if media is mounted or storage is built-in, if so, try and use external cache dir
// otherwise use internal cache dir
final String cachePath =
Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) ||
!isExternalStorageRemovable() ? getExternalCacheDir(context).getPath() :
context.getCacheDir().getPath();
return new File(cachePath + File.separator + uniqueName);
}
For more information check the link below
http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html
I see you have used getAppliactionContext(). Check the link below
When to call activity context OR application context?. Get to know when to use activity context and getApplicationContext()
Edit:
File cacheDir=new File(android.os.Environment.getExternalStorageDirectory(),"MyFolder");
if(!cacheDir.exists()) // check if it exits. if not create one
{
cacheDir.mkdirs();
DiskLruImageCache dlic=new DiskLruImageCache(ActivityName.this,cacheDir, CACHESIZE, CompressFormat.PNG, 70);
}
else
{
DiskLruImageCache dlic=new DiskLruImageCache(ActivityName.this,cacheDir, CACHESIZE, CompressFormat.PNG, 70);
}
Edit: 2
As you can see below you are just passing the file not creating a new one.
private DiskLruCache(File directory, int appVersion, int valueCount, long maxSize) {
this.directory = directory;
this.appVersion = appVersion;
this.journalFile = new File(directory, JOURNAL_FILE);
this.journalFileTmp = new File(directory, JOURNAL_FILE_TMP);
this.valueCount = valueCount;
this.maxSize = maxSize;
}
public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize)
throws IOException {
if (maxSize <= 0) {
throw new IllegalArgumentException("maxSize <= 0");
}
if (valueCount <= 0) {
throw new IllegalArgumentException("valueCount <= 0");
}
// prefer to pick up where we left off
DiskLruCache cache = new DiskLruCache(directory, appVersion, valueCount, maxSize);
if (cache.journalFile.exists()) {
try {
cache.readJournal();
cache.processJournal();
cache.journalWriter = new BufferedWriter(new FileWriter(cache.journalFile, true),
IO_BUFFER_SIZE);
return cache;
} catch (IOException journalIsCorrupt) {
System.logW("DiskLruCache " + directory + " is corrupt: "
+ journalIsCorrupt.getMessage() + ", removing");
cache.delete();
}
}
// create a new empty cache
directory.mkdirs();
cache = new DiskLruCache(directory, appVersion, valueCount, maxSize);
cache.rebuildJournal();
return cache;
}

Categories

Resources