Why does MediaPlayer not prepare? - java

I'm using MediaPlayer to load an mp3 file and play it online. I am using this code:
try{
Log.i("tag1", "try");
mediaPlayer.setDataSource(activity.this, Uri.parse("link"));
mediaPlayer.prepareAsync();
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mediaPlayer) {
Log.i("tag2", "" + mediaPlayer.getDuration());
}
});
} catch(IOException e) {
e.printStackTrace();
}
Most of the times nothing is prepared, so I have the log.i results as below:
tag1 = try
tag2 is never executed
If, sometimes only, mediaPlayer is prepared, I get these logs:
tag1 = try
tag2 = 0 _ which is neither acceptable nor usable
Also, when I call mediaPlayer.setOnErrorListener, I get errors 1,-1004 or 1,-2147483648. Additionally, mediaPlayer.setOnInfoListener gives nothing; I think it's never called...
What could be the problem?
It is not unnecessary to mention that in the log folder of the server's file manager, I found this: "stagefright/1.2 (Linux; Android 4.4.4)". I think this could help to solve the problem. Also, related to this, can the problem be caused by PHP extensions? if yes, activating which extension solves this issue?
Any help is really appreciated.

You have a MEDIA_ERROR_IO. As the documentation says it's for File or network related operation errors.
In most cases the problem is in the implementation of the MediaPlayer class or maybe in android 4 as mentioned here
I would recommend you ExoPlayer, instead.

You are missing mediaPlayer.start() in your MediaPlayer.OnPreparedListener(). See attached kotlin code for an extending class with example http request
Error 1004: Source not found (f.e. wrong path or no stream at url)
Error 2147483648: Media format not supported at your device
Another mention: keeping references for audiofiles on device system needs persistable uri permission
Here's stripped down code for starting a radio stream in kotlin with OkHttp
class MyPlayer: MediaPlayer(), MediaPlayer.OnPreparedListener {
fun playStream() {
try {
val uri = Uri.parse( [URL] )
//check if url valid
val client = OkHttpClient()
val request = Request.Builder().url( [URL] ).build()
val newCall = client.newCall(request).execute()
if (newCall.code() != 200) {
//handle error for stream, stream not broadcasting
return
}
val headers = HashMap<String, String>()
headers.put("User-Agent", " [SOME AGENT] ")
setDataSource(context, uri, headers)
prepareAsync()
} catch (e: Exception) {
L.e("Url Parsing failed for ${e.message}")
setInternalState(State.Error, StreamErrorMapping.ShoutCastError)
}
}
}
override fun onPrepared(player: MediaPlayer) {
player.start() //<-- this call is missing in your code
}
By the way, like Ezaldeenn sahb already mentioned, I would also recommend using ExoPlayer, since it's way more faster than MediaPlayer! In my projects buffering went down from 2-4seconds (MediaPlayer) to 200ms (Exoplayer). Happy coding

It seems your problem is because of using http links instead of https. Add android:usesCleartextTraffic="true" to your manifest application tag like so:
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:usesCleartextTraffic="true"
android:theme="#style/AppTheme"
>
...
</application>
Also, don't forget to use internet permission.

Of course, I thank all my friends who put their most effort to answer this problem of mine, but none of them solved the main issue.
How I came to find a way to get rid of this situation:
I tried another Host for my files and it worked. So I decided to move all my data and databases to another Host.

Related

Is it impossible to call mediaplayer.setpreparedlistener when mediapler.create method is used?

I'm trying to learn kotlin with a media player project in Android studio.
So I create a media player using create method.
val mediaplayer : MediaPlayer
mediaplayer= MediaPlayer.create(this,R.raw.song)
mediaplayer.start()
But the problem come when I use this:
mediaplayer.setOnPreparedListener(object: MediaPlayer.onPreparedListener{
override fun onPrepared(MediaPlayer mp){
val max = mp.max
Seekbar.max = max
textview.text = convertToSeconde(max) // a function I define
mp.start()
}
})
The problem is that, when I run the app my implementation of onpreparedlistener have never been called. And any error is raise to tell me what the cause.
Can you help me on this please?
No. It is not possible. But, why do you want to do so? It is prepared immediately after that file is created. But, in some cases it might not get prepared due to some issue with the file or uri. So, you can use this alternate after the .create() function:
if(mediaplayer != null){
// it was not created or prepared.
}else{
// good news. it got prepared successfully
}

Android Copy & Paste to any text field in any application

I am developing an app for commercial use with a background service that is getting transponder numbers (of animals) from an RFID reader via bluetooth.
After processing the received number I would like to send it to the clipboard and paste it in the focused text field of whatever application is currently in front which in my case is a browser app.
I already found a similar question from 2013 but with no accepted answer by now. All answers to the question just explained how to use ClipboardManager to copy and paste code within the developed application but that has not been meant by the problem as he clarified in a comment.
The simplest scenario that I could imagine is to just simulate a paste action on the android device. I would prefer not to need to install a third party app.
Just to add to Kirill's answer and assuming the app has Accessibility permission,
Create a class extending AccessibilityService and override onAccessibilityEvent method.
public class SampleAccessibilityService extends AccessibilityService {
#Override
public void onAccessibilityEvent(AccessibilityEvent accessibilityEvent) {
AccessibilityNodeInfo source = accessibilityEvent.getSource();
if (source != null) {
AccessibilityNodeInfo rowNode = getRootInActiveWindow();
if (rowNode != null) {
for (int i = 0; i < rowNode.getChildCount(); i++) {
AccessibilityNodeInfo accessibilityNodeInfo = rowNode.getChild(i);
if (accessibilityNodeInfo.isEditable() && accessibilityNodeInfo.isFocused()) {
accessibilityNodeInfo.performAction(AccessibilityNodeInfoCompat.ACTION_PASTE);
return;
}
}
}
}
}
#Override
public void onInterrupt() {
}
}
accessibilityNodeInfo.performAction(AccessibilityNodeInfoCompat.ACTION_PASTE) will paste the text that is copied to clipboard.
Also make sure you have right accessibility configuration.
config.xml
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:accessibilityFlags="flagDefault"
android:accessibilityEventTypes="typeViewClicked|typeViewFocused"
android:accessibilityFeedbackType="feedbackGeneric"
android:notificationTimeout="0"
android:canRetrieveWindowContent="true"
android:description="#string/testing" />
Here android:accessibilityEventTypes="typeViewClicked|typeViewFocused" will filter the events to view click or view focus.
You can also the events based on the packages using "android:packageNames" (so that your service won't get called often)
Finally declare the service in manifest,
<service android:name=".SampleAccessibilityService"
android:label="#string/app_name"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService"/>
</intent-filter>
<meta-data
android:name="android.accessibilityservice"
android:resource="#xml/config" />
</service>
If you want your app to interact with an app that isn't yours (the browser) you will have to give this app accessibility permissions. those are special kind of permission that allow apps to interact with something that is a bit more senstive.
there are accessibility actions, the one that you are looking for is the
AccessibilityNodeInfoCompat.ACTION_PASTE it allows you to preform a paste into a focused field.
Note that I'd recommend you to replace the browser with a inapp WebView, and inject the values with javascript this will be much more robust solution for your automation. you can find more info on how to run JS on a webview here: How to get return value from javascript in webview of android?

Getting data from a website on to Google Glass

I'm still learning how to extract data from a website and I really hope I'll get some nice answers adequate for a starter. Anyways, my goal here is to extract the data in the background of my app(without openning and showing it in my app). The idea is that data then would be stored for later use.
The API I'm using has 2 GetMethods:
GetProductJSON(which has JSON Response) and GetProduct(with a Comma Seperated Values(CSV) Response)
Here is an example of the JSON Response website:
{"0":{"productname":"Neutrogena Lips Stick 4.8g","imageurl":"http://ecx.images- amazon.com/images/I/31E1ct854gL._SL160_.jpg","producturl":"","price":"5.65","currency":"USD","saleprice":"","storename":"N/A"}}
The Comma Seperated Values Response looks like this:
"productname","imageurl","producturl","price","currency","saleprice","storename"
"Neutrogena Lips Stick 4.8g","http://ecx.images-amazon.com/images/I/31E1ct854gL._SL160_.jpg","","5.65","USD","","N/A"
Here is how I call the website:
url = url.replace("{CODE}", codeValue);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(url));
cardPresenter.setPendingIntent(createPendingIntent(getContext(), intent));
Any suggestions on how to make this a background task and how to actually get the data in java so that I can use them on a Livecard.
First, you need to have access to the Internet. Include the following permission into your AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET" />
Using GDK and AsyncTask:
import android.os.AsyncTask;
public class RetrieveData extends AsyncTask<String, String, String> {
#Override
protected String doInBackground(String... resource) {
String data;
try {
URL url = new URL(resource[0]);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
InputStream in = new BufferedInputStream(connection.getInputStream());
data = convertStreamToString(in);
in.close();
} catch (Exception e) {
e.printStackTrace();
}
return data;
}
private String convertStreamToString(InputStream in) {
Scanner s = new Scanner(in);
return s.useDelimiter("\\A").hasNext() ? s.next() : "";
}
}
The method convertStreamToString() is described there.
In your Service or Activity:
String retrievedData;
try {
retrievedData = new RetrieveData().execute("http://www.example.com/GetProductJSON").get();
} catch (Exception e) {
e.printStackTrace();
}
// Process data
Hope that helps.
You have at least these choices using GDK: 1) create an asynch task; or 2) create a private service that you assign tasks to periodically.
The first thing you will need to do in your Android Application is to add permission to access the Internet in your AndroidManifest.xml file. Add this tag as a sibling of <application>.
<uses-permission android:name="android.permission.INTERNET"/>
You will then need to consider in what manner you will make the HTTP requests. In an ideal application, you need to use the AsyncTask class to make these requests to avoid blocking the UI thread.
If you are just looking for a quick proof of concept, you can permit these requests on the UI thread by modifying your policy. Add this code to your onCreate() method in the MainActivity
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
This is not an advisable long term solution since it blocks the UI thread, but there are StackOverflow topics on it. How to fix android.os.NetworkOnMainThreadException?.
Here is another article on the concept of an AsyncTask http://www.androiddesignpatterns.com/2012/06/app-force-close-honeycomb-ics.html.
Although you seem to be indicating you're using the GDK, you may want to consider a server-push via the Mirror API instead. Since you need to fetch the information via the network anyway, you're losing out on many of the advantages the GDK offers.
With the Mirror API, you would create a new timeline item with timeline.insert and save the id of the card that was created. You would probably want to give your user the option to pin the card so it is placed in the "now" area of the timeline.
When updating, you can call timeline.update with the new information.
Keep in mind that you do need to update the card periodically or it may fall off the timeline or out of the pinned area after seven days of inactivity.

sendBroadCast(Intent.ACTION_MEDIA_MOUNTED) not working [duplicate]

Because I want to make sure the MediaStore has the latest information without having to reboot I'd like to trigger the MediaScanner using the popular way I found on SO
context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED,
Uri.parse("file://" + Environment.getExternalStorageDirectory())));
This works fine on my Samsung S2 w/ICS but not on my Nexus 7 w/JellyBean. Logcat shows this on my Nexus 7:
WARN/ActivityManager(480): Permission denied: checkComponentPermission() owningUid=10014
WARN/BroadcastQueue(480): Permission Denial: broadcasting Intent { act=android.intent.action.MEDIA_MOUNTED dat=file:///storage/emulated/0 flg=0x10 } from com.example.foo.bar (pid=17488, uid=10046) is not exported from uid 10014 due to receiver com.android.providers.downloads/.DownloadReceiver
INFO/ActivityManager(480): Start proc com.google.android.music:main for broadcast com.google.android.music/.store.MediaStoreImportService$Receiver: pid=17858 uid=10038 gids={50038, 3003, 1015, 1028}
INFO/MusicStore(17858): Database version: 50
INFO/MediaStoreImporter(17858): Update: incremental Added music: 0 Updated music: 0 Deleted music: 0 Created playlists: 0 Updated playlists: 0 Deleted playlists: 0 Inserted playlist items: 0 Deleted playlist items: 0 Removed orphaned playlist items: 0
The last line sounds encouraging in theory, but the values are always 0 even after new files had been pushed to the SD card (via adb push). On my older device (S2) it does remount the SD card.
I've added the following permissions to my AndroidManifest.xml but it behaves the same as without those permissions:
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Any ideas/alternatives?
Edit 1:
Note that I don't know any file paths of new or modified or deleted files. I just want to make sure the MediaStore is up-to-date.
Here's the sample code based on CommonsWare's answer:
MediaScannerConnection.scanFile(activity, new String[]{path}, null,
new MediaScannerConnection.OnScanCompletedListener() {
#Override
public void onScanCompleted(final String path, final Uri uri) {
Log.i(TAG, String.format("Scanned path %s -> URI = %s", path, uri.toString()));
}
});
Even though in most of the cases, where one knows the files to be added/updated/etc. to the MediaStore, one should follow CommonsWare's answer, I wanted to post the my solution where I need to do it the rough way because I don't know the file paths. I use this mostly for testing/demoing:
Uri uri = Uri.fromFile(Environment.getExternalStorageDirectory());
activity.sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, uri));
BTW, no permissions are necessary for either solution.
using the popular way I found on SO
Faking ACTION_MEDIA_MOUNTED broadcasts has never been an appropriate solution IMHO.
Any ideas/alternatives?
Use MediaScannerConnection, such as via its scanFile() static method.
My answer is a little late, but it might help those, who save a new file, and would like to extend the media store by just that file on Android Kitkat: On Android Kitkat the intent ACTION_MEDIA_MOUNTED is blocked for non-system apps (I think, because scanning the whole filesystem is pretty expensive). But it is still possible to use the intent ACTION_MEDIA_SCANNER_SCAN_FILE to add a file to the media store:
File f = new File(path to the file you would like to add to the media store ...);
try {
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
Uri uri = Uri.fromFile(f);
mediaScanIntent.setData(uri);
sendBroadcast(mediaScanIntent);
} catch(Exception e) {
...
}

Why doesn't Android's WebView load some URLs?

My WebView doesn't show some URLs especially if it has the leading www. part missing. http://google.com doesn't load but http://www.google.com loads just fine. I don't get any exceptions or messages in the logcat so it seems rather hard to find out what's going on behind the scenes. Here's the snippet that actually displays my WebView.
WebView wbvBrowser = new WebView(this.objContext);
wbvBrowser.getSettings().setBuiltInZoomControls(true);
wbvBrowser.getSettings().setJavaScriptEnabled(true);
wbvBrowser.loadUrl("http://google.com");
Would any of you know what's causing this issue? I'm baffled.
Thanks.
Enable DOM Storage APIs
wbvBrowser.setDomStorageEnabled(true);
Make sure the app has permission to access the Internet. Add the following to AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET" />
try this...
wbvBrowser.setWebViewClient(new Callback());
private class Callback extends WebViewClient{ //HERE IS THE MAIN CHANGE.
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
return (false);
}
}
This worked for me: Add an 's' to the http. Make it https
wbvBrowser.loadUrl("https://google.com");

Categories