I am building a meme generator app. So far, the app does everything I need it to do but I want to add 1 more functionality. The app saves the meme as a bitmap on my device. I want to add a functionality where, if the user wishes to share the meme on Facebook, Twitter, IG, etc, the app retrieves that same bitmap (which was just created.).
I'm not worried about the sharing function at the moment. I want to find out how I can retrieve the file to be able to share it.
This is the method where the creation and saving of the meme takes place. I will omit unnecessary code:
public void createBitmapAndSave(ImageView img) {
...
counter++;
File file;
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
String path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getPath();
file = new File(path + "/SimpliMeme/" + timeStamp + "-" + counter + ".jpg");
file.getParentFile().mkdir();
try {
OutputStream stream = new FileOutputStream(file);
mutableBitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);
stream.flush();
stream.close();
Toast.makeText(getContext(), "Top Text: " + String.valueOf(topTextMeasurement) + " and bottom text: " + String.valueOf(bottomTextMeasurement),
Toast.LENGTH_SHORT).show();
} catch (IOException e) {
e.printStackTrace();
}
Uri contentUri = Uri.fromFile(file);
mediaScanIntent.setData(contentUri);
Objects.requireNonNull(getContext()).sendBroadcast(mediaScanIntent);
}
and I've created an empty method that needs to be called when the user hits the "Share" button:
public void shareMeme(){}
Like you've mentioned earlier, you gotta divide this big method into 2 small ones.
As far as your initial question goes: There is no point in going back to your device just to find and get that same photo. Divide the method into 2 methods (createBitmap() & saveBitmap(), for example) and if the user just wants to share it without saving it to the device, the app will just call the createBitmap() method to only create the bitmap and then you'll use that in your upcoming sharing functionality.
Related
I have an android app I've programmed where most of the action happens in a html+javascript webView, and I have a couple of scenarios where I pass data and commands back and forth between the Java side and the WebView/JS side.
I've recently programmed a way for the JS side to trigger a registerForActivityResult(new ActivityResultContracts.GetContent(), ... call to allow the user to select an image, and it works, but when I try to send the data back from Java to my javascript, it fails.
public void onActivityResult(Uri uri) {
// this means I've got the URI selected from the gallery
try {
final InputStream imageStream = getContentResolver().openInputStream(uri);
final Bitmap selectedImage = BitmapFactory.decodeStream(imageStream);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
selectedImage.compress(Bitmap.CompressFormat.JPEG, 100, baos);
byte[] b = baos.toByteArray();
String ecImage = Base64.encodeToString(b, Base64.DEFAULT);
myWebView.evaluateJavascript("onImageSelectTest('" + ecImage + "')", null);
} catch (FileNotFoundException e) {
// e.printStackTrace();
}
}
After a bit of testing, I've found that it's only when the ecImage variable contains the base64 long string that the function doesn't run -- it runs just fine if I set ecImage = "abcd"; for example.
I want the webview to have the image for display purposes and, mainly, for posting the data to a web server, and right now for me the easiest way I can think of doing that is passing the image as a base64 string, but the evaluateJavascript call just isn't working with the long strings right now. I'm open to alternative ways of passing the image data to the webview.
So I've created this simple app that asks the user questions (it's like a truth or dare game).
The questions are saved in a .json-file in SD-Card > Android > data > [package name] > files.
I want to make it possible, however, to add or delete those questions by manually editing or exchanging that .json-file in which the questions are saved (so that those new questions then appear in the app).
I already understand that the app needs to call the getExternalFilesDir() method somewhere, so that a directory that I can find in the device's file manager is created in the first place. However - as you probably have guessed - when I open that directory, the "files" folder is empty. (I know the .json-files must be in there since the app is working fine!)
Now my question:
Is there any way I can view and edit those .json-files? I don't care if the solution includes using a PC or some program.
Or should I maybe not save the questions in a .json-file but in a .txt-file instead? Or should I use a different directory to save my question files to begin with??
I would appreciate a detailed answer, since I'm obviously new.
Thanks in advance!
P.S.: I can include code on request.
EDIT: I don't want to edit those files from code, I already know how to do that. My question in particular is about whether there is a possibility to edit the json files using a text editor for example or exchanging the files using copy paste.
Code:
public void copy() {
Context Context = getApplicationContext();
String DestinationFile = Context.getExternalFilesDir(null).getPath() + File.separator + "fragenAdvanced.json";
if (!new File(DestinationFile).exists()) {
try {
CopyFromAssetsToStorage(Context, "fragenAdvanced.json", DestinationFile);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private void CopyFromAssetsToStorage(Context Context, String SourceFile, String DestinationFile) throws IOException {
InputStream IS = Context.getAssets().open(SourceFile);
OutputStream OS = new FileOutputStream(DestinationFile);
CopyStream(IS, OS);
OS.flush();
OS.close();
IS.close();
}
private void CopyStream(InputStream Input, OutputStream Output) throws IOException { //brauche ich das?
byte[] buffer = new byte[5120];
int length = Input.read(buffer);
while (length > 0) {
Output.write(buffer, 0, length);
length = Input.read(buffer);
}
}
This is how I save the file to storage.
there is 3 way to save your user data but your way is not secure because the user has access on it.
the first way is saving user data in SharedPreferences , it's very simple to use , but if user clears the app catch, the data will be deleted ( you can just convert your json to string and save it in sharedPreferences , for converting string to json you can use Gson library )
second way is using SQlite and save data on local database , it will be deleted by clear stroge and still not good for important data
the final way is using remote database and get data from api
This question is related to this previously answered question Share Image on Android Application from Unity Game
My question is this:
Is there a way to share the image WITHOUT using a file? I'd like to remove the sd card read/write permission on Android. I'm not a Java programmer, so I'm having a heck of a time getting it working. None of my attempts have yielded anything.
"Programmer" answered the previous question with the below code, which works great for me. I basically want to use the variable imageBytes instead of the file. Is this even possible?
void takeScreenShotAndShare()
{
StartCoroutine(takeScreenshotAndSave());
}
private IEnumerator takeScreenshotAndSave()
{
string path = "";
yield return new WaitForEndOfFrame();
Texture2D screenImage = new Texture2D(Screen.width, Screen.height);
//Get Image from screen
screenImage.ReadPixels(new Rect(0, 0, Screen.width, Screen.height), 0, 0);
screenImage.Apply();
//Convert to png
byte[] imageBytes = screenImage.EncodeToPNG();
System.IO.Directory.CreateDirectory(Application.persistentDataPath + "/GameOverScreenShot");
path = Application.persistentDataPath + "/GameOverScreenShot" + "/DiedScreenShot.png";
System.IO.File.WriteAllBytes(path, imageBytes);
StartCoroutine(shareScreenshot(path));
}
private IEnumerator shareScreenshot(string destination)
{
string ShareSubject = "Picture Share";
string shareLink = "Test Link" + "\nhttps://stackoverflow.com/questions/36512784/share-image-on-android-application-from-unity-game";
string textToShare = "Text To share";
Debug.Log(destination);
if (!Application.isEditor)
{
AndroidJavaClass intentClass = new AndroidJavaClass("android.content.Intent");
AndroidJavaObject intentObject = new AndroidJavaObject("android.content.Intent");
intentObject.Call<AndroidJavaObject>("setAction", intentClass.GetStatic<string>("ACTION_SEND"));
AndroidJavaClass uriClass = new AndroidJavaClass("android.net.Uri");
AndroidJavaObject uriObject = uriClass.CallStatic<AndroidJavaObject>("parse", "file://" + destination);
intentObject.Call<AndroidJavaObject>("putExtra", intentClass.GetStatic<string>("EXTRA_STREAM"), uriObject);
intentObject.Call<AndroidJavaObject>("putExtra", intentClass.GetStatic<string>("EXTRA_TEXT"), textToShare + shareLink);
intentObject.Call<AndroidJavaObject>("putExtra", intentClass.GetStatic<string>("EXTRA_SUBJECT"), ShareSubject);
intentObject.Call<AndroidJavaObject>("setType", "image/png");
AndroidJavaClass unity = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject currentActivity = unity.GetStatic<AndroidJavaObject>("currentActivity");
currentActivity.Call("startActivity", intentObject);
}
yield return null;
}
Unity3d share image on android
You can directly pass the byte array, no need to convert it to file -> uri -> string
Below are java code, but you can easily translate this to JNI wrapper calls
Bundle bundle = new Bundle();
bundle.putByteArray("byteArr", imageBytes); //put byte array to bundle!!!
Intent intent = new Intent(...);
intent.putExtra(bundle );
To retrieve the image byte array in another activity, use below code:
getIntent().getByteArrayExtra("byteArr");
If you wrap each above function calls into a corresponding JNI function, it would be very tedious. You can on the other hand:
Create an android library project
Add two static java functions, one is saveByteArrayToBundle(...), and the other is getByteArrayFromBundle(...)
Compile the android library into an aar file;
then put the aar file into the Assets/ folder (actually any subfolders will do)
Then call the two static java functions as you have done in the OP
Refer to below tutorials if you need to go through step-by-step:
Step-by-Step guide for developing Android Plugin for Unity3D (I)
Step-by-Step guide for developing Android Plugin for Unity3D (II)
After clicking a button in my app, it creates new normal Thread and start downloading large image and saving it to file. Everything is going well, but when i click button more than once it's going without errors and when i try to view these images they're bugged like they re overwriting themself.
I don't have any idea how to debug it.
localPath = today + "/" + productCode + "/" + this.placeId; //Unique
/* ... */
private void productSave(String productCode, int whichCamera, boolean isError) {
for (int i = position; i < lastCamera; i++) {
Date dateSave = new Date();
path = localPath + "/" + dateFormat.format(dateSave) + "_" + (i + 1) + ".jpg";
try {
BufferedImage imageOld = ImageIO.read(new URL(this.camerasUrlsToSave[i]));
ImageIO.write(imageOld, "jpg", new File(rootPath + "/" + path));
ComDb.getInstance().saveProduct(productCode, this.placeId, path, dateSave);
} catch (IOException ex) {
result = false;
}
}
}
EDIT: path is 100% unique (different folders with product code). And it shoudn't be problem with image from camera - I can open 10 cards i dont see image bugs
EDIT2: Can it be something like downloading Img bufor? Cause all images are downloaded from the same IP. Or maybe its problem with bufferedimg memory leaks. Need idea how to repair it.
EDIT3: I found that if i open 5 cards in web browser with my camera address like : blah.blah.some.ip/GetImage.cgi?CH=0 They're loading one after the other, not all at once. But, i dont see bugged images when downloading ends.
EDIT4: I tried to reproduce this bug in web browser, if i try to open link in ff and in IE. IE prints "getImage busy". When I try ff and chrome i got broken images. So i have to do sth like queue or disable button ...
EDIT5: My temporary solution: synchronized function productSave. Images from second click will be saved few seconds later.
http://oi57.tinypic.com/ofrrn.jpg!
One from saved Images
First action of the click event for the button should be to disable the button and maybe change the text to "In process". Last action should be to re-enable the button and restore the text.
This answer is a guess as you have not given full code, issue could be with variable i - where is it from?
Or could be same file name is being reused, mnake sure that is nto the case by getting unique file name from a seperate function something like this:
if dateFormat is only to minute or second, same file name might be used for 2 images use this API of java.io.File to get a unique name
http://docs.oracle.com/javase/7/docs/api/java/io/File.html#createTempFile%28java.lang.String,%20java.lang.String,%20java.io.File%29
public static File createTempFile(String prefix,
String suffix,
File directory)
//you can pass extn as jpg
public File getFileName(File localPath ,Date dateSave, int i, String extn){
File fileUniqe = File.createTempFile(dateSave + "_" + (i+1), extn, localPath );
return fileUniqe,
}
I have a little bit strange question: this time everything works, but I can't understand why.
AFAIK it's possible to mount more than one sd card. Everything will be mounted to /mnt directory. (is it true?)
On my device there is only one sd card which mounted to /mnt/sdcard. And in my application I open files from it. I'm using next code:
private void open() {
// get file extension
String extension = "";
int dotIndex = downloadedFile.lastIndexOf('.');
if (dotIndex != -1) {
extension = downloadedFile.substring(dotIndex + 1, downloadedFile.length());
}
// create an intent
Intent intent = new Intent(android.content.Intent.ACTION_VIEW);
Uri data = Uri.fromFile(new File(downloadedFile));
String type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
if (type == null || type.length() == 0) {
// if there is no acceptable mime type
type = "application/octet-stream";
}
intent.setDataAndType(data, type);
// get the list of the activities which can open the file
List resolvers = context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
if (resolvers.isEmpty()) {
(new AlertDialog.Builder(context)
.setMessage(R.string.AttachmentUnknownFileType)
.setNeutralButton(R.string.NeutralButtonText, null)
.create()).show();
} else {
context.startActivity(intent);
}
}
Actually downloadedFile variable has value like file:///sdcard/mydir/myfile.txt. But the code works. Why? How Android understand what /sdcard/... is the same as /mnt/sdcard/...?
And main question: what happened if sd card will be mounted to other dir (for exmaple, /mnt/another-sd/ or even /media/sd)? What if more than one sd cards will be mounted: how android understand what card to use?
Thank you for any help! Have a good day!
It's simple android configueres the mounting over a settings file on phone boot so if there are mor sdcards Android will simply prefer one of them to set as
/sdcard/
so when the mount settings change your code is simply useless you can only hope the settings being untouched .
Every company that procuces Android smartphones use the "sdcard" path even custom roms like use it