Getting videos(non-local) from the Google Photos App - android

With the Google Photos app, I am trying to pick a video, that is not cached on the device.
I am using the ACTION_GET_CONTENT intent, to launch the options dialog, and from there I choose the Google Photos app.
While selecting local videos, it returns an Uri in this form.
content://media/external/video/media/6708
And from that, I query the content provider to retrieve the actual file location, and proceed from there. The file location looks like this.
/storage/emulated/0/WhatsApp/Media/WhatsApp
Video/VID-20131102-WA0000.mp4
Now, when I choose an online video, i.e: a video not available on my device yet, and which needs to be downloaded to be used, the returned Uri looks like this:
content://com.google.android.apps.photos.content/1/https://lh6.googleusercontent.com/_RD-QTO_SK5jlaPldTe2n5GANqMc3h-ukcbNoFlF1NLy=s0-d
Now, with this, there is no documented ContentProvider that would help me to get the actual link to this video. Even if I do a query, it returns nothing apart from a DISPLAY_NAME and SIZE columns.
DISPLAY_NAME contains video.mpeg (Same display name for different videos)
SIZE probably tells me the size of the actual file.
Referred to this post on SO.
I checked various posts, and thought that I would have to get an InputStream for the video through the content provider, save the file, and work with the file. Picking an image file however works fine, but with video it doesn't.
So, to copy the stream to a file, I have this code.
InputStream inputStream = context.getContentResolver().openInputStream(Uri.parse(path));
And finally write to a temporary file. The file gets created, but that doesn't seem to be correctly formatted. VLC plays the file, but shows only the first frame all throughout.
If I take the URL from the last part of the URI given above, and try to view it on a browser, it downloads a GIF file. I am guessing that's the problem. But I don't know how to get the mpeg format of the video.
Anyone has experienced the same?

Finally found the solution to the problem. This would work for both images and videos.
Referenced this video:
DevBytes: Android 4.4 Storage Access Framework: Client
https://www.youtube.com/watch?v=UFj9AEz0DHQ
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
startActivity(intent);
Get the Uri, and access and save the file like this:
ParcelFileDescriptor parcelFileDescriptor = context.getContentResolver()
.openFileDescriptor(Uri.parse(path),"r");
FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
InputStream inputStream = new FileInputStream(fileDescriptor);
BufferedInputStream reader = new BufferedInputStream(inputStream);
// Create an output stream to a file that you want to save to
BufferedOutputStream outStream = new BufferedOutputStream(
new FileOutputStream(filePath));
byte[] buf = new byte[2048];
int len;
while ((len = reader.read(buf)) > 0) {
outStream.write(buf, 0, len);
}
For some reason, getting an input stream without using a ParcelFileDescriptor doesn't work.

Related

How to correctly send audio files to Google Speech API?

I'm trying to implement Google Speech API in Android by following this demo: https://github.com/GoogleCloudPlatform/android-docs-samples
I was able to successfully reproduce the example in my app by using the given "audio.raw" file located in R.raw, and everything works perfectly. However, when I try to use my own audio files, it returns "API successful" without any transcription text. I'm not sure if it has to do with the files' path or the encoding, so I'll include information on both just in case.
Encoding
My audio files are obtained by recording a voice through MediaRecorder. These are the settings:
myAudioRecorder = new MediaRecorder();
myAudioRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
myAudioRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
myAudioRecorder.setAudioEncoder(MediaRecorder.OutputFormat.AMR_WB);
myAudioRecorder.setAudioSamplingRate(16000);
myAudioRecorder.setAudioEncodingBitRate(16000);
myAudioRecorder.setAudioChannels(1);
myAudioRecorder.setOutputFile(outputFile);
SpeechService's recognizeInputStream() function in the API:
mApi.recognize(
RecognizeRequest.newBuilder()
.setConfig(RecognitionConfig.newBuilder()
.setEncoding(RecognitionConfig.AudioEncoding.AMR_WB) //originally it was LINEAR16
.setLanguageCode("en-US")
.setSampleRateHertz(16000)
.build())
.setAudio(RecognitionAudio.newBuilder()
.setContent(ByteString.readFrom(stream))
.build())
.build(),
mFileResponseObserver);
Encoding guidelines by Google: https://cloud.google.com/speech/docs/best-practices
From what I understand, I can use AMR_WB and 16kHz instead of the default LINEAR16, I'm just not sure if I'm doing it right.
Path
This is the example that is fully working (with the audio file from the repo):
mSpeechService.recognizeInputStream(getResources().openRawResource(R.raw.audio));
However, none of the following options work, even with the exact same file:
InputStream inputStream = new URL("[website]/test/audio.raw").openStream();
mSpeechService.recognizeInputStream(inputStream);
Neither:
Uri uri = Uri.parse("android.resource://[package]/raw/audio");
InputStream inputStream = getActivity().getContentResolver().openInputStream(uri); //"getActivity()" because this is in a Fragment
mSpeechService.recognizeInputStream(inputStream);
To be clear, the result on the above paths is the same as on my custom audio files: "API successful" with no transcription. One of the options I have tried for my custom audio files, with the same thing happening, is this:
FileInputStream fis = new FileInputStream(filePath);
mSpeechService.recognizeInputStream(fis);
The only reason I'm not 100% sure the problem is in the path is because if the API is returning with success, then the file was found in the specified path. The problem should be the encoding, but then it's weird that the same file ("audio.raw") sent in different ways produces different results.
Anyway, thank you in advance! :)
EDIT:
To be clear, it's not that it returns an empty string in the transcription. It just never enters the "onSpeechRecognized" function that also exists in the demo, so no transcription is given.

Parse error when trying toprogrammatically install APK from android app

To be as succinct as possible:
-APK file is not corrupt.
-I can browse to the APK in the phone's file system and manually install it from there without issue.
-I am using the following code to kick off the install process. File location is confirmed correct:
public void installfromlocal()
{
String downloadfilelocation = getsharedresourcestring("updatepackagelocation");
Log.e("installing from",downloadfilelocation);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(new File(downloadfilelocation)), "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
So far what I could gather from a couple hours on the internet is that apparently I can't make my app install an APK programmatically from external storage. I can also apparently not copy the file to internal storage and install from there.
So what now? Additionally, I get no messages from Logcat. I only get a popup alerting me that there was an error parsing the apk.
I found a solution for me (not so clear why have this issue, but i solve it).
It seems to me that when downloading with DownloadManager you cant access to the downloaded file via URI, and you get access denied (and various file not found exception error) that's why PackageInstaller cannot read at all the manifest (and that's the parse error).
This is what i did, i hope that resolve you problem as well, i know it's not elegant to say the least.
Because of DownloadManager.COLUMN_LOCAL_FILENAME is deprecated i tried with COLUMN_LOCAL_URI to access the file and access its content (q is Cursor)
String strUri = q.getString(q.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
Uri apkUri = Uri.parse(strUri);
with this uri i can access and copy the file to a temp file in getExternalCacheDir()
ParcelFileDescriptor pfd = context.getContentResolver().openFileDescriptor(apkUri, "r");
InputStream inFile = new FileInputStream(pfd.getFileDescriptor());
OutputStream outFile = new FileOutputStream(tmpFile);
//copy
byte[] buffer = new byte[1024];
int length;
while ((length = inFile.read(buffer)) > 0) {
outFile.write(buffer, 0, length);
}
outFile.flush();
inFile.close();
outFile.close();
Grab the file created and get its uri (that is accessible) and start the activity with that uri.
I hope it helps
You should use canonical path of the file. From the docs-
A canonical pathname is both absolute and unique. The precise definition of canonical form is system-dependent. This method first converts this pathname to absolute form if necessary, as if by invoking the getAbsolutePath() method, and then maps it to its unique form in a system-dependent way. This typically involves removing redundant names such as "." and ".." from the pathname, resolving symbolic links (on UNIX platforms), and converting drive letters to a standard case (on Microsoft Windows platforms).

How to get writable DocumentFile Uri from a Media real path?

I have a situation in Lollipop where I have:
Directory tree (DocumentFile) which is granted from user.
A collection of audio files that need to modify retrieved from media provider.
Uri mediaUri = Uri.withAppendedPath(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
"45");
Then, how to write a stream into one of those files?
I think, this https://stackoverflow.com/a/30514269/615025 gives a work around. Copy bytes of the file to cache directory, do modification on the temporary file and then copy the bytes back to the original file.
DocumentFile is a new mechanism which allows us to modify files in Lollipop. It is not the same case with this post how to get contact photo URI
Thanks
You can open an outputStream directly from a Uri using ContentResolver.openOutputStream(Uri)
For example,
OutputStream fos;
fos = new BufferedOutputStream(context.getContentResolver().openOutputStream(uri));
Optionally, openOutputStream takes a string to specify mode.
i.e
openOutputStream(uri, "w");
to write or
openOutputStream(uri, "wa");
to append.

Copying resource file to external storage on android not working

I'm working on a mediaplayer application and am trying to have some default songs get put on the phone in case the user doesn't have any on their phone (I'm pulling the list of actual songs via mediastore).
So I have the songs put in the res/raw folder and fun the following code to copy them. It seems to be copying ok (since astro file browser and other apps see them fine) but the mediastore still can't find them.
I think it's something with the permissions on the file but I'm not sure what. Anybody know why?
InputStream song = getResources().openRawResource(R.raw.aquarel);
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC), "aquarel.mp3");
Log.e(TAG, "File1: " + file.getPath());
OutputStream copySong = new FileOutputStream(file);
byte[] buffer = new byte[1024];
int readvalue = 0;
readvalue = song.read(buffer);
while (readvalue > 0) {
copySong.write(buffer, 0, readvalue);
readvalue = song.read(buffer);
}
copySong.close();
"When you add files to Android’s filesystem these files are not picked
up by the MedaScanner automatically.
...
If you want your files to be added to the media library, you can do so
either by using the MediaStore content provider, or by using the
MediaScanner."
You can add them by sending a broadcast:
Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
intent.setData(Uri.fromFile(file));
sendBroadcast(intent);
(Source)

How to get file bytes with Dropbox Chooser for Android

I am using Dropbox chooser for Android.
mDropboxChooser.forResultType(DbxChooser.ResultType.FILE_CONTENT)
.launch(SendActivity.this,
DBX_CHOOSER_REQUEST_CODE);
and in onActivityResult I get the url
DbxChooser.Result result = new DbxChooser.Result(data);
Uri u = result.getLink();
but I am not sure how can I get file bytes using this Uri.
Adding Andy Res's answer as an answer, because he's right. :-)
I think you are supposed to use that Uri to open an input stream
connection, that is from where you'll get the bytes, presumably making
a HttpUriRequest.
EDIT
Also note that you should get a "direct" link, not a "preview" link if you want to download the file contents.

Categories

Resources