Inside of the onReceive(Content context, Intent intent) method of my public class MediaButtonIntentReceiver extends BroadcastReceiver I need to count the number of headset button clicks (single, double, triple), which is denoted by KeyEvent.ACTION_DOWN of the ACTION_MEDIA_BUTTON.
What I have almost works, but my current algorithm sucks and is unreliable after a few times. Basically every successive ACTION_DOWN (hit within a certain number of milliseconds to the previous ACTION_DOWN) I do numClicks++. But also I need to see when the user is done pressing, so after each event I start a CountDownTimer, and if by the time it runs out there are no new clicks, then I'm done and now know the number of clicks.
The problems I'm running into are as follows: for one, the button itself seems noisy - if I press it too fast I usually miss a click. Two, after a few trials when the app it loaded, it starts getting random and I'm assuming that there are multiple CountDownTimer threads (is that the right word?) still running which screws my stuff up.
Anyways here's the main code snippet:
//note: thisClickTime uses System.currentTimeMillis()
if (action == KeyEvent.ACTION_UP) {
if (isDown == true) {
if (numClicks == 0 && lastClickTime == 0) {
//we have a new click
numClicks++;
lastClickTime = thisClickTime; //update the click time
isDown = false;
elapsedTime = thisClickTime - lastClickTime;
} else if (thisClickTime - lastClickTime < clickDelay) { //&& thisClickTime - lastClickTime > 10
numClicks++;
lastClickTime = thisClickTime;
isDown = false;
}
final int oldNumClicks = numClicks;
final CountDownTimer checkIfDone = new CountDownTimer(clickDelay, 10) {
public void onTick(long millisUntilFinished) {
if (oldNumClicks != numClicks) {
cancel();
}
}
public void onFinish() { //code that executes when counter is done
if (oldNumClicks == numClicks) {
//if user doesn't click anymore in time clickDelay + X milliseconds, then it's done
Toast.makeText(context, "Number of clicks: " + Integer.toString(numClicks), Toast.LENGTH_SHORT).show();
//reset state variables
numClicks = 0;
lastClickTime = 0;
}
}
}.start();
} else {
//?
}
}
For reference, I've been looking around at stuff like:
http://musicqueueproject.googlecode.com/svn-history/r83/trunk/src/com/yannickstucki/android/musicqueue/old/PlayerService.java
To see if there's a good way to register number of clicks. I don't really understand their code too well though, and from what I can see they only deal with single/double clicks (I may need triple and quadruple).
EDIT - uploaded the current code I'm working with. It works pretty decently most of the time. Here's what I've noticed though: if I do my button testing too close together in time, the results start screwing up and under counting the clicks. I think this is because other CountDownTimers from previous attempts are still open, and when they finish, they reset certain state variables (numClicks = 0, for one). So am I misusing the timer? I can't think of another solution though as I need some concept of elapsed time after the last click to determine when the clicking is done.
Thanks for any help.
If your BroadcastReceiver is registered in the manifest, the BroadcastReceiver will only exist for a single call to onReceive() -- subsequent broadcasts may result in another BroadcastReceiver instance. And a manifest-registered BroadcastReceiver cannot fork threads, as the whole process may get shut down once onReceive() is over.
I am skeptical that there a clean way to get your code to be reliable, as the media button simply was not designed for your intended use pattern.
Related
I am making a board game were I have 3 AI players and a user playing. When the user presses a Button to give its turn up to the AI's I want to add a delay so the user can see every move each AI makes.
I have tried a thread sleep and handler but it seems they are unable to update the board and add a delay with each iteration of the while loop. The code without any attempt to add a delay can be found below. I would need to add a delay after the inner while loop terminates.
public void onClickNextTurn(View view){
boolean turnFinished;
findViewById(R.id.btnChangeTurn).setVisibility(View.INVISIBLE);
while (this.playerTurn<4) {
this.playerTurn++;
turnFinished=false;
while (!turnFinished) {
diceRoll();
MoveTriplet result = ai[playerTurn-2].aiTurn(this.boardPieceLocations, this.homeLocations, this.finishLocations, this.roll, playerTurn);
if (result != null) {
if (result.getMoveType() == 'b') { //The Artificial Opponent is moving from one home location to the board AND gets to roll again
this.homeLocations[playerTurn - 1][result.getPreviousIndex()] = 0;
if (this.boardPieceLocations[result.getNextIndex()] != 0)
returnPieceHome(this.boardPieceLocations[result.getNextIndex()]);
this.boardPieceLocations[result.getNextIndex()] = this.playerTurn;
this.homeButtons[playerTurn - 1][result.getPreviousIndex()].setBackgroundColor(getResources().getColor(R.color.colorHoles));
this.buttons[result.getNextIndex()].setBackgroundColor(colors[playerTurn - 1]);
}
So if anyone could point me in the right direction on how I could add an delay between iterations of the outer while loop and at the same time updating the my board. Thanks in advance!
Try looking at the standard Android animation APIs. Those should handle the timing for you and be smoother anyways -- plus, they'll use the GPU more efficiently for you.
First app ever for me, and first time experiencing with java coding.
I'm building an app for assisting my Rubiks cube speed training, and i'm stuck on my timer.
My general plan is:
I have my main activity screen, where with 1 touch (anywhere on the screen except my 2 buttons) can start a timer. When the timer starts the buttons will fade, and only the timer is visible.
At this moment I have my MainActivity, and a Timer activity. When pressing the screen the timer activity "launches". I then have to press once more to start the timer, this is ok for now, I will fix it somewhat later.
My main goal for now is:
On the timer activity, I want to press and HOLD for at least 2 seconds, and THEN upon release, the timer must start. Hereafter, with a new click, the timer must stop.
I have searched, but it is difficult with minimum knowledge. I have tried a few different things. And what I have is basically something like this.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_timer);
TimerView = (TextView) findViewById(R.id.TextTimerView);
View StopTimeView = (View) findViewById(R.id.StopTimeView);
StopTimeView.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
starttime = SystemClock.uptimeMillis();
timerhandler.postDelayed(timerrunnable,2000);
timestarted = true;
}
if (event.getAction() == MotionEvent.ACTION_UP) {
if(timestarted = true){
timestarted = false;
timerhandler.removeCallbacks(timerrunnable);
}
}
return true;
}
});
}
This code stops when the touch is released. If I remove the last IF sentence, the timer automatically starts after the given 2 seconds, no matter if I hold or not. Furthermore, I need to add an additional button to stop the timer, which I do not want (the ability to be able to stop by touching everywhere is important).
I hope the question is understandable and not to vague. If more of the code is needed, please let me know.
Thanks for your time!
Simply check in your timerrunnable if the button is still pressed. Also, start the onTouch method with a check whether your timer is running. If it is, you know you want to stop it - if it isn't, you can continue with the code you already have.
import greenfoot.*; // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)
public class Turtle extends Actor
{
/**
* Act - do whatever the Turtle wants to do. This method is called whenever
* the 'Act' or 'Run' button gets pressed in the environment.
*/
int laufmenge;
public void act()
{
if(Greenfoot.isKeyDown("left")){
move(-speed);
}
if(Greenfoot.isKeyDown("right")){
move(speed);
}
if(Greenfoot.isKeyDown("up")){
setLocation(getX() ,getY() -speed);
}
if(Greenfoot.isKeyDown("down")){
setLocation(getX() ,getY() +speed);
}
if(Greenfoot.isKeyDown("x")){
if(speed<10) speed++;
}
if(Greenfoot.isKeyDown("y")){
if(speed>0) speed--;
}
System.out.println(speed);
}
private int speed=1;
}
This is code from Greenfoot because i am currently trying to learn coding. I cant understand why when i execute the programm and control the speed he is changing the value by more than one. I guess it will be an easy question.
And is it possible to put the increase and decrease of the speed on one button with two letters like the >< key? i didnt work in my case.
This happens because act() is called in rapid succession. Even if you just press and release x, act() will have run several times while the key is down, and therefore updated the speed several times.
To avoid that, you can track whether or not you've adjusted the speed since the first time you noticed that the button was pressed.
For example, you can have a private bool adjustedSpeed = false; in your class, and then do:
if(Greenfoot.isKeyDown("x")){
if(speed<10 && !adjustedSpeed) speed++;
adjustedSpeed = true;
} else if(Greenfoot.isKeyDown("y")){
if(speed>0 && !adjustedSpeed) speed--;
adjustedSpeed = true;
} else {
adjustedSpeed = false
}
Using the System.currentTimeMillis( ) method how can I detect if at least 200ms have passed in between mouse clicks? I have the following method that passes in a boolean value that tells you if the mouse button is currently pressed down or not. This method is called every 20ms.
public void update(boolean mouseDown)
I thought about using a series of if statements but I just can't get it to work.
if(mouseDown)
{
click = true;
waitTime = System.currentTimeMillis();
}
if(click && (!mouseDown) && (waitTime-System.currentTimMillis()) <= 200)
{
//You got a Double Click
}
else if(click && (!mouseDown))
{
//You got a Single Click
}
The problem is since the method is called every 20ms it always registers it as a double click. It always enters the first if statement and resets the value so I never end up with a time that is greater then 200ms. Any idea how I can fix this?
I'm writing an android app which should take pictures in a user-defined interval (20 sec - 1 min). It should take the pictures even while it is running in background or while the device is sleeping. The app will run for a very long time period. If it is necessary to wake up the device, it should put back to sleep as soon as possible to save batterie life. After taking a picture the app will process some additional work (comparison of two pictures).
I read some stuff about sheduling alarms (http://developer.android.com/training/scheduling/alarms.htm), creating Services (also # android training) and Android AsyncTasks, Java threads (http://www.mergeconflict.net/2012/05/java-threads-vs-android-asynctask-which.html)
... but I'm still not sure what is the best way to achieve this.
My questions are:
Should I use thread or a task to take the pictures in background?
(the comparison of the two pictures might take longer than a few
milliseconds but i don't know anything about the cpu load of this
operation)
Should I use an alarm to wake the device up or are there any alternative solutions?
How can both (alarms and thread/task) work together? (Include the Alarm in the Task/Thread?)
Many thanks for your help in advance.
As to our question I know I can help get started with the aspect of repeating the picture taking task at a user defined time interval. For such a task you can user a Timer to achieve this. The code would look something like this:
mTmr = new Timer();
mTsk = new TimerTask() {
#Override
public void run() {
//Take picture or do whatever you want
}
};
mTmr.schedule(mTsk, 0, USER_DEFINED_EXECUTION_INTERVAL);
schedule begins the timer. The first parameter of schedule used here is the task to run which is mTsk. The second parameter is the delay until the first execution (in milliseconds), in this case no delay. The third parameter is what you'll want to manipulate which is the interval of executions. The parameter is the time between executions so if it were 20 seconds you'd pass in 20,000. If it were a minute it would be 60,000. You can get this value from the user using any method you'd like.
To keep the timer running make sure you don't call mTmr.cancel in onPause because for your case you want to keep the timer running while the user isn't on the app. Not calling cancel means the timer will hold it's resources until the app is closed by the user.
OR you can look at this How to schedule a periodic task in Java? If you'd like to use ScheduledExecutorService instead of a Timer.
I have made this app - Lenx. It uses Camera extensively and I am processing image in the background. I have used AsyncTask to process the image and it has never given any problems. The app also has a timer which starts the process after certain interval. The logic that I have used is very simple.
I have not used Camera2 API yet, so the code might be deprecated. I created CameraPreview class which implements Camera.PreivewCallback.
#Override
public void onPreviewFrame(byte[] data, Camera camera) {
if (data == null) {
return;
}
int expectedBytes = previewWidth * previewHeight *
ImageFormat.getBitsPerPixel(ImageFormat.NV21) / 8;
if (expectedBytes != data.length) {
Log.e(TAG, "Mismatched size of buffer! Expected ");
mState = STATE_NO_CALLBACKS;
mCamera.setPreviewCallbackWithBuffer(null);
return;
}
if (mProcessInProgress || mState == STATE_PROCESS_IN_PROGRESS) {
mCamera.addCallbackBuffer(data);
return;
}
if (mState == STATE_PROCESS) {
mProcessInProgress = true;
processDataTask = new ProcessDataTask();
processDataTask.execute(data);
}
}
public void startProcessing() {
mState = STATE_PROCESS;
}
And my AsyncTask is something like this
private class ProcessDataTask
extends
AsyncTask<byte[], Void, Boolean> {
#Override
protected Boolean doInBackground(byte[]... datas) {
mState = STATE_PROCESS_IN_PROGRESS;
Log.i(TAG, "background process started");
byte[] data = datas[0];
long t1 = java.lang.System.currentTimeMillis();
// process your data
long t2 = java.lang.System.currentTimeMillis();
Log.i(TAG, "processing time = " + String.valueOf(t2 - t1));
mCamera.addCallbackBuffer(data);
mProcessInProgress = false;
return true;
}
#Override
protected void onPostExecute(Boolean result) {
mState = STATE_PROCESS_WAIT;
}
}
onPreviewFrame() will always get called as long as the camera preview is running. You need to take the data and process it only when you trigger something. So simply change the state of a variable, in this case, mState, and based on the state, call your AsyncTask.