I am trying to use a MediaController and alter it so that it does not disappear after 3 seconds. I have found this code in a related question and I am using it:
mediaController = new MediaController(this) {
#Override
public void hide()
{
mediaController.show();
}
};
This code works, but when the activity stops (from using back button), I get log errors about a leaked window from a view added in the code below at the show(0) statement:
public void onPrepared(MediaPlayer mediaPlayer) {
mediaController.setMediaPlayer(this);
mediaController.setAnchorView(findViewById(R.id.audio_control));
handler.post(new Runnable() {
public void run() {
mediaController.setEnabled(true);
mediaController.show(0);
}
});
}
It seems to me that overriding the hide method by simply calling the show method means the hide method is not doing what is needed when finishing the activity. I must be overriding other necessary functionality, like actually hiding the controller!
I want to hide the controller when necessary (such as when finishing with it), but not in the case of when it is simply being hidden after 3 seconds (and the activity is not being finished).
Or maybe I should let the controller disappear after 3 seconds all the time but I am not sure I understand why it is implemented this way. It seems better to just keep it there all the time to me.
It's a bug in the MediaController:
private View.OnClickListener mPauseListener = new View.OnClickListener() {
public void More ...onClick(View v) {
doPauseResume();
show(sDefaultTimeout);
}
};
There are two ways to solve this.
A) Override the hide() method:
class MyMediaController extends MediaController {
#Override
public void hide() {
// Nope, do not hide. Call hideActually() to actually hide.
}
public void hideActually() {
super.hide();
}
}
B) Override the show() methods:
class MyMediaController extends MediaController {
public int mTimeout = 0;
#Override
public void show() {
show(mTimeout);
}
#Override
public void show(int timeout) {
super.show(mTimeout);
}
}
Overriding the hide() method gives you the full control over hiding the MediaController, but you have to ensure calling hideActually() before the Activity is destroyed, else you'll get these log errors about a leaked window.
Overriding the show() methods gives you the chance to set a timeout after all. In this case there are some events on which the MediaController will hide without calling the hide() method explicitly, i.e. when the user presses the back button.
Personally I'd prefer using a mix of both implementations:
class MyMediaController extends MediaController {
public int mTimeout = 0;
#Override
public void show() {
show(mTimeout);
}
#Override
public void show(int timeout) {
super.show(mTimeout);
}
#Override
public void hide() {
// Do not hide until a timeout is set
if (mTimeout > 0) super.hide();
}
public void hideActually() {
super.hide();
}
}
In this case you have full control over showing and hiding the MediaController when mTimeout = 0, but you get the "normal" behaviour of the MediaController when you actually set a timeout.
Related
In the onCreate() method of my activity I have a Timer + TimerTask that will schedule a ParseQuery. On The ParseQuery callback, which is on mainThread, I delegate an interface callback to make a simple UI update. This works when I let the Activity unchanged. But if I exit from the activity and enter again it (A new timer will NOT be created here, because it gets created only when starting the activity from a certain point) wouldn't work. I think is something with Activity instances but I cannot handle it.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat);
....
uiTimer = new Timer();
uiTask = new TimerTask() {
#Override
public void run() {
doParseTask();
}
};
uiTimer.schedule(uiTask, shortCodeLeft);
}
doParseTask(){
Utils.doParseQuery(this, new MyListener{
#Override
public void onSuccess() {
updateUI();
}
});
}
updateUI(){
Log.i(TAG, "Show changed layout"); //This is always shown, this way I ensure it gets here!!
mTextView.setText(foo); //this doesn't work
mLayout.setVisibility(View.GONE); //this doesn't work
}
The ParseQuery is executed in done() callback method, I call the function that updates the UI:
public class Utils{
.......
doParseQuery(Context ctx, MyListener listener){
.......
query.saveInBackground(new SaveCallback() {
#Override
public void done(ParseException e) {
if(e == null){
....
listener.onSuccess();
}
}
});
}
}
What I have tried, with no success:
1. make the `uiTimer` and `uiTask` static global variables; // I thought that maybe it gets leaked into activity instances
2. update the UI using
runOnUiThread(new Runnable() {
#Override
public void run() {}
});
OR
mLayout.post(new Runnable() {
#Override
public void run() {
mLayout.setVisibility(View.GONE);
}
});
3. android:launchMode= "singleInstance" //in Manifest
If you want that your UITimer to gets executed every time your activity goes to foreground, you should implement the onStart or onResume method and move your uiTimer implementation to one of both method. Even your activity being already started these two methods are called after exiting the activity and reopening it again.
A better explanation of Android Activity lifecycle is well explained by google documentation https://developer.android.com/guide/components/activities/activity-lifecycle.html.
Your code would look like this:
#Override
protected void onStart() {
super.onStart();
....
uiTimer = new Timer();
uiTask = new TimerTask() {
#Override
public void run() {
doParseTask();
}
};
uiTimer.schedule(uiTask, shortCodeLeft);
}
doParseTask(){
Utils.doParseQuery(this, new MyListener{
#Override
public void onSuccess() {
updateUI();
}
});
}
When you exit from your activity, the instances mTextView and mLayout will be destroyed.
Then, when you create a new activity, the activity creates new instances of the text view and layout.
Your timer goes off and tries to update the original elements, which are now invalid as the activity has been closed (but the log still works as this is separate to your activity).
You should initialise the timer & task in onCreate(), and then in order to stop updating the old UI elements:
#Override
protected void onStop() {
if (uiTimer != null) {
uiTimer.cancel();
}
super.onStop();
}
I want to press volume button programatically. In Java it is possible using the robot class, but in Android there is no robot class.
I am wondering how to achieve this in Android.
I would suggest you to increase/decrease the volume programmatically which would be a tad bit easier, however if you want to use it for some other process then you can check the code below -
EDIT - The snippet I gave before doesn't work, but this one does. It uses a runnable so the try catch block is necessary.
new Thread(new Runnable() {
#Override
public void run() {
try {
Instrumentation inst = new Instrumentation();
//This is for Volume Down, change to
//KEYCODE_VOLUME_UP for Volume Up.
inst.sendKeyDownUpSync(KeyEvent.KEYCODE_VOLUME_DOWN);
}catch(InterruptedException e){}
}
}).start();
how about this
private abstract class SimpleButton extends Button {
public SimpleButton(String text) {
super(TechDemoLauncher.this);
setText(text);
setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
onButtonPressed();
}
});
}
public abstract void onButtonPressed();
}
after that you can just implement the onButtonPressed() method like this
private void Example(String string) {
yourLayout.addView(new SimpleButton(string) {
#Override
public void onButtonPressed() {
//insert your code
}
});
}
I know this question have been asked many times around here, but i didn't find the propert answer for my issue.
this code can disable back button:
#Override
public void onBackPressed() {
// Do Here what ever you want do on back press;
}
but is there anyway that i can disable back button for a temporary time,not for the whole Activity ?
nice answer by Dixit. Just another option
public boolean onKeyDown(int keyCode, KeyEvent event) {
boolean result = false;
if (keyCode == KEYCODE_BACK) {
if (condition) {
result = true;
}
}
return result;
}
N.B ..
it will work on ancient version also
returning true from onKeyDown consumes the default behavior
You have to set on boolean flag where you have to require disable back button set flag value true;
In onBackPressed() you have to put condition as per #Dixit says
#Override
public void onBackPressed() {
if(condition to check){
// this block disable back button
}else{
// this block enable back button
super.onBackPressed();
}
}
If you want to disable backbutton for certain time use this,
//for 5 sec = 5000
countDownTimer = new CountDownTimer(5000,1000) {
#Override
public void onTick(long millisUntilFinished) {
txtWait.setTextColor(getResources().getColor(R.color.errorcolor));
txtWait.setText("Wait( " + millisUntilFinished / 1000+" sec)");
onBackPressed();
}
#Override
public void onFinish() {
YourActivityName.super.onBackPressed();
}
}.start();
And in the override method:
#Override
public void onBackPressed() {
//super.onBackPressed(); commented this to disable the back press
}
Full working code:
YourActivity extends AppCompatActivity{
boolean isBackButtonDisabled = false;
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState)
setContentView(R.layout.somelayout);
disableBackButton(4000); //<--Back button is disabled
}
#Override
public void onBackPressed(){
if(!sBackButtonDisabled){
super.onBackPressed();
}
}
private void disableBackButton(final int timeInMilis){
if(!isBackButtonDisabled) {
isBackButtonDisabled = true; //<-- Keep it outside Thread code
Thread t = new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(timeInMilis);
} catch (InterruptedException e) {
} finally {
isBackButtonDisabled = false;
}
}
});
t.start();
}
}
}
Note: You can use disableBackButton(time) in other scenarios as well. For example Button click. If
you click button multiple times the Thread will only run once. Because in this code
isBackButtonDisable variable is thread-safe "in a way".
I have my main Activity, it starts with a custom SurfaceView called DrawView being set by setContentView. The Main Activity (Draw) has the following method within it
public void launchCutScene(int scene) {
Intent intent = new Intent(Draw.this, CutScene.class);
startActivityForResult(intent, 0);
}
if I call this method directly after setContentView the new Activity CutScene loads properly. CutScene is as follows
public class CutScene extends Activity implements OnCompletionListener, OnPreparedListener{
String pathToFile = "";
VideoView videoPlayer;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
pathToFile = "EM Math/" + "st.mp4";
setContentView(R.layout.main);
File root = Environment.getExternalStorageDirectory();
videoPlayer = (VideoView) findViewById(R.id.myvideoview);
videoPlayer.setOnPreparedListener(this);
videoPlayer.setOnCompletionListener(this);
videoPlayer.setKeepScreenOn(true);
videoPlayer.setVideoPath(root + "/" + pathToFile);
}
#Override
protected void onDestroy() {
super.onDestroy();
}
#Override
protected void onStop() {
super.onStop();
}
#Override
public void onPrepared(MediaPlayer vp) {
videoPlayer.start();
}
#Override
public void onCompletion(MediaPlayer mp) {
finish();
}
#Override
public boolean onTouchEvent (MotionEvent ev){
if(ev.getAction() == MotionEvent.ACTION_DOWN){
if(videoPlayer.isPlaying()){
videoPlayer.pause();
} else {
videoPlayer.start();
}
return true;
} else {
return false;
}
}
}
However, if within DrawView I call draw.launchCutScene(0) then the activity still comes up, but the video glitches, it either stays as a black screen and you have to press back to make the activity crash, in which case it will bring up the first activity. Or it will play the sound only but multiple times and un-synced. Either way after it crashes if a launchCutScene call is done again within the DrawView class the video now works fine.
Why is this happening? does anybody understand what I need to do?
Okay, Finely fixed the error!
All I had to do was set my threads runnable boolean to false, then call the activity. Once activity closes my program reinitiates the thread, and everything work hunkydorry now!!!!... So if your getting this Video Bug with your Video Views it's probably because you are running a thread in the background!
I try to use MediaController to play music.
I want the MediaController appear until the "back" button is pressed.
Now I have try below code:
MediaController mediaController = new MediaController(this){
#Override
public void setMediaPlayer(MediaPlayerControl player) {
super.setMediaPlayer(player);
this.show();
}
#Override
public void show(int timeout) {
super.show(0);
}
//instead of press twice with press once "back" button to back
#Override
public boolean dispatchKeyEvent(KeyEvent event) {
if(event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
Activity a = (Activity)getContext();
a.finish();
}
return true;
}
};
But it still one trouble while the MediaController visible.
When the MediaController appear touch the screen, the MediaController will hide.
I also already try below code:
#Override
public boolean onTouchEvent(MotionEvent event) {
Log.d("screen","touch");
return true;
}
But it did not work.
The string did not show in Logcat.
Anyone has idea to do it?
Override this method also inside media controller
#Override
public void hide() {
// TODO Auto-generated method stub
super.show();
}
If you want to keep the hide() method but not have the controller disappearing every time a control is used :
this.mediaController = new MediaController(this){
#Override
public void show(int timeout) {
super.show(0);
}
};