MapActivity Force Closes, Touch Event fires recklessly - java

I have a MapActivity which has a touch event.
In the touch event:
I get the current geocodes
Put an overlay image on that location.
and set it as the center of the mapview.
This seems to work fine and as expected for a while. But then the application force closes. I think the touch event is being fired like crazy even when nothing's being touched. I know that because I had put a toast set up that shows the longitude and lattitude of the touched position. and it keeps showing up even when nothing's touched.
I cant seem to accurately position the problem, let alone fixing it. Here's the touch event for my mapActivity
private void LocationStuffs(double latitude, double longitude){
itemizedOverlay.clear();
itemizedOverlay.addOverlayItem((int)latitude, (int)longitude, "place");
mapView.invalidate();
mapView.getOverlays().add(itemizedOverlay);
MapController mc = mapView.getController();
mc.setCenter(new GeoPoint((int)latitude, (int)longitude));
mc.setZoom(20);
}
public boolean onTouchEvent(MotionEvent event, MapView mapView){
//---when user lifts his finger---
if (event.getAction() == 1) {
GeoPoint p = mapView.getProjection().fromPixels(
(int) event.getX(),
(int) event.getY());
Toast.makeText(getBaseContext(),
p.getLatitudeE6() / 1E6 + "," +
p.getLongitudeE6() /1E6 ,
Toast.LENGTH_SHORT).show();
latitude = p.getLatitudeE6() / 1E6;
longitude = p.getLongitudeE6() / 1E6;
LocationStuffs(latitude*1E6, longitude*1E6);
}
return false;
}

Change your return statement to return true:
return true;
Basically, what that does is that it tells the system that you have handled the touchevent. Let me know if that solves it.

I believe you have few errors in your code:
1- You need a "return true" statement before you close the "if" statement in the "onTouchEvent" method. This tells the system that the event has been handled and it should be consumed. That's probably the reason for multiple touchs.
2- the "mapView.invalidate();" should be moved to the end of your "LocationStuffs" method, as you want to have you screen redrawn after you have add the new location and not before.
3- You are adding repeatedly the same itemizedOverlay to the mapview. After calling your "LocationStuffs" method 10 times, you will have the same overlay added 10 times to the overlays list. You should add the Itemizedoverlay only once, outside this method (on the onCreate or onResume for example)
good luck

Related

OnSensorChanged Being Called More Than Intended

I'm trying to develop an app that detects a fall and so far the accuracy of a fall is in an acceptable range but the problem is the "OnSensorChanged" gets invoked way too frequently causing the toast to appear on my screen constantly.
I think the problem is that during a free fall, the "OnSensorChanged" keeps on getting called for the duration of the fall (since the values correspond to a fall) which is whats causing the toast spam on my screen.
A solution i tried is to unregister the listener after a fall so that it only appears once but the problem is that it wont detect a fall again unless i restart the app (because obviously the listener stopped working).
Is there any solution to this issue?
Thanks
private void checkFall(SensorEvent xyzValues) {
float[] values = xyzValues.values;
double rootSquare = Math.sqrt(Math.pow(values[0],2)+Math.pow(values[1],2)+Math.pow(values[2],2));
if (rootSquare < 1.5){
Toast toast = Toast.makeText(this, "The Phone Fell!", Toast.LENGTH_LONG);
toast.show();
sensorManager.unregisterListener(this);
sensorManager = null;
}
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
checkFall(event);
}
}
You can make use of a member boolean variable, mFallen that keeps track of when a fall has just occurred. You might also want to define some threshold value to indicate when the phone is back to a normal "standing" state. Try the following:
if (rootSquare < 1.5 && !mFallen){
Toast toast = Toast.makeText(this, "The Phone Fell!", Toast.LENGTH_LONG);
toast.show();
mFallen = true;
} else if (rootSquare > STANDING_THRESHOLD) {
mFallen = false;
}
Better Standing Detection Algorithm
Once the state of mFallen has changed from false to true, the magnitude of the device's acceleration vector (as you've calculated and stored in rootSquare) should be very close to 0. This is because when the device is in free-fall (falling all by itself), its acceleration will be that of gravity from the reference frame of a standing person. But in theory, the accelerometer would only be measuring values relative to free-fall, and therefore it would be exactly 0.
Since the acceleration of gravity is approximately 9.81 m/s^2, to detect when the device is not moving again, you'd need to check when the magnitude of acceleration is close to that. This is because while still, the sensor will be detecting the force that is preventing it from falling (canceling the acceleration due to gravity) which are the forces of whatever is keeping it still. The overall magnitude of the accelerations due to these forces must sum up exactly to the magnitude of the acceleration due to gravity in this case.
You could define a constant GRAVITY to be 9.81, and GRAVITY_THRESHOLD to be a tolerance value, which you can try setting to 0.1 and then refining later on. Try replacing your code with the following:
if (rootSquare < 1.5 && !mFallen){
Toast toast = Toast.makeText(this, "The Phone Fell!", Toast.LENGTH_LONG);
toast.show();
mFallen = true;
} else if (Math.abs(rootSquare - GRAVITY) < GRAVITY_THRESHOLD) {
mFallen = false;
}
Just to emphasize, the standing state here is defined as only when the device has stopped moving, so it won't be able to detect when the phone has reached a certain height with respect to the ground.
Please see https://developer.android.com/reference/android/hardware/SensorEvent.html#values, as it may help you understand the problem better.

How to make a similar animation to Flappy Bird in Libgdx?

I'm creating a game like flappy bird where the bird flaps his wings only when the screen is touched, but I'm having a problem activating the animation when the screen is touched.
batch.draw(animation.getKeyFrame(myTimeState, false), x, y); //the myTimeState is 0 to render the 1st frame only.
Then when the screen is touched I do this:
//myTimeStep is just basically a controllable timeState for the animation only
if(Gdx.input.justTouched){
myTimeState = timeState;
}else if(Gdx.input.justTouched == false && animation.isAnimationFinished(timeState)){
myTimeState = 0;
}
I don't think the animation is able to play all the frames because myTimeStep become 0 immediately after finishing to touch the screen. Also I don't think this is the right way of doing it, if you guys have better ideas or solution please help. Thanks in advance.
There are probably several ways to achieve this. You'll need to increment your timeState, of course, and also it depends how long your animation is and if you want it to loop.
If you've created your animation to play only once, and then stop (until the screen is touched again), you could simply set your myTimeState to 0 when the screen is touched, and then increment it every frame. The animation will run through and then "stop" on its own when it reaches the end (as you said no loop). The next time someone touches the screen, your myTimeState is set back to 0 and the animation starts again.
Firstly, you have to ensure your animation's playmode is set to Animation.PlayMode.NORMAL. It's a default setting, but if you set it somewhere to LOOPED, nothing would work as expected.
Secondly, I wouldn't use Input.justTouched() in this case. Instead, a listener in your input processor would be a great fit. Here's an example with Stage. If you have no idea what input processor is, here's tutorial on event handling and class documentation.
stage.addListener(new ClickListener() {
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
if(button == Input.Buttons.LEFT) {
timeState = 0;
}
return super.touchDown(event, x, y, pointer, button);
}
});
You can pick what's going to be displayed (animation's keyframe or sprite) based on result of animation.isAnimationFinished()
if(animation.isAnimationFinished(timeState)) {
//draw some sprite
} else {
//draw animation keyframe
}
I haven't checked it but there's a possibility, that this could lead to the last frame being cut out, because as soon as it gets displayed, animation.isAnimationFinished() will return true. I may be wrong, so you'll have to check it. If it becomes an issue, you can add your sprite as the last frame of your animation. When animation ends, it frezzes on the last frame, which would be your static sprite.
In both cases you'll get your animation played at the beginning of game because timeStep equal to 0. I see 2 solutions, I advise you to take the second:
Set timeStep to a large number, that is for sure larger than your animation's duration. Animation.isAnimationFinished() will then return true.
Introduce boolean variable isAnimationPlayed that:
is initialized with false,
gets set to true in your click listener,
gets set to false during isAnimationFinished(), which is called each frame only when isAnimationPlayed is true,
is used in draw() method to determine what to display.
You could just set your timeState to the duration of the animation.

Which component can I use in Android Studio for the purpose of creating a touchpad?

I've been searching for a View/Component in Android Studio that I could use for creating a touchpad. I need the ability to track mouse movements, so that I use that information on the server side to handle it and emulate mouse movements.
What would be the best fit for that purpose?
That would be a ScrollView or a HorizontalScrollView.
Unfortunately, Shishdem's answer didn't satisfy me. What I basically was trying to achieve is to make a prototype of a touchpad for a school project. ScrollView contains elements that are to be scrolled within, and I needed to track finger movements information that is suitable to be handled for moving cursor on PC by my server application.
I found solution here: Track touch and pointer movements
I needed to create an android.view.VelocityTracker and track touch velocity to further send that data to my PC server and simulate mouse movements via java.awt.Robot within onTouchEvent. The component could be anything, a Button in my case.
Here's the working code for the class that handles touch event of a touchpad view:
private VelocityTracker mVelocityTracker = null;
#Override
public boolean onTouchEvent(MotionEvent event) {
int index = event.getActionIndex();
int action = event.getActionMasked();
int pointerId = event.getPointerId(index);
switch(action) {
case MotionEvent.ACTION_DOWN:
if(mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
else {
mVelocityTracker.clear();
}
mVelocityTracker.addMovement(event);
break;
case MotionEvent.ACTION_MOVE:
mVelocityTracker.addMovement(event);
mVelocityTracker.computeCurrentVelocity(1000);
// Log velocity of pixels per second
// Those values can be used to be sent to the server
Log.d("Velocity", "X velocity: " + mVelocityTracker.getXVelocity(pointerId));
Log.d("Velocity", "Y velocity: " + mVelocityTracker.getYVelocity(pointerId));
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
mVelocityTracker.recycle();
mVelocityTracker = null;
break;
}
return true;
}
In case of crash
Note that in the example of the link above there isn't this line:
mVelocityTracker.recycle();
mVelocityTracker = null; // this line
But in my case, if I didn't assign mVelocityTracker to null every recycle, it would crash with the following errors:
2021-10-05 09:30:21.711 4385-4385/com.example.javaapp E/InputEventReceiver: Exception dispatching input event.
2021-10-05 09:30:21.711 4385-4385/com.example.javaapp E/MessageQueue-JNI: Exception in MessageQueue callback: handleReceiveCallback
2021-10-05 09:30:21.713 4385-4385/com.example.javaapp E/MessageQueue-JNI: java.lang.IllegalStateException: Already in the pool!
at android.util.Pools$SimplePool.release(Pools.java:120)
at android.util.Pools$SynchronizedPool.release(Pools.java:179)
at android.view.VelocityTracker.recycle(VelocityTracker.java:87)
More on that issue: VelocityTracker causes crash on Android 4.4

android: major prob with detecting angle of device inclination

For a project I need to detect the inclination (pitch) of an android device. For that, I use the acceleration sensor and the magnetic field sensor and everything works fine. The device is able to move forward and backward hanging on a pendulum. If I have the angle of the pendulum/device, I can calculate the acceleration. The problem is: All that works only stationary. If the device is in a car which is moving, it doesnn't work any more. When the car is braking, the pendulum moves forward and the inclination changes, but the device cannot detect that because the force is still acting "downward" along the y-axis.
Is it any possible to detect the inclination angle in this case?
Not sure if I've explained my problem clearly. What I need is the angle of a moving pendulum, detected by device sensors.
<< EDIT >>
What I need is the correctly measrued angle of the pendulum even when it is within a moving car (please take a look at my pdf lying in my Dropbox):
https://dl.dropboxusercontent.com/u/5655235/sensors.pdf
As you can see on the image, the measured angle is not correct if the box is accelerating.
Here is my code:
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
acc = event.values;
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
mag = event.values;
if (acc != null && mag != null) {
float R[] = new float[9];
float I[] = new float[9];
boolean success = SensorManager.getRotationMatrix(R, I, acc, mag);
if (success) {
float orientation[] = new float[3];
SensorManager.getOrientation(R, orientation);
phiRad = orientation[1];
phi = Math.toDegrees(phiRad);
}
}
I hope that I understood your problem correctly!! So you want to detect the inclination of the device when it is in a moving car...
First of all, when you say that:
When the car is braking, the pendulum moves forward and the inclination changes, but the device cannot detect that because the force is still acting "downward" along the y-axis.
Are you sure that the device is kept vertically straight?
So, when the car is moving the pendulum will obtain an acceleration of the car in forward direction. Here, forward doesn't mean that it is directed towards x-axis of the device, but the x-axis of the car/surface. As per my understanding, you are trying to check the pendulum's movement towards x-axis, but you should check for the position of device. Hope it helps, if I understood your problem correctly.

Android - How to handle two finger touch

The documentation say this about that:
A gesture starts with a motion event with ACTION_DOWN that provides
the location of the first pointer down. As each additional pointer
that goes down or up, the framework will generate a motion event with
ACTION_POINTER_DOWN or ACTION_POINTER_UP accordingly.
So i have done the override of onTouchEvent function in my activity:
#Override
public boolean onTouchEvent(MotionEvent MEvent)
{
motionaction = MEvent.getAction();
if(motionaction == MotionEvent.ACTION_DOWN)
{
System.out.println("DEBUG MESSAGE POINTER1 " + MEvent.getActionIndex() );
}
if(motionaction == MotionEvent.ACTION_POINTER_DOWN)
{
System.out.println("DEBUG MESSAGE POINTER2 " + MEvent.getActionIndex() );
}
}
Unfortunately the second if is never entered. The activity contains 2 view with 2 OnTouchListener, i know that onTouchEvent is called only if the view of the activity don't consume the event so i tried to return false in the listener and in that way i can recognize only the first finger touch but this avoid the listener to receive the ACTION_UP event and don't allow me to recognize the second finger touch. I also tried to return true in the listener but after manually invoke the onTouchEvent function but this allow me to recognize only the first finger touch too.
What's wrong in my code ?
I believe your code is missing the masking operation like:
switch (motionaction & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_POINTER_DOWN:
}
This code should be able to check for ACTION_POINTER_DOWN.
Good luck & tell us what happens.
Tommy Kwee

Categories