I'm working on an application that which is media player.
Question: How do I make media player (application) work without issues from turning the screen off?
Question: loadInBackground() returns the uri but onLoadFinished not called when screen off.
Few words to explain trouble better:
The media player contains Loader which loads the song and another Loader which loads related suggestions. I've also implemented the method to play_next() which relies on a listener of media player on finished (button in right upper corner).
The media player is initialized in the service class which I've made so the user can search new songs, and prepare the next_song() with the button (and the playing continues because I connect to service each time Activity is loaded and I return from service media player so I can attach listener for onFinish method).
The thing that bothers me is that when the user turns off the screen, the activity goes to idle state (status from android monitor - log cat) and once in idle state (aka turned off screen) if the song ends, it will start new intent which is media player to start initializing and auto-playing song. It works when the screen is on but it doesn't if it goes to idle state.
If I turn on the screen I get activity to act like this:
Little pink dot is a progress bar. So the activity tries to refresh itself?
In the onCreate() method I call start_loader which initializes and does the things with Loader.
I've seen some power manager tools and seen the bad comments about it which imply to the battery usage but I did try it and from log cat it just went to idle state again (if it matters).
Help please, maybe if I override onPause() Activity and onResume()?
Also i get message from loadInBackground() which is uri from song and from there on it freezes doesn't continue.
you need to create Service for that that run on Background.so when you play song don'tstop if you keep you screen off.Service in Android
upper link perfectly describe service.
example of service ...
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Build;
import android.os.IBinder;
import android.support.annotation.RequiresApi;
import android.util.Log;
import android.widget.Toast;
import com.example.divyesh.musiclite.Pojos.SongsList;
import java.io.File;
import java.io.IOException;
/**
* Created by Divyesh on 11/18/2017.
*/
public class MediaSongServiece extends Service {
SongsList s;
private static Boolean destroy = false;
private String TAG = "HELLO";
private MusicIntentReceiver reciever;
private SharedPreferences prefrence;
private static MediaPlayer player;
private int thisStartId = 1;
private String ss[];
SharedPreferences.Editor editor;
public IBinder onBind(Intent arg0) {
return null;
}
public static void requestPlayMedia() {
player.start();
}
public void requestPauseMedia() {
player.pause();
}
#Override
public void onCreate() {
super.onCreate();
reciever = new MusicIntentReceiver();
IntentFilter filter = new IntentFilter(Intent.ACTION_HEADSET_PLUG);
registerReceiver(reciever, filter);
Log.d("service", "onCreate");
}
#Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
stopSelf();
}
#Override
public boolean onUnbind(Intent intent) {
stopSelf(thisStartId);
return super.onUnbind(intent);
}
public void onStart(Intent intent, int startId) {
if (intent.equals(null)) {
stopSelf();
}
if (destroy == false) {
thisStartId = startId;
ss = intent.getExtras().getStringArray("getArray");
Log.e(TAG, "onStart: " + ss[0] + ss[1] + " path" + ss[5]);
s = new SongsList();
s.setAll(ss);
if (player != null) {
player.stop();
player.reset();
try {
player.setDataSource(getApplicationContext(), Uri.fromFile(new File(s.getPath())));
player.prepare();
} catch (IOException e) {
e.printStackTrace();
}
player.setLooping(true);
player.setVolume(100, 100);
player.start();
Log.e(TAG, "onStart: m= is not null" + player.isPlaying());
} else {
player = MediaPlayer.create(getApplicationContext(), Uri.fromFile(new File(s.getPath())));
player.setLooping(true);
player.setVolume(100, 100);
player.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mediaPlayer) {
mediaPlayer.start();
}
});
Log.e(TAG, "onStart: m= is null WE created new player");
}
} else {
Log.e(TAG, "onelse destroy ");
recover();
}
}
private void recover() {
destroy = false;
prefrence = getSharedPreferences("SongPrefrence", Context.MODE_PRIVATE);
for (int i = 0; i <= 5; i++) {
ss[i] = prefrence.getString("" + i, "");
}
String currentPose = prefrence.getString("current_pos", "");
Log.e(TAG, "recover: Shared Daata is" + ss[5] + "_______" + currentPose);
}
#Override
public void onDestroy() {
unregisterReceiver(reciever);
player.stop();
player.release();
stopSelf(thisStartId);
}
#Override
public void onLowMemory() {
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
prefrence = getSharedPreferences("SongPrefrence", Context.MODE_PRIVATE);
editor = prefrence.edit();
destroy = true;
}
if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
prefrence = getSharedPreferences("SongPrefrence", Context.MODE_PRIVATE);
editor = prefrence.edit();
destroy = true;
}
}
#RequiresApi(api = Build.VERSION_CODES.M)
private void saveData() {
player.pause();
for (int i = 0; i < ss.length; i++) {
editor.putString("" + i, ss[i]);
}
editor.putString("current_pos", "" + player.getCurrentPosition());
editor.commit();
}
public class MusicIntentReceiver extends BroadcastReceiver {
public String TAG = "ss";
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_HEADSET_PLUG)) {
int state = intent.getIntExtra("state", -1);
switch (state) {
case 0:
Log.d(TAG, "Headset is unplugged");
Toast.makeText(context, " Headset is unpluged ", Toast.LENGTH_SHORT).show();
Log.e(TAG, "onReceive: " + " is play song " + player.isPlaying());
break;
case 1:
Log.d(TAG, "Headset is plugged");
break;
default:
Log.d(TAG, "I have no idea what the headset state is");
}
}
}
}
}
Related
I'm creating a service that runs a mediaplayer for a set period of time.This service gets a constant value that I defined in another class and based on that the duration of the playing is determined.
I looked all over the web but couldn't find a solution or a similar problem , spent hours trying to no avail
package com.quantyam.sleepbaby.sleepbaby;
import android.app.IntentService;
import android.app.Service;
import android.content.Intent;
import android.content.res.AssetFileDescriptor;
import android.media.MediaPlayer;
import android.os.Handler;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import android.widget.Toast;
public class ContinousService extends IntentService {
private static final String TAG = "HelloService";
MediaPlayer player;
private boolean isRunning = false;
int time = 0;
Thread runner;
boolean keepplaying=true;
Handler mHandler = new Handler();
boolean keepgoiong = true;
public ContinousService() {
super("ContinousPlayer");
}
private void sendMessageToActivity(int msg) {
Intent intent = new Intent("intentKey");
intent.putExtra("current_timing", msg);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
#Override
public void onCreate() {
Log.i(TAG, "Service onCreate");
isRunning = true;
}
public static String
ACTION_CONTINOUS_PLAY = "";
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
System.out.println("******************************************* selected DUration = " + Constant.PlayDuration);
Log.i(TAG, "Service onStartCommand");
//Creating new thread for my service
//Always write your long running tasks in a separate thread, to avoid ANR
new Thread(new Runnable() {
#Override
public void run() {
runner = Thread.currentThread();
//Your logic that service will perform will be placed here
//In this example we are just looping and waits for 1000 milliseconds in each loop.
while (keepgoiong) {
try {
Thread.sleep(1000);
startplaying();
time++;
} catch (Exception e) {
e.printStackTrace();
}
if (isRunning) {
Log.i(TAG, "Service running and time is = " + time);
}
}
//Stop service once it finishes its task
stopSelf();
}
}).start();
return Service.START_STICKY;
}
public void startplaying() {
try {
if(keepplaying) {
if (player == null) {
AssetFileDescriptor afd = getAssets().openFd("music/" + Constant.SelectedMusic);
player = new MediaPlayer();
player.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
player.prepare();
player.start();
System.out.println("============================= player Started!");
}
final int duration = Integer.parseInt(Constant.PlayDuration) * 15;
int timeleft = duration - time;
sendMessageToActivity(timeleft);
System.out.println("============================= time left = " + timeleft);
if (player.isPlaying() && timeleft > 0) {
} else if (!player.isPlaying() && timeleft > 0) {
System.out.println("================================== Run Again!");
// player.prepare();
player.start();
} else if (player.isPlaying() && timeleft <= 0) {
System.out.println("============================= Time is up!");
player.stop();
keepplaying=false;
keepgoiong = false;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public IBinder onBind(Intent arg0) {
Log.i(TAG, "Service onBind");
return null;
}
#Override
protected void onHandleIntent(#Nullable Intent intent) {
}
Handler handler = new Handler();
#Override
public void onDestroy() {
keepgoiong = false;
isRunning=false;
keepplaying=false;
player.stop();
super.onDestroy();
// stopSelf();
Log.i(TAG, "Service onDestroy");
}
}
when the time is up I call stopSelf() but everytime I get the following error message :
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.quantyam.sleepbaby.sleepbaby, PID: 6550
java.lang.RuntimeException: Unable to stop service com.quantyam.sleepbaby.sleepbaby.ContinousService#cbde8b0: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.os.Looper.quit()' on a null object reference
at android.app.ActivityThread.handleStopService(ActivityThread.java:3732)
at android.app.ActivityThread.-wrap30(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1745)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6692)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1468)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1358)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.os.Looper.quit()' on a null object reference
at android.app.IntentService.onDestroy(IntentService.java:138)
at com.quantyam.sleepbaby.sleepbaby.ContinousService.onDestroy(ContinousService.java:153)
at android.app.ActivityThread.handleStopService(ActivityThread.java:3715)
at android.app.ActivityThread.-wrap30(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1745)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6692)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1468)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1358)
my code https://codeshare.io/5MJEVQ
An IntentService runs on its own thread.
So what you are doing is starting a thread that starts another thread that starts the media player and waits before calling stopSelf() on the first thread.
An intent service is only available for as long as it has work.
If the intent service launches another thread... its work is done and it will go away.
When you call the stopSelf() method your Intent service has already gone away because it started the thread and has completed its work...
I would first suggest that when the intent service starts you start the media player. Then use a PostDelayed runnable to stop the media player when it is finished. Something like below. Note: that this will still not work as is because the IntentService will finish its work once it starts the postDelayed Runnable. Solution is to use a Service instead of an IntentService.
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
System.out.println("******************************************* selected DUration = " + Constant.PlayDuration);
Log.i(TAG, "Service onStartCommand");
startMediaPlayer();
new Handler().postDelayed(new Runnable() {
public void run () {
stopSelf();
}
}, playDuration);
return Service.START_STICKY;
}
I would suggest that you use a Service instead of an IntentService.
Here is an example of a media player in a service. It uses state and intents to receive actions from UI and Uses Broadcast receivers to update ui when needed.
I am basically working with Android Application , i have requirement to restrict to open others apps while my app is running, Means My app is running it will put some locks on other application while i am accessing the others app, Kind of Application Lock. I am trying but could not find good solution. If any buddy have some idea or link or sample code please share to me.
Basically you want Kiosk Mode .
Try this:
Home button press:
<category android:name="android.intent.category.HOME" /> //add in manifest
What id does: whenever you press the home button, all the applications installed in your phone which have category.HOME category in intent-filter in their AndroidManifest.xml will be listed .
then handle Long press Home Button:
#Override
protected void onPause() {
super.onPause();
ActivityManager activityManager = (ActivityManager) getApplicationContext()
.getSystemService(Context.ACTIVITY_SERVICE);
activityManager.moveTaskToFront(getTaskId(), 0);
}
for this add this line in manifest :
<uses-permission android:name="android.permission.REORDER_TASKS" />
3.handle BackButton :
#Override
public void onBackPressed() {
// Stop user to exit
// super.onBackPressed();
}
You can also try this for Kiosk Mode:
Read this document
import android.app.ActivityManager;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.os.IBinder;
import android.provider.SyncStateContract;
import android.util.Log;
import java.io.File;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
public class HeartBeat extends Service {
private static final String TAG = HeartBeat.class.getSimpleName();
public Timer TIMER;
// private static Set<AccessGranted> mAccessGrantedList = new HashSet<AccessGranted>();
private Set<String> mLockedApps = new HashSet<String>();
private long lastModified = 0;
private BroadcastReceiver mScreenStateReceiver;
// private BroadcastReceiver mAccessGrantedReceiver;
private File mLockedAppsFile;
ArrayList<String> packagezList;
SharedPreferences sharedPrefs;
Map<String, ?> allEntries;
SharedPreferences sharedPrefsapp;
String prefix;
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
startService(new Intent(this, HeartBeat.class));
Log.i("LocalService", "Received start id " + startId + ": " + intent);
// We want this service to continue running until it is explicitly
// stopped, so return sticky.
if (TIMER == null) {
TIMER = new Timer(true);
TIMER.scheduleAtFixedRate(new LockAppsTimerTask(), 1000, 250);
mScreenStateReceiver = new BroadcastReceiver() {
private boolean screenOff;
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
screenOff = true;
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
screenOff = false;
}
if (screenOff) {
//Log.i(TAG, "Cancel Timer");
TIMER.cancel();
} else {
// Log.i(TAG, "Restart Timer");
TIMER = new Timer(true);
TIMER.scheduleAtFixedRate(new LockAppsTimerTask(), 1000, 250);
}
}
};
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
registerReceiver(mScreenStateReceiver, filter);
}
// this.stopSelf();
//startforeground goes here
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
startService(new Intent(this, HeartBeat.class));
}
private class LockAppsTimerTask extends TimerTask {
#Override
public void run() {
sharedPrefs = getApplicationContext().getSharedPreferences(getApplicationContext().getPackageName(), Context.MODE_PRIVATE);
sharedPrefsapp = getApplicationContext().getSharedPreferences("appdb", Context.MODE_PRIVATE);
allEntries= null;
allEntries = sharedPrefsapp.getAll();
Set keySet = allEntries.keySet();
Iterator<String> keySetIter = keySet .iterator();
while (keySetIter.hasNext()) {
String keyEntry= keySetIter.next();
Log.e("Shared Vaues",keyEntry);
}
//prefix = "m";
packagezList= null;
packagezList = new ArrayList<String>();
for (Map.Entry<String, ?> entry : allEntries.entrySet()) {
packagezList.add(entry.getKey());
Log.e("right key: ", entry.getKey().toString() + "right value: " + entry.getValue().toString());
}
/* for (Map.Entry<String, ?> entry : allEntries.entrySet())
{
//Check if the package name starts with the prefix.
if (entry.getKey().startsWith(prefix)) {
//Add JUST the package name (trim off the prefix).
packagezList.add(entry.getKey().substring(prefix.length()));
packagezList.add(entry.getKey());
}
}*/
for(Object object: packagezList){
Log.e("YO!", (String) object);
}
ActivityManager activityManager = (ActivityManager) getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE);
try {
//List<RecentTaskInfo> recentTasks = activityManager.getRecentTasks(1, ActivityManager.RECENT_IGNORE_UNAVAILABLE);
ActivityManager mActivityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> RunningTask = mActivityManager
.getRunningTasks(1);
ActivityManager.RunningTaskInfo ar = RunningTask.get(0);
String activityOnTop = ar.topActivity.getPackageName();
Log.e("activity on Top", "" + activityOnTop);
Log.e(" My package name", "" + getApplicationContext().getPackageName());
//for (Object data : newArrayList) {
for(Object object: packagezList){
// Provide the packagename(s) of apps here, you want to show password activity
if (!activityOnTop.contains(getApplicationContext().getPackageName()))
// if(!activityOnTop.contains(getApplicationContext().getPackageName()))
{ // you have to make this check even better
Intent i = new Intent(getApplicationContext(), LockScreenActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_ANIMATION);
i.putExtra( "", "");
startActivity(i);
}
}
} catch (Exception e) {
Log.e("Foreground App", e.getMessage(), e);
}
}
}
I have an app that captures NFC tags. The problem i have had in the past is that users hover over the tag in an unsteady manner causeing the NFC adapter to trigger twice.
I have done a few things to counter this.
manifest:
<activity
android:name=".NfcActivity"
android:screenOrientation="portrait"
android:launchMode="singleTask"
android:noHistory="true"
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation">
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
This sets the NFC capturing Activity to be the only instance in the stack and there to be no history. I've overridden all the config changes that can stop and relaunch this activity, the latter can lead to intent data being redelivered to the activity, making it look like a duplicate scan.
In the Activity itself i have overridden onNewIntent to do nothing but show a bad scan screen. I also understand that onNewIntent should mirror onCreate from a functionality standpoint, but because previous versions of the app have sent 2 scans to the next Activity, i just want the NFC capturing code in one place, onCreate.
In onCreate i do further tests to counter against hovering over a tag and creating a bad scan.
I check the launched form history flag in the intent. Android can kill an app when low on memory and relaunch later REDELIVERING the original intent. This can cause what seems like a duplicate scan.
In onCreate i check that the user STILL has the phone connected to the tag. This proves the user is not hovering over the tag with ndefTag.connect();
The app seems to work fine but on one particular phone (Samsung Galaxy Young 2), if the user places the phone on the tag for say a few seconds the the NFC adapter seems to fire a few times in a row.
When this happens the original scan is cancelled. The reason for this is oncreate processes the tag but when a subsequent scan happens(by hovering, by accident), onPause -> onNewIntent runs. So the Activity jumps out of onCreate and stops processing the tag. onNewIntent shows a failed scan screen and launches the menu screen.
The above isn't too much of a problem as all that happens is the user must re-scan the tag.
What i would like to happen is:
When onCreate runs, the tag is processed no matter what, even if onNewintent executes. Is there a way maybe to intercept the intent before is reaches onNewintent and onPause?
Maybe there is a global flag i can use, that can be checked first to say that onCreate is still running and onNewIntent shouldn't, or more importantly onPause isn't called making onCreate stop running.
import java.util.List;
import java.util.concurrent.ExecutionException;
import org.ndeftools.Message;
import org.ndeftools.Record;
import android.app.Activity;
import android.app.PendingIntent;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.tech.Ndef;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Parcelable;
import android.os.Vibrator;
import android.util.Log;
import android.widget.Toast;
public class NfcActivity extends Activity {
private static final String TAG = NfcActivity.class.getName();
protected NfcAdapter nfcAdapter;
protected PendingIntent nfcPendingIntent;
Handler handler;
Runnable runnable;
Handler failHandler;
Runnable failRunnable;
Parcelable[] messages;
Intent i;
Tag tag;
String tagId;
boolean nfcConnected;
ProgressDialog progressDialog;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.nfcactivitylayout);
Log.e(TAG, "oncreate");
nfcConnected = false;
// initialize NFC
nfcAdapter = NfcAdapter.getDefaultAdapter(this);
nfcPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, this.getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
tag = null;
tagId = null;
i = getIntent();
if ((i.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0) {
//check to see if Android has previously killed the app and relaunched it from History
//and delivered the original intent.
//if it has do not process and launch the menu screen
Intent processPayloadIntent = new Intent(NfcActivity.this, NfcscannerActivity.class);
processPayloadIntent.setAction("QRCODE_ACTION");
processPayloadIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(processPayloadIntent);
}else{
tag = i.getParcelableExtra(NfcAdapter.EXTRA_TAG);
tagId = bytesToHexString(tag.getId());
Log.e(TAG, "tagID = " + tagId);
Log.e(TAG, "oncreate intent action = " + i.getAction());
//The activity has captured tag data, prove the user is not hovering over the tag and is doing a good scan
//hovering can trigger the adapter twice
AsyncNfcConnect asnc = new AsyncNfcConnect();
try {
asnc.execute().get();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.e(TAG, "nfcConnected!!!!!!!!!!!!!!!!!!!!!!!!! = " + nfcConnected);
if(nfcConnected == true){
int buildVersionSdk = Build.VERSION.SDK_INT;
int buildVersionCodes = Build.VERSION_CODES.GINGERBREAD;
Log.e(TAG, "buildVersionSdk = " + buildVersionSdk
+ "buildVersionCodes = " + buildVersionCodes);
int themeVersion;
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.GINGERBREAD) {
themeVersion = 2;
} else {
themeVersion = 1;
}
try{
progressDialog = new ProgressDialog(this, themeVersion);
progressDialog.setTitle("NFC Tag Scanned");
progressDialog.setMessage("Processing tag...");
progressDialog.setIndeterminate(true);
progressDialog.show();
}catch(Exception e){ }
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(i.getAction()) || NfcAdapter.ACTION_TAG_DISCOVERED.equals(i.getAction())) {
if(NfcScannerApplication.isCanScanNfcTag()){
messages = i.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
if (messages != null) {
//setContentView(R.layout.successfulnfc);
NfcScannerApplication.startNfcTimer();
//Toast.makeText(this, "NFC timer set", Toast.LENGTH_LONG).show();
Log.e(TAG, "Found " + messages.length + " NDEF messages"); // is almost always just one
vibrate(); // signal found messages :-)
initHandler();
handler.postDelayed(runnable, 2000);
}else{
Toast.makeText(this, "Data on tag was not correct", Toast.LENGTH_LONG).show();
try{
handler.removeCallbacks(runnable);
Log.e(TAG, "just removed callback to runnable that reads nfc tag data");
}catch(Exception e){
}
initFailHandler();
failHandler.postDelayed(failRunnable, 1);
}
}else{
try{
handler.removeCallbacks(runnable);
Log.e(TAG, "just removed callback to runnable that reads nfc tag data");
}catch(Exception e){
}
initFailHandler();
failHandler.postDelayed(failRunnable, 1);
}
} else {
Toast.makeText(this, "Tag not recognized correctly", Toast.LENGTH_LONG).show();
try{
handler.removeCallbacks(runnable);
Log.e(TAG, "just removed callback to runnable that reads nfc tag data");
}catch(Exception e){
}
initFailHandler();
failHandler.postDelayed(failRunnable, 1);
}
}else{
try{
Toast.makeText(this, "Phone wasn't connected to Tag", Toast.LENGTH_LONG).show();
handler.removeCallbacks(runnable);
Log.e(TAG, "just removed callback to runnable that reads nfc tag data");
}catch(Exception e){
}
initFailHandler();
failHandler.postDelayed(failRunnable, 1);
}//end of NFC connect test
}//end of launched from history check
}//end of onCreate
#Override
protected void onStart() {
super.onStart();
Log.e(TAG, "onStart");
}
#Override
protected void onStop() {
super.onStop();
Log.e(TAG, "onStop");
}
#Override
public void onNewIntent(Intent intent) {
Log.e(TAG, "onNewIntent");
Toast.makeText(this, "Bad scan!!!", Toast.LENGTH_LONG).show();
initFailHandler();
failHandler.postDelayed(failRunnable, 1);
}//end of onNewIntent
public void enableForegroundMode() {
Log.e(TAG, "enableForegroundMode");
IntentFilter tagDetected = new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED); // filter for all
IntentFilter[] writeTagFilters = new IntentFilter[] {tagDetected};
nfcAdapter.enableForegroundDispatch(this, nfcPendingIntent, writeTagFilters, null);
}
public void disableForegroundMode() {
Log.e(TAG, "disableForegroundMode");
nfcAdapter.disableForegroundDispatch(this);
}
#Override
protected void onResume() {
super.onResume();
Log.e(TAG, "onResume");
enableForegroundMode();
}
#Override
protected void onPause() {
Log.e(TAG, "onPause");
super.onPause();
disableForegroundMode();
if(handler != null){
handler.removeCallbacks(runnable);
}
}
private void vibrate() {
Log.e(TAG, "vibrate");
Vibrator vibe = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE) ;
vibe.vibrate(500);
}
public void initHandler(){
handler = new Handler();
runnable = new Runnable() {
public void run() {
processTag();
}
private void processTag() {
Log.e(TAG, "about to process tag");
try{
progressDialog.dismiss();
}catch(Exception e){
//do nothing
}
// parse to records
for (int i = 0; i < messages.length; i++) {
try {
List<Record> records = new Message((NdefMessage)messages[i]);
Log.e(TAG, "Found " + records.size() + " records in message " + i);
for(int k = 0; k < records.size(); k++) {
Log.e(TAG, " Record #" + k + " is of class " + records.get(k).getClass().getSimpleName());
Record record = records.get(k);
NdefRecord ndefRecord = record.getNdefRecord();
byte[] arr = ndefRecord.getPayload();
String payload = new String(arr);
if(payload.length() > 0){
payload = payload.substring(3, payload.length());
Log.e(TAG, "payload = " + payload);
String[] splitPayload = payload.split(",");
String tagType = splitPayload[0];
String tagCompany = splitPayload[1];
String tagClientID = splitPayload[2];
String tagClientName = splitPayload[3];
if(! tagClientID.equalsIgnoreCase("0") && tagClientID.length() > 0){
handler.post(new Runnable(){
public void run() {
setContentView(R.layout.successfulnfc);
}
});
Intent processPayloadIntent = new Intent(NfcActivity.this, NfcscannerActivity.class);
processPayloadIntent.putExtra("payload", payload);
processPayloadIntent.putExtra("tagid", tagId);
processPayloadIntent.setAction("NFC");
processPayloadIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
//processPayloadIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(processPayloadIntent);
finish();
overridePendingTransition(0, R.anim.activity_animation_zoom_in);
}else{
Toast.makeText(NfcActivity.this, "Tag data problem/Scan problem.", Toast.LENGTH_LONG).show();
initFailHandler();
failHandler.postDelayed(failRunnable, 1);
}
}else{
Toast.makeText(NfcActivity.this, "Tag data problem/Scan problem.", Toast.LENGTH_LONG).show();
initFailHandler();
failHandler.postDelayed(failRunnable, 1);
}
}
} catch (Exception e) {
Log.e(TAG, "Problem parsing message", e);
}
}
}
};
}
public void initFailHandler(){
failHandler = new Handler();
failRunnable = new Runnable() {
public void run() {
returnToMainMenu();
}
private void returnToMainMenu() {
//Log.e(TAG, "about to return to main menu");
try{
progressDialog.dismiss();
}catch(Exception e){
//do nothing
}
Toast.makeText(NfcActivity.this, "Please check your scanning technique.\nPlease do not hover over tag or swipe...", Toast.LENGTH_LONG).show();
failHandler.post(new Runnable(){
public void run() {
setContentView(R.layout.nfcfail);
}
});
//onBackPressed();
Intent processPayloadIntent = new Intent(NfcActivity.this, NfcscannerActivity.class);
processPayloadIntent.setAction("QRCODE_ACTION");
processPayloadIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(processPayloadIntent);
finish();
//overridePendingTransition(0, R.anim.activity_animation_zoom_in);
}
};
}
private String bytesToHexString(byte[] src) {
StringBuilder stringBuilder = new StringBuilder("0x");
if (src == null || src.length <= 0) {
return null;
}
char[] buffer = new char[2];
for (int i = 0; i < src.length; i++) {
buffer[0] = Character.forDigit((src[i] >>> 4) & 0x0F, 16);
buffer[1] = Character.forDigit(src[i] & 0x0F, 16);
System.out.println(buffer);
stringBuilder.append(buffer);
}
return stringBuilder.toString();
}
private class AsyncNfcConnect extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
NfcActivity.this.nfcConnected = false;
String result;
Ndef ndefTag = Ndef.get(tag);
try {
Log.e(TAG, "about to test connect()********************************************");
ndefTag.connect(); // this should already perform an IO operation and should therefore fail if there is no tag
Log.e(TAG, "Ndef.connect() connected!********************************************");
NdefMessage ndefMsg = ndefTag.getNdefMessage(); // this reads the current NDEF message from the tag and consequently causes an IO operation
NfcActivity.this.nfcConnected = true;
result = "OK";
return result;
} catch (Exception e) {
// there is no tag or communication with tag dropped
Log.e(TAG, "There a problem with connecting to the tag using Ndef.connect(");
NfcActivity.this.nfcConnected = false;
result = "NOTOK";
return result;
} finally {
try {
ndefTag.close();
} catch (Exception e) {
}
}
}
}//end of Async
}
You seem to insist on not handling NFC intents in onNewIntent(). I would suggest that onCreate() and onNewIntent() both call a common procedure for scanning the tag. In that way, both entry points would follow the same code path.
Your claim that the app "jumps out of onCreate" is probably just a figure of speech? What happens is that your tag scanning AsyncNfcConnect runs on a separate thread as a background task (as it should). That task is created in onCreate() and continues running after onCreate() has finished (you could add add a Log statement at the end of onCreate() to check). When the connection with the tag is lost somehow and the tag is rediscovered, onNewIntent() is called, as you observed.
In any case there is no way to prevent this from happening, so your app has to be able to handle it. To detect this and deal with it, you could set some flag inside your activity to indicate that your background task is running or has run. You could also store the information whether an exception has occurred and simply try scanning the tag again when it is rediscovered (this probably requires that you implement the suggestion I made above). If you want to make your app even more failure proof, you could also store the ID of the last scanned tag to positively identify it again when it is rediscovered after you have successfully scanned it (or not). When exceptions keep occurring with the same tag, you could indicate his after a certain number of times to the user (e.g. by suggesting that the device be positioned differently w.r.t. the tag).
Basicly I'm trying to cancel method execution in an aspect.
So, here's my program:
I have
a Sender Application
a receiver Application (let's call it the Central Monitor)
In the Sender App :
I have,
An Activity (ın this activity, I have a method called callMethodA() )
An Aspect (In this aspect, I'm catching before the callMethodA() execution and in this before structure, I'm starting the Service )
A Service (When this service is started, it basicly sends a String to the Receiver App by Broadcast)
In the Receiver App:
I have :
An Activity ( When a string is broadcasted by sender app, then it receives the broadcast by broadcastreceiver and puts the string into an automaton which checks some condition and when automaton completes, then Result string is broadcasted back to the sender App)
So here's my actual question :
When the Sender App receives the Result string (In the sender's Activity), if the Result is Success, then I want to allow callMethodA() to be executed( this can be done by doing simply nothing, because we caught the callMethodA() execution with before and if we do nothing, then this method will be executed. )
But if the Result is FAIL then I want this method not to be executed and also I want whole program to keep running (I mean for this broadcast result, callMethodA() doesn't have to be executed, It can be executed on the next broadcast result according to the automaton result), also I want to cancel it in the aspect.
Simply, please teach me how can I cancel a method execution in an aspect.
Here's the Sender App codes:
Sender1Activity.java
package com.example.sender;
import java.util.Random;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
public class Sender1Activity extends Activity {
Button btn_send;
public Intent serviceIntent;
public Context context;
//The initial state for automaton Result is Success, nothing fancy.
static String string_AutomatonResult = "Success";
public int id;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// context = getApplicationContext();
setContentView(R.layout.activity_sender1);
// serviceIntent = new Intent(context, senderService.class);
btn_send = (Button) findViewById(R.id.buttonSend);
methodCallerHandler.removeCallbacks(hMyValueTask);
methodCallerHandler.post(hMyValueTask);
registerReceiver(broadcastReceiver_AutomatonResult, new IntentFilter(
"intent_AutomatonResult"));
}
// callMethodA() is called in the random time. It's just provides randomness
public Handler methodCallerHandler = new Handler();
public Runnable hMyValueTask = new Runnable() {
public void run() {
int n = new Random().nextInt(3000);
System.out.println("A random delay : " + (float) n / 1000
+ " seconds");
callMethodA(new View(getApplicationContext()));
methodCallerHandler.postDelayed(hMyValueTask, (long) n);
}
};
// The actual method who starts everything, it does simply nothing for now.
public void callMethodA(View v) {
System.out.println("MethodA called");
}
// Receives Automaton result from the receiver via BroadcastReceiver
public BroadcastReceiver broadcastReceiver_AutomatonResult = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
if (bundle != null) {
string_AutomatonResult = bundle
.getString("automatonResult_Put_String");
System.out
.println("***************************************************************");
System.out.println("** Automaton Result returned to Sender1 : "
+ string_AutomatonResult + "**");
System.out
.println("***************************************************************");
}
}
};
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public void onDestroy() {
unregisterReceiver(broadcastReceiver_AutomatonResult);
stopService(serviceIntent);
}
}
senderService.java
package com.example.sender;
import java.util.Random;
import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
//Sends "a" string to the receiver via Broadcast
public class senderService extends Service {
String value = String.valueOf("a");
#Override
public void onCreate() {
super.onCreate();
}
public int onStartCommand(Intent intent, int flags, int startId) {
mSendValue.removeCallbacks(hMyValueTask);
mSendValue.post(hMyValueTask);
return startId;
}
public Handler mSendValue = new Handler();
public Runnable hMyValueTask = new Runnable() {
public void run() {
publishBuiltinAccelResults(value);
}
};
#Override
public void onDestroy() {
}
public void publishBuiltinAccelResults(String value) {
Intent intent = new Intent("ResultsA");
intent.putExtra("resultA", value);
sendBroadcast(intent);
}
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
}
Test.aj (Sender's aspect)
package com.example.sender;
import android.app.Activity;
import android.content.Intent;
public aspect Test {
int i = 1;
// pointcut for the callMethodA() execution.
pointcut pointcutCatchMethod(Activity activity) : execution(* callMethodA(*))
&& target(activity);
// a hopeless try for me to cancel the method execution, see below please
pointcut pointcutMethodAExecution() : execution(* callMethodA(*));
// before callMethodA() execution, start sendService which sends string "a"
// to the Receiver
before(Activity activity) : pointcutCatchMethod(activity) {
System.out.println("******" + "Beginning of " + i
+ "th Aspect *************************");
Intent sendIntent = new Intent(activity.getApplicationContext(),
senderService.class);
System.out.println("SenderService is starting");
activity.startService(sendIntent);
System.out
.println(" callMethodA() cought by before aspect , aspect No: "
+ i);
i++;
}
// a hopeless try, for example, here, when string_AutomatonResult is FAIL,
// then I want to cancel callMethodA() execution, then I want also whole
// program to keep running.
Object around() : pointcutMethodAExecution(){
Object result = proceed();
System.out.println("aut res : "
+ Sender1Activity.string_AutomatonResult);
System.out.println("******" + "End of " + i
+ "th Aspect ******************");
return result;
}
}
Receiver Application codes below:
ReceiverActivity.java
package com.example.receiver;
import android.app.Activity;
public class ReceiverActivity extends Activity {
TextView txt_recA;
TextView txt_recB;
TextView txt_packageNumber;
String returningStringInput;
TextView txt_nowReceived;
int state = 1;
String automatonResult = "Init";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Integer pkg_number_int = 0;
setContentView(R.layout.activity_receiver);
txt_recA = (TextView) findViewById(R.id.txt_recA);
txt_recB = (TextView) findViewById(R.id.txt_recB);
txt_nowReceived = (TextView) findViewById(R.id.txt_nowReceived);
txt_packageNumber = (TextView) findViewById(R.id.txt_packageNumber);
registerReceiver(receiverResultsA, new IntentFilter("ResultsA"));
registerReceiver(receiverResultsB, new IntentFilter("ResultsB"));
}
// Broadcast Receiver for the string "a" coming from Sender1.
public BroadcastReceiver receiverResultsA = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
if (bundle != null) {
String sentStringA = bundle.getString("resultA");
returningStringInput = sentStringA;
AutomatonAB(sentStringA);
txt_recA.setText(sentStringA);
txt_nowReceived.setText("Now Received String : " + sentStringA);
}
}
};
// Ignore this BroadcastReceiver, because I have 2 Senders actually. This is
// for other sender
public BroadcastReceiver receiverResultsB = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
if (bundle != null) {
String sentStringB = bundle.getString("resultB");
returningStringInput = sentStringB;
AutomatonAB(sentStringB);
txt_nowReceived.setText("Now Received String : " + sentStringB);
txt_recB.setText(sentStringB);
}
}
};
#Override
protected void onDestroy() {
super.onDestroy();
// unregisterReceiver(receiverResultsPackageNumber);
unregisterReceiver(receiverResultsA);
unregisterReceiver(receiverResultsB);
}
// Automaton for checking the strings coming from the senders. In the end,
// it broadcasts the result to the senders (FAIL or SUCCESS)
public String AutomatonAB(String returningString) {
int stringIntValue = 0;
// to use Java version below than 1.7, 'cause string value
// cannot be used on switch...
if (returningString.equals("a")) {
stringIntValue = 1;
} else if (returningString.equals("b")) {
stringIntValue = 2;
} else {
System.out.println("No input");
}
switch (stringIntValue) {
case 1:
switch (state) {
case 1:
System.out.println("Status : Passing from State 1 to State 2");
state = 2;
System.out.println(" Success ");
// Status : Passing from State 1 to State 2 :
automatonResult = "Success2";
break;
case 2:
System.out
.println("Status : Passing from State2 to Failure State");
state = 3;
System.out.println(" Failure ");
// Status : Passing from State2 to Failure State :
automatonResult = "Failure";
break;
default:
break;
}
break;
case 2:
switch (state) {
case 1:
System.out
.println("Status : Passing from State 1 to Failure State");
state = 3;
System.out.println(" Failure ");
// Status : Passing from State 1 to Failure State :
automatonResult = "Failure";
break;
case 2:
System.out.println("Status : Passing from State 2 to State 1");
state = 1;
System.out.println(" Success ");
// Status : Passing from State 2 to State 1 :
automatonResult = "Success1";
break;
default:
break;
}
break;
default:
break;
}
// to make automaton keep going on the next turns.
if (state == 3) {
state = 1;
}
System.out.println("automata result : " + automatonResult);
txt_packageNumber.setText(automatonResult);
//Broadcast the automaton result to the senders
Intent intent = new Intent("intent_AutomatonResult");
intent.putExtra("automatonResult_Put_String", automatonResult);
sendBroadcast(intent);
return automatonResult;
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
I've resolved my problem, using Around advice is the solution,
if we use proceed() then method is going to be executed, if we don't then it is not going to.
if method returns a value, you can manipulate the methods return value in around advice like:
return null.
or if the method is void , then simply don't call the proceed().
How will we play youtube video with android media player???
Anybody has idea then please explain me.
I have to play the URL:"http://www.youtube.com/embed/bIPcobKMB94?autoplay=1" with android default media player.
When i played this url with android media player, i got MediaPlayer error (1, -2147483648).
I play that url in my android device media player but now i am not able play in tablet. Anybody help me. Why i am not able to play that video in tablet?
rtsp://v6.cache3.c.youtube.com/CiILENy73wIaGQnokCRYfXXPsBMYDSANFEgGUgZ2aWRlb3MM/0/0/0/video.3gp
Thanks
Well, the Android part is quite easy. You just need a raw URI of the YouTube video and trigger an intent with it:
Uri uri = Uri.parse("http://<link-to-RAW-youtube-video>"); // i.e. mp4 version
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(uri, "video/*"); // important! otherwise you just download the video
startActivity(intent); // called directly from an other activity as you see
If the user has multiple video players installed the user also gets a choice which one he wants to use for the playback.
The tricky part here is not Android related it is how to get the raw URI of a YouTube video. Usually they are extracted from the source code of the original YouTube Video page but that's an other topic. I tried the code above with a self extracted URI to a mp4 version of the video and it worked just fine on my Android 4.0 phone.
EDIT:
You really have to use a raw URI to the YouTube Video, for your Video it would be:
http://o-o.preferred.ber01s04.v22.lscache2.c.youtube.com/videoplayback?sparams=cp%2Cid%2Cip%2Cipbits%2Citag%2Cratebypass%2Csource%2Cexpire&fexp=904550%2C919700%2C911614&itag=18&ip=77.0.0.0&signature=C721CE7543081FC0C805C86F5D3C4D9B34D77764.D4288106CF7A3153FF1574F2334161CBD1176535&sver=3&ratebypass=yes&source=youtube&expire=1332001847&key=yt1&ipbits=8&cp=U0hSR1BLT19JUUNOMl9IRVNJOmllRjJJYy1SSG92&id=6c83dca1b28c07de&title=AT%26T%20Samsung%20Captivate%20TV%20Commercial%20-%20Galaxy%20S%20Phone-360p
It's very long but it will work :)
I had a very hard time implementing a player supporting many features and formats. Even VideoView didn't match all of my needs. Finally, I ended up writting my own solution based on SurfaceView and MediaPlayer. Here is the source code. It was validated on 4.0.3 and 4.1.2 for local 3gp, local mp4, http 3gp and youtube rtsp streams.
Remember that, presently, an URI for valid youtube video on android is to be like this: rtsp://v5.cache1.c.youtube.com/CjYLENy73wIaLQnhycnrJQ8qmRMYESARFEIJbXYtZ29vZ2xlSARSBXdhdGNoYPj_hYjnq6uUTQw=/0/0/0/video.3gp. You get them via http://m.youtube.video.
The activity's arguments are set by Intent. There are quite a variety of options. See the last source code provided in my comment. You can remove the code related to Sequencer, Scenario and Test classes. They are specific to my program (automated system for platform testing)
package my.package;
import java.io.IOException;
import java.lang.ref.WeakReference;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Point;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnBufferingUpdateListener;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.media.MediaPlayer.OnVideoSizeChangedListener;
import android.net.Uri;
import android.os.Build.VERSION;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.text.format.Time;
import android.view.Display;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import my.package.Log;
import my.package.R;
import my.package.Scenario;
import my.package.Sequencer;
import my.package.Test;
import my.package.TestUtil;
/**
* An activity to display local or remote video or play audio file.
*/
public class MediaPlayerActivity extends Activity implements
OnBufferingUpdateListener, OnCompletionListener, OnPreparedListener,
OnVideoSizeChangedListener, OnErrorListener, SurfaceHolder.Callback {
private static final String LOG_TAG = MediaPlayerActivity.class
.getSimpleName();
// Mandatory creation arguments passed by extras in starting Intent
public static final String SEQUENCER = "sequencer"; //$NON-NLS-1$
public static final String SCENARIO = "scenario"; //$NON-NLS-1$
public static final String TEST = "test"; //$NON-NLS-1$
public static final String SOURCE_URI = "uri"; //$NON-NLS-1$
// Optional creation arguments passed by extras in starting Intent
public static final String PAUSE_ON_BACKGROUND = "auto_pause"; //$NON-NLS-1$
public static final String TIMEOUT = "timeout"; //$NON-NLS-1$
public static final String LOOP = "loop"; //$NON-NLS-1$
public static final String SCREEN_ON_WHILE_PLAYING = "screen_on_while_playing"; //$NON-NLS-1$
// data arguments returned by Intent on finish
public static final String REASON = "cause"; //$NON-NLS-1$
public static final String EXCEPTION = "exception"; //$NON-NLS-1$
// additional state bundle arguments.
private static final String START_POSITION = "start"; //$NON-NLS-1$
private static final String VIDEO_WIDTH = "video_width"; //$NON-NLS-1$
private static final String VIDEO_HEIGHT = "video_height"; //$NON-NLS-1$
private WeakReference<Sequencer> mSequencer = new WeakReference<Sequencer> (null);
private WeakReference<Test> mTest = new WeakReference<Test> (null);
/**
* URI of the video/audio source.
*
* This player supports a variety of videos and audio sources, either local
* or remote.
* <p>
* An HTTP live streaming URI would be:
* {#code httplive://xboodangx.api.channel.livestream.com/3.0/playlist.m3u8}
* </p>
* <p>
* A local video file URI would be {#code file:///sdcard/spiderman.mp4}
* </p>
* <p>
* A remote 3GPP format video URI would be
* {#code http://commonsware.com/misc/test2.3gp}
* </p>
* <p>
* And finally an RTP or RTSP video source URI would be
* {#code rtsp://v4.cache1.c.youtube.com/CjYLENy73wIaLQk4RDShYkdS1BMYDSANFEIJbXYtZ29vZ2xlSARSBXdhdGNoYK-Cn8qh8J6-Tgw=/0/0/0/video.3gp}
* </p>
*/
private Uri mMediaURI;
/**
* Input: this flag is set to true if the video must be paused when the
* activity is not visible any more. The video will resume when the activity
* is visible again.
*/
private boolean mPauseOnBackground;
/**
* Input: number of milliseconds until automatic shutdown, or -1 if no
* timeout.
*/
private long mTimeout;
/**
* Input: flag set to true to loop back to the beginning of the video when
* reaching its end
*/
private boolean mLoop;
/**
* The width of the video, obtained by
* {#link #onVideoSizeChanged(MediaPlayer, int, int)}
*/
private int mVideoWidth;
/**
* The height of the video, obtained by
* {#link #onVideoSizeChanged(MediaPlayer, int, int)}
*/
private int mVideoHeight;
private MediaPlayer mMediaPlayer;
private SurfaceView mPreview;
private boolean mIsVideoSizeKnown = false;
private boolean mMediaPrepared = false;
/**
* This member is set to position the video should start. It is set when
* pausing the video and used when restoring the instance.
*/
private int mStartPosition;
private boolean mTimeoutSet;
private boolean mScreenOnWhilePlaying;
private SurfaceHolder mHolder;
private static class ShutdownHandler extends Handler {
WeakReference<MediaPlayerActivity> mActivity;
public ShutdownHandler(MediaPlayerActivity activity) {
mActivity = new WeakReference<MediaPlayerActivity>(activity);
}
#Override
public void handleMessage(Message msg) {
MediaPlayerActivity activity = mActivity.get();
if (activity != null) {
activity.finishTest(Activity.RESULT_OK, null);
} else {
//Log.w(LOG_TAG, "no activity for shutdown");
}
}
}
public MediaPlayerActivity() {
super();
// These members are initialized in onCreate(Bundle) by the
// starting Intent, the first time the activity is created, and restored
// in the same method with the arguments in the saved instance bundle.
mSequencer = new WeakReference<Sequencer> (null);
mTest = new WeakReference<Test> (null);
setSourceURI(null);
setPauseOnBackground(false);
setPlayTimeout(-1);
setLooping(false);
setScreenOnWhilePlaying(true);
// Initialize internals.
mIsVideoSizeKnown = false;
mVideoWidth = mVideoHeight = 0; // unknown
mMediaPrepared = false;
mMediaPlayer = null;
mPreview = null; // set in onCreate(Bundle)
setStartPosition(0); // beginning of the video
mTimeoutSet = false;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.video_player);
Intent intent = getIntent();
if (savedInstanceState != null) {
onRestoreInstanceState(savedInstanceState);
} else if (intent != null) {
Log.d(LOG_TAG, "Loading starting Intent extras...");
// read starting Intent extras.
_updateForeignReferences(intent);
setSourceURI((Uri) intent.getParcelableExtra(SOURCE_URI));
setPlayTimeout(intent.getLongExtra(TIMEOUT, -1L));
setPauseOnBackground(intent.getBooleanExtra(PAUSE_ON_BACKGROUND,
false));
setLooping(intent.getBooleanExtra(LOOP, false));
setScreenOnWhilePlaying(intent.getBooleanExtra(SCREEN_ON_WHILE_PLAYING, true));
}
mTimeoutSet = false;
_updateWidgets();
}
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
Log.d(LOG_TAG, "Restoring instance state...");
// restore saved references
_updateSavedForeignReferences(savedInstanceState);
// restore saved inputs
setSourceURI(Uri.parse(savedInstanceState.getString(SOURCE_URI)));
setPlayTimeout(savedInstanceState.getLong(TIMEOUT));
setPauseOnBackground(savedInstanceState.getBoolean(PAUSE_ON_BACKGROUND));
setLooping(savedInstanceState.getBoolean(LOOP));
setScreenOnWhilePlaying(savedInstanceState.getBoolean(SCREEN_ON_WHILE_PLAYING));
// restore internals
setStartPosition(savedInstanceState.getInt(START_POSITION, 0));
mVideoWidth = savedInstanceState.getInt(VIDEO_WIDTH);
mVideoHeight = savedInstanceState.getInt(VIDEO_HEIGHT); // unknown
mIsVideoSizeKnown = (mVideoWidth > 0) && (mVideoHeight > 0);
}
#Override
protected void onResume() {
super.onResume();
if (mMediaPlayer == null) {
try {
_playMedia();
} catch (Exception e) {
_fail(e);
}
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Log.d(LOG_TAG, "Saving instance state");
Sequencer sequencer = mSequencer.get();
if (sequencer != null) {
outState.putInt(SEQUENCER, sequencer.getPosition());
Scenario scenario = sequencer.getScenario();
if (scenario != null) {
outState.putInt(SCENARIO, scenario.getScenarioId());
}
}
Test test = mTest.get();
if (test != null) {
outState.putString(TEST, TestUtil.getTestPath(test, TestUtil.Path.Static));
}
if (getSourceURI() != null) {
outState.putString(SOURCE_URI, getSourceURI().toString());
}
outState.putBoolean(LOOP, isLooping());
outState.putBoolean(PAUSE_ON_BACKGROUND, isPausingOnBackground());
outState.putLong(TIMEOUT, getPlayTimeout());
outState.putBoolean(SCREEN_ON_WHILE_PLAYING, isScreenOnWhilePlaying());
outState.putInt(START_POSITION, getStartPosition());
}
#Override
protected void onPause() {
super.onPause();
if (isPausingOnBackground()) {
_pausePlayback();
}
}
#Override
protected void onStop() {
super.onStop();
Log.d(LOG_TAG, "onStop");
if (isPausingOnBackground()) {
_releaseMediaPlayer();
}
}
#Override
protected void onDestroy() {
super.onDestroy();
Log.d(LOG_TAG, "onDestroy");
// TODO: It would be fine to fail the test if the activity was destroyed
// if we didn't finished the test yet but there are far too many cases
// and I failed to implement one working with all of them!
/* if (!mInstanceSaved) {
finishTest(Activity.RESULT_FIRST_USER, new Intent().putExtra(REASON,
"Activity destroyed. Something certainly goes wrong there."));
}
*/
_releaseMediaPlayer();
}
// Restore sequencer, scenario and test references from saved state.
private void _updateSavedForeignReferences(Bundle savedInstanceState) {
int sequencer = savedInstanceState.getInt(SEQUENCER, -1);
int scenarioId = savedInstanceState.getInt(SCENARIO, -1);
mSequencer = new WeakReference<Sequencer>(null);
mTest = new WeakReference<Test>(null);
if (scenarioId >= 0 && sequencer >= 0) {
Scenario scenario = Controller.controller.getData().scenarios()
.getScenario(scenarioId);
mSequencer = new WeakReference<Sequencer>(Controller.controller
.engine().getSequencerAt(sequencer));
String testPath = savedInstanceState.getString(TEST);
if (!TextUtils.isEmpty(testPath)) {
mTest = new WeakReference<Test>(TestUtil.fromPath(
scenario.getRootTest(), testPath));
}
}
}
// Update sequencer, scenario and test references from starting Intent
protected void _updateForeignReferences(Intent intent) {
int scenarioId = intent.getIntExtra(MediaPlayerActivity.SCENARIO, -1);
Scenario scenario = Controller.controller.getData().scenarios()
.getScenario(scenarioId);
int sequencer = intent.getIntExtra(MediaPlayerActivity.SEQUENCER, -1);
mSequencer = new WeakReference<Sequencer>(null);
mTest = new WeakReference<Test>(null);
if (scenarioId >= 0 && sequencer >= 0) {
mSequencer = new WeakReference<Sequencer>(Controller.controller
.engine().getSequencerAt(sequencer));
String testPath = intent.getStringExtra(MediaPlayerActivity.TEST);
if (!TextUtils.isEmpty(testPath)) {
mTest = new WeakReference<Test>(TestUtil.fromPath(
scenario.getRootTest(), testPath));
}
}
}
/**
* Terminate the test case and finish the activity at the same time.
* <p>
* The result code and data are passed to both the parent activity and the
* {#link Test#terminate(int, Sequencer, Object)} method.
* </p>
*
* #param resultCode
* the result code. May be on of the Activity result code but
* also any other one having a meaning for the test and caller
* activity.
* #param data
* extra result data. Can be null.
*/
public void finishTest(int resultCode, Intent data) {
Test test = mTest.get();
Sequencer sequencer = mSequencer.get();
if ((test != null) && (sequencer != null)) {
test.terminate(resultCode, sequencer, data);
// prevent any further call to finishTest.
mTest = new WeakReference<Test> (null);
}
if (!isFinishing()) {
setResult(Activity.RESULT_OK, data);
finish();
}
}
#SuppressWarnings("deprecation")
private void _updateWidgets() {
SurfaceView surface = (SurfaceView) findViewById(R.id.surface);
mPreview = surface;
SurfaceHolder holder = surface.getHolder();
holder.addCallback(this);
if (VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB) {
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
}
public void onBufferingUpdate(MediaPlayer arg0, int percent) {
Log.d(LOG_TAG, "onBufferingUpdate percent:" + percent);
if (percent >= 100) {
mMediaPlayer.setOnBufferingUpdateListener(null);
}
// no display so don't bother.
}
public void onCompletion(MediaPlayer player) {
_releaseMediaPlayer();
finishTest(Activity.RESULT_OK, null);
}
private void _rearmPlayer() {
mVideoWidth = 0;
mVideoHeight = 0;
mMediaPrepared = false;
mIsVideoSizeKnown = false;
}
public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
if (mIsVideoSizeKnown) return; // further notifications are completely wrong!!
Log.i(LOG_TAG, "Video size: " + width + "x" + height);
mIsVideoSizeKnown = true;
mVideoWidth = width;
mVideoHeight = height;
if (width > 0 && height > 0) {
_fitSurfaceForVideo();
} else {
// audio only or video size unknown.
}
if (mMediaPrepared) {
_startPlayback();
}
}
#SuppressWarnings("deprecation")
#SuppressLint("NewApi")
private void _fitSurfaceForVideo() {
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
if (VERSION.SDK_INT >= 13) {
display.getSize(size);
} else {
size.x = display.getWidth();
size.y = display.getHeight();
}
double ratioVideo = (double)mVideoWidth / mVideoHeight;
double ratioScreen = (double)size.x / size.y;
if (ratioScreen > ratioVideo) {
// fit in height and scale the width to match the video ratio
mVideoHeight = size.y;
mVideoWidth = (int) (size.y / ratioVideo);
} else {
// fit in width and scale height to keep the video ratio
mVideoWidth = size.x;
mVideoHeight = (int) (size.x / ratioVideo);
}
}
public void onPrepared(MediaPlayer mediaplayer) {
mMediaPrepared = true;
if (mIsVideoSizeKnown) {
_startPlayback();
}
}
private void _startPlayback() {
SurfaceHolder holder = mPreview.getHolder();
if (mVideoWidth > 0 && mVideoHeight > 0) {
holder.setFixedSize(mVideoWidth, mVideoHeight);
}
if (mStartPosition > 0) {
Log.i(LOG_TAG, String.format("Resume at %f seconds", mStartPosition / 1000.f));
mMediaPlayer.seekTo(mStartPosition);
} else {
Log.i(LOG_TAG, "Start video");
}
if (!mTimeoutSet && (getPlayTimeout() > 0)) {
// this is a constant time reference: deduce the time already played.
long remaining = getPlayTimeout() - mStartPosition;
Time time = new Time();
time.setToNow();
time.second += remaining / 1000;
time.normalize(false);
Log.i(LOG_TAG, "Will end the video on " + time.format2445());
new ShutdownHandler(this).sendEmptyMessageDelayed(0, remaining);
mTimeoutSet = true;
}
mMediaPlayer.start();
}
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
Log.d(LOG_TAG, String.format(
"surfaceChanged called: format=%d, width=%d, height=%d",
format, width, height));
}
public void surfaceDestroyed(SurfaceHolder surfaceholder) {
Log.d(LOG_TAG, "surfaceDestroyed called");
mHolder = null;
if (mMediaPlayer != null) {
mMediaPlayer.setDisplay(null);
}
}
public void surfaceCreated(SurfaceHolder holder) {
Log.d(LOG_TAG, "surfaceCreated called");
mHolder = holder;
if (mMediaPlayer != null) {
// surface created after the media player
try {
mMediaPlayer.setDisplay(holder);
mMediaPlayer.setScreenOnWhilePlaying(isScreenOnWhilePlaying());
mMediaPlayer.setOnCompletionListener(this);
if (!mMediaPrepared) {
mMediaPlayer.setDataSource(this, mMediaURI);
mMediaPlayer.prepareAsync();
}
} catch (IllegalStateException e) {
_fail(e);
} catch (IllegalArgumentException e) {
_fail(e);
} catch (SecurityException e) {
_fail(e);
} catch (IOException e) {
_fail(e);
}
}
}
private void _playMedia() throws IllegalArgumentException,
SecurityException, IllegalStateException, IOException {
Log.d(LOG_TAG, "_playMedia()");
_rearmPlayer();
/*
* The video should be in a streamable mp4 or 3gpp format. The URI
* scheme may be Http. Mediaplayer can only play
* "progressive streamable contents" which basically means: 1. the movie
* atom has to precede all the media data atoms. 2. The clip has to be
* reasonably interleaved.
*/
if (mMediaURI != null) {
Log.i(LOG_TAG, "Source: " + mMediaURI);
// Create a new media player and set the listeners
if (mMediaPlayer != null) {
mMediaPlayer.reset();
} else {
mMediaPlayer = new MediaPlayer();
}
// mMediaPlayer.setDataSource(this, mMediaURI);
mMediaPlayer.setOnBufferingUpdateListener(this);
mMediaPlayer.setOnPreparedListener(this);
mMediaPlayer.setLooping(isLooping());
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mMediaPlayer.setOnVideoSizeChangedListener(this);
if (mHolder != null) {
// surface created before the media player
mMediaPlayer.setDisplay(mHolder);
mMediaPlayer.setScreenOnWhilePlaying(isScreenOnWhilePlaying());
mMediaPlayer.setOnCompletionListener(this);
mMediaPlayer.setDataSource(this, mMediaURI);
mMediaPlayer.prepareAsync();
}
} else {
_fail("No video source defined");
}
}
// fail due to exception
private void _fail(Exception e) {
Log.e(LOG_TAG, e);
Intent data = new Intent();
data.putExtra(EXCEPTION, e);
finishTest(Activity.RESULT_FIRST_USER, data);
}
// fail due to generic error
private void _fail(String text) {
Log.e(LOG_TAG, text);
Intent data = new Intent();
data.putExtra(REASON, text);
finishTest(Activity.RESULT_FIRST_USER, data);
}
private void _pausePlayback() {
if (mMediaPlayer != null && mMediaPlayer.isPlaying()) {
Log.i(LOG_TAG, "Pause playback");
mMediaPlayer.pause();
// retain position for use by onSaveInstanceState(Bundle)
setStartPosition(mMediaPlayer.getCurrentPosition());
}
}
#Override
public void onBackPressed() {
super.onBackPressed();
Intent data = new Intent();
data.putExtra(REASON, "canceled by user");
finishTest(Activity.RESULT_CANCELED, data);
}
private void _releaseMediaPlayer() {
_stopPlayback();
if (mMediaPlayer != null) {
mMediaPlayer.release();
mMediaPlayer = null;
}
_rearmPlayer();
}
private void _stopPlayback() {
if (mMediaPlayer != null && mMediaPlayer.isPlaying()) {
_pausePlayback();
Log.i(LOG_TAG, "stop video");
mMediaPlayer.stop();
}
}
public boolean isPausingOnBackground() {
return mPauseOnBackground;
}
public void setPauseOnBackground(boolean pause) {
Log.d(LOG_TAG, "Pausing on background: " + pause);
this.mPauseOnBackground = pause;
}
public Uri getSourceURI() {
return mMediaURI;
}
public void setSourceURI(Uri uri) {
Log.d(LOG_TAG, "Media source: " + uri);
this.mMediaURI = uri;
}
public long getPlayTimeout() {
return mTimeout;
}
public void setPlayTimeout(long timeout) {
Log.d(LOG_TAG, "Play length (ms): " + timeout);
this.mTimeout = timeout;
}
public boolean isLooping() {
return mLoop;
}
public void setLooping(boolean loop) {
Log.d(LOG_TAG, "Is looping: " + loop);
this.mLoop = loop;
}
public int getStartPosition() {
int position = 0;
if (mMediaPlayer != null) {
position = mMediaPlayer.getCurrentPosition();
}
return position;
}
public void setStartPosition(int position) {
Log.d(LOG_TAG, String.format("Start at %fs", position / 1000.));
this.mStartPosition = position;
}
public boolean isScreenOnWhilePlaying() {
return mScreenOnWhilePlaying;
}
public void setScreenOnWhilePlaying(boolean screenOnWhilePlaying) {
Log.d(LOG_TAG, "Screen ON while playing: " + screenOnWhilePlaying);
this.mScreenOnWhilePlaying = screenOnWhilePlaying;
}
#Override
public boolean onError(MediaPlayer mp, int what, int extra) {
_fail(String.format("Media player error: what=%d, extra=%d", what, extra));
return true;
}
}
The resource for the layout containing the SurfaceView:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<SurfaceView
android:id="#+id/surface"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</FrameLayout>
An example of use of the activity:
Intent intent = new Intent(parent, MediaPlayerActivity.class);
intent.putExtra(MediaPlayerActivity.SOURCE_URI, this.getSourceURI());
intent.putExtra(MediaPlayerActivity.PAUSE_ON_BACKGROUND,
this.getPauseOnBackground());
Scenario scenario = sequencer.getScenario();
intent.putExtra(MediaPlayerActivity.SCENARIO, scenario.getScenarioId());
intent.putExtra(MediaPlayerActivity.SEQUENCER, sequencer.getPosition());
intent.putExtra(MediaPlayerActivity.TEST, TestUtil.getTestPath(
scenario.getCurrentTest(), TestUtil.Path.Static));
// timeout option
TimeSpan timeout = this.getTimeout();
if (!timeout.isNull()) {
timeout.renew();
intent.putExtra(MediaPlayerActivity.TIMEOUT, timeout.value());
}
intent.putExtra(MediaPlayerActivity.LOOP, this.isLooping());
startActivity(intent);
#Sock have you thought about using the YouTube API for Android. They have a great playerview which gives you lots of control and event-listening ability on the video. I recently posted a tutorial on using the API if it might fit your needs, check it out here