I am unable to figure out how to share a video from SnapChat to my app while WhatsApp can do it without problems so it is possible.
Since SnapChat works with a contentprovider I figured I should just query the uri using the android contentresolver method. Using the databaseUtils I dumped the cursor to logcat but all it gives me back is the displayname and the filesize. I see no way how to get the actual file.
Help me out guys. What am I missing?
A bit late but i managed to solve it. Here is the solution. I added comments in the code to explain what i am doing.
void handleSendVideo(Intent intent)
{
// get title
String title = intent.getExtras().getString(Intent.EXTRA_SUBJECT);
// get the uri for the video
mVideoUri = (Uri) intent.getExtras().get(Intent.EXTRA_STREAM);
// check if it originates from snapchat
if (mVideoUri.getAuthority().equals(UriHelper.SNAPCHAT_FILE_PROVIDER))
{
Intent mRequestFileIntent;
ParcelFileDescriptor mInputPFD;
mRequestFileIntent = new Intent(Intent.ACTION_PICK);
mRequestFileIntent.setType("video/*");
// Query the content resolver to get the name of the file. Beware that you will not find
// the actual file here. You must read it from the fileDescriptor.
Cursor fileDataCursor = getContentResolver().query(mVideoUri, null, null, null, null);
String fileName = "";
if (fileDataCursor != null)
{
fileDataCursor.moveToFirst();
fileName = fileDataCursor.getString(0);
fileDataCursor.close();
}
// something is wrong... return
if (fileName.isEmpty())
{
return;
}
try {
// open the file descriptor that belongs to the file given to us by snapchat.
mInputPFD = getContentResolver().openFileDescriptor(mVideoUri, "r");
// fetch the descriptor
FileDescriptor fd = mInputPFD.getFileDescriptor();
// create in input stream from descriptor
InputStream inputStream = new FileInputStream(fd);
// This is the file that will be created
File targetFile = new File(Environment.getExternalStorageDirectory(), fileName);
// Open a outputstream connected to the file
FileOutputStream fileOutputStream = new FileOutputStream(targetFile);
// Create a buffer with a size equal to what is available from the inputstream.
// Note: we dont have to loop here because the file is available on the storage.
byte[] buffer = new byte[inputStream.available()];
// Read all data into the buffer
inputStream.read(buffer);
// Write the buffer to the outputstream
fileOutputStream.write(buffer);
// close all streams, our file is ready.
inputStream.close();
fileOutputStream.close();
mInputPFD.close();
// check if the new file exists.
if (targetFile.exists())
{
// add the file to the android MediaProvider
mVideoUri = addVideo(targetFile);
}
else
{
DialogMaker.showAlertMessage(this, "Could not read video", "unable to read video from SnapChat.", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
finish();
}
});
return;
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
try {
logger.i("videoUri: " + mVideoUri.toString());
logger.i("videoPath: " + mVideoUri.getPath());
} catch (Exception e) {
e.printStackTrace();
}
}
public Uri addVideo(File videoFile) {
ContentValues values = new ContentValues(3);
values.put(MediaStore.Video.Media.TITLE, "My video title");
values.put(MediaStore.Video.Media.MIME_TYPE, "video/mp4");
values.put(MediaStore.Video.Media.DATA, videoFile.getAbsolutePath());
return getContentResolver().insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, values);
}
Related
I have written codes for adding sticker pack dynamically. But I want to know how to update the sticker pack after adding to whatsapp?
I can add sticker file to the pack which is listed on my app only but it is not reflecting in whatsapp. I tried adding files to the same location (file:///...) from where the pack was sent to whatsapp.
I want to try updating content provider. But how to do that? Can I add files to whatsapp's 'content://...' uri or should I update my app's content provider or anything else?
I am using react-native-whatsapp-stickers module for react-native.
react-native code
invoking after adding single sticker from UI
const addOne = (path, packName) =>{
// log('path ',path[0])
// log('packName ',packName)
RNWhatsAppStickers.addSticker(path[0],packName)
.then(res=>RNWhatsAppStickers.send(packName,packName))
.then(res=>console.log('response ',res))
}
Java code of module RNWhatsAppStickers
#ReactMethod
public void send(String identifier, String stickerPackName, Promise promise) {
Intent intent = new Intent();
intent.setAction("com.whatsapp.intent.action.ENABLE_STICKER_PACK");
intent.putExtra(EXTRA_STICKER_PACK_ID, identifier);
intent.putExtra(EXTRA_STICKER_PACK_AUTHORITY, getContentProviderAuthority(reactContext));
intent.putExtra(EXTRA_STICKER_PACK_NAME, stickerPackName);
try {
Activity activity = getCurrentActivity();
ResolveInfo should = activity.getPackageManager().resolveActivity(intent, 0);
if (should != null) {
activity.startActivityForResult(intent, ADD_PACK);
promise.resolve("OK");
} else {
promise.resolve("OK, but not opened");
}
} catch (ActivityNotFoundException e) {
promise.reject(ERROR_ADDING_STICKER_PACK, e);
} catch (Exception e) {
promise.reject(ERROR_ADDING_STICKER_PACK, e);
}
}
// saving image to same pack
public static void SaveImage(Bitmap finalBitmap, String name, String identifier) {
String root = path + "/" + identifier;
File myDir = new File(root);
myDir.mkdirs();
String fname = name;
File file = new File(myDir, fname);
if (file.exists()){
// Log.d("ReactNative","root "+root);
file.delete();
}
try {
FileOutputStream out = new FileOutputStream(file);
finalBitmap.compress(Bitmap.CompressFormat.WEBP, 90, out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
Please give any idea what to do? Thanks
I found the solution on official doc. You have to increase the image_data_Version for that pack after adding new images.
To track the image_data_Version you can query the ContentProvider of your app or Store the image_data_Version somewhere and make changes accordingly .
I'm developing image editor app.. so each time the user have to save the image.
So first i inserted
String savedImageURL = MediaStore.Images.Media.insertImage(
getContentResolver(),
bitmap,
"Bird",
"Image of bird"
);
this code, but it creating new file instead of overwriting.
So i use another method
public String saveImage(String folderName, String imageName) {
String selectedOutputPath = "";
if (isSDCARDMounted()) {
File mediaStorageDir = new File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), folderName);
// Create a storage directory if it does not exist
if (!mediaStorageDir.exists()) {
if (!mediaStorageDir.mkdirs()) {
Log.d("PhotoEditorSDK", "Failed to create directory");
}
}
// Create a media file name
selectedOutputPath = mediaStorageDir.getPath() + File.separator + imageName;
Log.d("PhotoEditorSDK", "selected camera path " + selectedOutputPath);
File file = new File(selectedOutputPath);
try {
FileOutputStream out = new FileOutputStream(file,true);
if (parentView != null) {
parentView.setDrawingCacheEnabled(true);
parentView.getDrawingCache().compress(Bitmap.CompressFormat.JPEG, 80, out);
}
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return selectedOutputPath;
}
But it also didn't work.
Does anyone know about overwrite a bitmap in the same name?
Pass false as 2nd argument, to set append to false, so that you will overwrite the existing file:
FileOutputStream out = new FileOutputStream(file,false);
Check out the constructor documentation:
here is your code:
public String saveImage(String folderName, String imageName) {
String selectedOutputPath = "";
if (isSDCARDMounted()) {
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), folderName);
// Create a storage directory if it does not exist
if (!mediaStorageDir.exists()) {
if (!mediaStorageDir.mkdirs()) {
Log.d("PhotoEditorSDK", "Failed to create directory");
}
}
// Create a media file name
selectedOutputPath = mediaStorageDir.getPath() + File.separator + imageName;
Log.d("PhotoEditorSDK", "selected camera path " + selectedOutputPath);
File file = new File(selectedOutputPath);
if (file.exists())
{
try {
file.delete();
} catch (IOException e) {
e.printStackTrace();
}
}
try {
file.createNewFile();
FileOutputStream out = new FileOutputStream(file,false);
if (parentView != null) {
parentView.setDrawingCacheEnabled(true);
parentView.getDrawingCache().compress(Bitmap.CompressFormat.JPEG, 80, out);
}
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return selectedOutputPath;
}
I also had this situation, but it turns out that this is not a problem with saving, but with displaying in ImageViev. I used Glide, and it turns out to be stored in the cache when outputting. And I did not change the name and path of the file. That is, I rewrote them. But Glide did not know this. He thought they were the same file. To fix this problem, I added the following
Glide.with(context)
.load(file)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.skipMemoryCache(true)
.into(view)
If you also have this situation and these solutions helped you, I'm glad to this.
I'm trying to copy files from the assets folder to the device folder using this function:
public static void copyJSON(Context aContext) {
AssetManager assetManager = aContext.getResources().getAssets();
String[] pFiles = null;
try {
pFiles = assetManager.list("ConfigurationFiles");
} catch (IOException e) {
Log.e("tag", "Failed to get asset file list.", e);
}
if (pFiles != null) for (String pJsonFileName : pFiles) {
InputStream tIn = null;
OutputStream tOut = null;
try {
tIn = assetManager.open("ConfigurationFiles" + File.separator + pJsonFileName);
String[] pList = aContext.getFilesDir().list(); //just for test
File pOutFile = new File(aContext.getFilesDir(), pJsonFileName);
tOut = new FileOutputStream(pOutFile);
if (pOutFile.exists()) {
copyFile(tIn, tOut);
}
} catch (IOException e) {
Log.e("tag", "Failed to copy asset file: " + pJsonFileName, e);
} finally {
if (tIn != null) {
try {
tIn.close();
} catch (IOException e) {
Log.e("tag", "Fail closing", e);
}
}
if (tOut != null) {
try {
tOut.close();
} catch (IOException e) {
Log.e("tag", "Fail closing", e);
}
}
}
}
}
If I delete the App and run the code, the variable pList is empty as I expect but the pOutFile.exists()returns true ALWAYS!!.
I don't want to copy them again every time I open my App, and I'm doing this because all my app uses JSON to navigate thru all the screens, so If I change any value in my BBDD a WS send a new JSON file and the App respond in accordance for example a button is no longer needed, so the first time you download my App I copy the original JSON and then if you use the app an if you have internet connection you will download a new JSON file that it is more accurate than the one that is in the Bundle and it will be override, this is because as far as I know I can't change the files that are in the assets folder.
I have read everywhere and all say the same use this:
File pOutFile = new File(aContext.getFilesDir(), pJsonFileName);
And then ask for this:
pOutFile.exists()
I don't know what I'm doing wrong.
Thanks for all your help.
put it this way:
File pOutFile = new File(aContext.getFilesDir(), pJsonFileName);
if (pOutFile.exists()) {
tOut = new FileOutputStream(pOutFile);
copyFile(tIn, tOut);
}
and everything should work fine. Remember the FileOutputStream creates the file it should stream to if possible and non existing
The problem is you're essentially creating a file and then checking if it exists.
try {
tIn = assetManager.open("ConfigurationFiles" + File.separator + pJsonFileName);
String[] pList = aContext.getFilesDir().list(); //just for test
File pOutFile = new File(aContext.getFilesDir(), pJsonFileName);
// See here: you're creating a file right here
tOut = new FileOutputStream(pOutFile);
// And that file will be created in the exact location of the file
// you're trying to check:
if (pOutFile.exists()) { // Will always be true if FileOutputStream was successful
copyFile(tIn, tOut);
}
}
You should instead create your FileOutputStream AFTER you've done your existence check.
Source: http://docs.oracle.com/javase/7/docs/api/java/io/FileOutputStream.html
A file that you have just created without getting an exception always exists. The test is pointless. Remove it.
I'm trying to generate a simple PDF and have it passed over to Google Cloud Print, but nothing happens when I try printing the PDF to my google drive. (Login works)
How would I even authenticate that my PDF is whole and valid, for starters? I feel like I'm taking iText's word for it.
Also, I get some error telling me that
public class PDFViewer extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
this.getWindow().setSoftInputMode
(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
super.onCreate(savedInstanceState);
InputStream object = this.getResources().openRawResource(R.raw.itextkey);
LicenseKey.loadLicenseFile(object);
File root = Environment.getExternalStorageDirectory();
File f = new File(android.os.Environment.getExternalStorageDirectory()
.getAbsolutePath() + java.io.File.separator + "HelloWorld.pdf");
boolean externalStorageAvailable = false;
boolean externalStorageWriteable = false;
String state = Environment.getExternalStorageState();
// if we can read and write to storage
if (Environment.MEDIA_MOUNTED.equals(state)) {
externalStorageAvailable = true;
externalStorageWriteable = true;
}
// else if we can read but cannot write
else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
externalStorageAvailable = true;
externalStorageWriteable = false;
}
if (externalStorageWriteable) {
System.out.println("enough storage!");
// creation of a document-object
Document document = new Document();
try {
// we create a writer that listens to the document
// and directs a PDF-stream to a file
if (f.exists())
f.delete();
try {
f.createNewFile();
} catch (IOException e) {System.out.println(e);}
PdfWriter.getInstance(document, new FileOutputStream
(android.os.Environment.getExternalStorageDirectory()
.getAbsolutePath() + java.io.File.separator + "HelloWorld.pdf"));
// open + format the document
document.open();
document.add(new Paragraph("Hello World"));
} catch (DocumentException de) {
System.err.println(de.getMessage());
} catch (IOException ioe) {
System.err.println(ioe.getMessage());
}
document.close();
}
Intent printIntent = new Intent(this, PrintDialogActivity.class);
Uri hello = Uri.fromFile(f);
printIntent.setDataAndType(hello, "application / pdf");
printIntent.putExtra("title", "stuff");
startActivity(printIntent);
I get this error which I have 0 idea what to do about:
04-29 03:41:18.502: E/chromium(749): external/chromium/net/disk_cache
/backend_impl.cc:1107: [0429/034118:ERROR:backend_impl.cc(1107)]
Critical error found -8
I'd like to know what I can try to play with to get this working. The PrintDialogActivity is stock from Google's website , by the way. I turned off Exchange in App settings, I've allowed external storage to be written to in the manifest, and internet has also been enabled.
Thanks
I had this same problem until I found the solution on the Android developer website: http://developer.android.com/guide/webapps/webview.html.
The targetSdkVersion in your app's AndroidManifest.xml is probably set to 17 or higher. In that case, you need to make a small change to the PrintDialogActivity that you got from the Google Developer website. You need to add the annotation, #JavascriptInterface to the public methods in the PrintDialogJavaScriptInterface class.
final class PrintDialogJavaScriptInterface
{
#JavascriptInterface
public String getType()
{
return cloudPrintIntent.getType();
}
#JavascriptInterface
public String getTitle()
{
return cloudPrintIntent.getExtras().getString("title");
}
#JavascriptInterface
public String getContent()
{
try
{
ContentResolver contentResolver = getContentResolver();
InputStream is = contentResolver.openInputStream(cloudPrintIntent.getData());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[4096];
int n = is.read(buffer);
while (n >= 0)
{
baos.write(buffer, 0, n);
n = is.read(buffer);
}
is.close();
baos.flush();
return Base64.encodeToString(baos.toByteArray(), Base64.DEFAULT);
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
return "";
}
#JavascriptInterface
public String getEncoding()
{
return CONTENT_TRANSFER_ENCODING;
}
#JavascriptInterface
public void onPostMessage(String message)
{
if (message.startsWith(CLOSE_POST_MESSAGE_NAME))
{
finish();
}
}
}
I'm trying to write a file from an Http post reply to a file on the sdcard. Everything works fine until the byte array of data is retrieved.
I've tried setting WRITE_EXTERNAL_STORAGE permission in the manifest
and tried many different combinations of tutorials I found on the net.
All I could find was using the openFileOutput("",MODE_WORLD_READABLE) method, of the activity but how my app writes file is by using a thread. Specifically, a thread is invoked from another thread when a file has to be written,
so giving an activity object didn't work even though I tried it.
The app has come a long way and I cannot change how the app is currently written.
Please, someone help me?
CODE:
File file = new File(bgdmanip.savLocation);
FileOutputStream filecon = null;
filecon = new FileOutputStream(file);
byte[] myByte;
myByte = Base64Coder.decode(seReply);
bos.write(myByte);
filecon.write(myByte);
myvals = x * 11024;
bgdmanip.savLocation holds the whole files path. seReply is a string reply from HttpPost response. The second set of code is looped with reference to x. The file is created but remains 0 bytes.
//------------------------------WRITING DATA TO THE FILE ---------------------------------
btnWriteSDFile.setOnClickListener(new OnClickListener()
{
public void onClick(View v)
{
try {
File myFile = new File("/sdcard/mysdfile.txt");
myFile.createNewFile();
FileOutputStream fOut = new FileOutputStream(myFile);
OutputStreamWriter myOutWriter =new OutputStreamWriter(fOut);
myOutWriter.append(txtData.getText());
myOutWriter.close();
fOut.close();
Toast.makeText(v.getContext(),"Done writing SD 'mysdfile.txt'", Toast.LENGTH_SHORT).show();
txtData.setText("");
}
catch (Exception e)
{
Toast.makeText(v.getContext(), e.getMessage(),Toast.LENGTH_SHORT).show();
}
}
});
//---------------------------READING DATA FROM THE FILE PLACED IN SDCARD-------------------//
btnReadSDFile.setOnClickListener(new OnClickListener()
{
public void onClick(View v)
{
try {
File myFile = new File("/sdcard/mysdfile.txt");
FileInputStream fIn = new FileInputStream(myFile);
BufferedReader myReader = new BufferedReader(new InputStreamReader(fIn));
String aDataRow = "";
String aBuffer = "";
while ((aDataRow = myReader.readLine()) != null)
{
aBuffer += aDataRow ;
}
txtData.setText(aBuffer);
myReader.close();
Toast.makeText(v.getContext(),"Done reading SD 'mysdfile.txt'",Toast.LENGTH_SHORT).show();
}
catch (Exception e)
{
Toast.makeText(v.getContext(), e.getMessage(),Toast.LENGTH_SHORT).show();
}
}
});
ALONG WITH THIS ALSO WRITE THIS PERMISSION IN Android.Manifest
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
The openFileOutput() method writes data to your application's private data area (not the SD card), so that's probably not what you want. You should be able to call Environment.getExternalStorageDirectory() to get the root path to the SD card and use that to create a FileOutputStream. From there, just use the standard java.io routines.
Here is a sample:
// Log used as debug
File log = new File(Environment.getExternalStorageDirectory(), "Log.txt");
try {
out = new BufferedWriter(new FileWriter(log.getAbsolutePath(), false));
out.write(new Date().toString());
out.write(" : \n");
} catch (Exception e) {
Log.e(TAG, "Error opening Log.", e);
}