Android sensor callback behavior - java

I'm working with a friend trying to develop an android application to track movement by numerically integrating acceleration. We are mechanical engineering students and having trouble understanding how the order of events is occurs within the threads used in an android application. For example it appears that the UI thread runs before the code that called it can finish executing. See the following code that just attempts to get the current acceleration and store the previous acceleration for later use in trapezoidal integration:
import java.util.Arrays;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.widget.TextView;
public class MainActivity extends Activity implements SensorEventListener {
float[] current;
float[] last;
SensorManager sm;
Sensor accelerometer;
TextView Display;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
current = new float[] {0, 0, 0};
last = new float[] {0, 0, 0};
sm = (SensorManager)getSystemService(SENSOR_SERVICE);
accelerometer = sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
sm.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL);
Display = (TextView)findViewById(R.id.text_box);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public void onSensorChanged(SensorEvent event) {
last = current;
current = event.values;
if (last != current) {
Display.setText(Arrays.toString(current)+"\n"+Arrays.toString(last)+"\nThe numbers are not the same!!!");
} else {
Display.setText(Arrays.toString(current)+"\n"+Arrays.toString(last)+"\nThe numbers are the same!!!");
}
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}
The result is that the TextView always displays "the numbers are the same" text.The acceleration values change but the printed current and last values are always the same (ie "[.4423,.12234,9.8234]\n[.4423,.12234,9.8234]\nThe values are the same"). We put a counter in the code to see how often the if statement detects that the values are different and it only increments to one, which I assumes happens on the first iteration. I can't come up with any good theory why the values would change with time but the current and last values are never different. Can the UI thread somehow get the value of last before it is updated by the sensor manager thread? Should I have to deal with handling the order of thread execution if I didn't explicitly create one?

OK so the problem was a fundamental misunderstanding of how Java works. We were passing around the pointers to the array. I have worked with c++ before and thought that since java doesn't use pointers that setting arrays equal to one another was equivalent to passing by value. Doing this actually just set the reference to the current and last variables equal to the reference to the events.value array, which means that the setText function was told to print the values from the same reference. This was a painful way to learn, the Professor who gave us this project is the third person who said to me "if you understand C++, you'll understand java", when he should have said go read a book on the specifics...
To run the above code running we changed:
last = current;
current = event.values;
to this:
System.arraycopy(current,0,last,0,3);
System.arraycopy(event.values, 0, current, 0, 3);

Related

Android Screen Rotation

I'm having this peculiar problem in Android studio. I made this simple app, to understand screen rotation. I understand the concept when the screen rotates the Activity gets destroy, and recall the onCreate method. For you to save data you have to put it in a Bundle by Overriding the onSaveInstanceState method. I made an app with 2 buttons and a number in the middle. the number will change depending on what button is click. But for some reason, when I rotate the screen the number reset, but still kept the value it was on before the screen got to rotate. For Example, if I set the number to 5, and I rotate the screen the number goes to zero, but if I increase it, it goes to 6 if I decrease it goes 4. Somehow it still kept its value but reset to zero, I don't know why. Here's the code
package com.example.android.application;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
Button upButton, downButton;
TextView amount;
int change;
private static final String banza = "Bundle";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState != null) {
change = savedInstanceState.getInt(banza);
}
upButton = (Button) findViewById(R.id.activity_main_up_button);
downButton = (Button) findViewById(R.id.activity_main_down_button);
amount = (TextView) findViewById(R.id.activity_main_textview_id);
upButton.setOnClickListener(this);
downButton.setOnClickListener(this);
}
#Override
public void onClick(View view) {
if (view == upButton) {
change++;
amount.setText(Integer.toString(change));
}
if (view == downButton) {
change--;
amount.setText(Integer.toString(change));
}
}
#Override
protected void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
savedInstanceState.putInt(banza, change);
}
}
You missed the code of
amount.setText(Integer.toString(change));
in onCreate that's why it don't show value while rotating but have correct value when you increment or decrement.

Google Street view + device tilting

I'm trying to add an activity as a feature to an app I'm building where, the API will return a lat long, and with this lat long I will load google street view. Which with the movement of the device, will rotate the 360 degree angle of the position. I'm struggling on the movement part of the device. Using your fingers on the screen you can rotate. I wonder if anyone can point me in the right direction in getting the device movement to affect the position of the street view?
The code I have so far is:
import android.support.v4.app.FragmentActivity;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import com.google.android.gms.maps.OnStreetViewPanoramaReadyCallback;
import com.google.android.gms.maps.StreetViewPanorama;
import com.google.android.gms.maps.StreetViewPanoramaFragment;
import com.google.android.gms.maps.StreetViewPanoramaOptions;
import com.google.android.gms.maps.StreetViewPanoramaView;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.StreetViewPanoramaCamera;
import com.google.android.gms.maps.model.StreetViewPanoramaLocation;
public class MainActivity extends FragmentActivity
implements OnStreetViewPanoramaReadyCallback {
private static final String TAG = MainActivity.class.getSimpleName();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
StreetViewPanoramaFragment streetViewPanoramaFragment =
(StreetViewPanoramaFragment) getFragmentManager()
.findFragmentById(R.id.streetviewpanorama);
streetViewPanoramaFragment.getStreetViewPanoramaAsync(this);
}
#Override
public void onStreetViewPanoramaReady(final StreetViewPanorama panorama) {
final long duration = 1000;
float tilt = 30;
float bearing = 90;
final StreetViewPanoramaCamera camera = new StreetViewPanoramaCamera.Builder()
.zoom(panorama.getPanoramaCamera().zoom)
.bearing(bearing)
.tilt(tilt)
.build();
panorama.setPosition(new LatLng(52.208818, 0.090587));
panorama.setStreetNamesEnabled(false);
panorama.setZoomGesturesEnabled(false);
panorama.setOnStreetViewPanoramaChangeListener(new StreetViewPanorama.OnStreetViewPanoramaChangeListener() {
#Override
public void onStreetViewPanoramaChange(StreetViewPanoramaLocation streetViewPanoramaLocation) {
if (streetViewPanoramaLocation != null) {
panorama.animateTo(camera, duration);
}
Log.d(TAG, "TESTINGGGGGGGGGG");
}
});
}
}
I'm not sure given your question, so comment if i'm wrong but it seems you're able to rotate through this instruction
panorama.animateTo(camera, duration);
and you're moving to a specific location using the "camera" variable you built before.
So, if i understand correctly what you are trying to do, you have to check for mobilephone sensors (accelerometer & position) to get the motion then apply the correct motion to the panorama. Take a look at android sensor documentation in order to get the proper listeners (or how to register a sensor usage) then build the correct camera object according to the acceleration registered by the phone (left acceleration -> rotating left, right acceleration --> rotating right).
If you need a code example i'd suggest you to look this question which has some other links to help you using sensors and getting more doc.
If this does not help, comment and/or clarify the question.

Trying to change background from white to black but can't get this timer() method to run, the screen is only white

I'm trying to make a simple app that changes the background color so many times a second. For example, here I'm trying to do it every 12.5 ms (how do I enter the .5 part?)
I'm extremely new to programming, and can't figure out how to call this method/timer to start running.
I run the app, and it opens the activity with a white background and nothing happens.
Since I'm so new, when I look into the Timer() documentation, I'm not really sure what I'm looking at here.... If someone could help that would be amazing.
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import java.util.Timer;
import java.util.TimerTask;
import static android.support.v7.appcompat.R.attr.background;
/**
* Created by Spader on 3/17/2017.
*/
public class FlashingScreen extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Remove title bar
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
//Remove notification bar
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
//set content view AFTER ABOVE sequence (to avoid crash)
this.setContentView(R.layout.flashing_screen);
new Timer().scheduleAtFixedRate(new TimerTask(){
#Override
public void run(){
runOnUiThread(new Runnable() {
#Override
public void run() {
//stuff that updates ui
getWindow().getDecorView().setBackgroundColor(Color.WHITE);
getWindow().getDecorView().setBackgroundColor(Color.BLACK);
}
;
});
}
},0,12);
}
}
1.
getWindow().getDecorView().setBackgroundColor(Color.WHITE); getWindow().getDecorView().setBackgroundColor(Color.BLACK);
This always set the black color since it is not on a conditional basis. You may want to use a boolean to switch color every time it executes the runnable.
You shouldn't use getDecorView(). Instead find the root View from your layout xml and change the color.
In Java there is no floating value for times. So you can't have 12.5 ms.

Android: addProximityAlert LocationManager Method doesn't send Broadcast

I'm working on an Android Project where i'm using AddProximityAlert method, as you already know this method let you set a proximity alert for the location given by the position (latitude, longitude) and the given radius, and notify you if you are so close to it.
so i was working on that for three days ago and i was getting the same probleme again and again..
in bref: this is my simple code.
#MainActivity.java
package com.example.proximityalert;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.Intent;
import android.content.IntentFilter;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.util.Log;
public class MainActivity extends Activity implements LocationListener {
LocationManager lm;
//Defining Latitude & Longitude
double lat=37.422006 ,long1=-122.084095;
//Defining Radius
float radius=1000;
//Intent Action
String ACTION_FILTER = "com.example.proximityalert";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//i'm registering my Receiver First
registerReceiver(new ProximityReciever(), new IntentFilter(ACTION_FILTER));
//i'm calling ther service Location Manager
lm=(LocationManager) getSystemService(LOCATION_SERVICE);
//for debugging...
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 10, this);
//Setting up My Broadcast Intent
Intent i= new Intent(ACTION_FILTER);
PendingIntent pi = PendingIntent.getBroadcast(getApplicationContext(), -1, i, 0);
//setting up proximituMethod
lm.addProximityAlert(lat, long1, radius, -1, pi);
}
#Override
//just For debugging to See the distance between my actual position and the aproximit point
public void onLocationChanged(Location newLocation) {
Location old = new Location("OLD");
old.setLatitude(lat);
old.setLongitude(long1);
double distance = newLocation.distanceTo(old);
Log.i("MyTag", "Distance: " + distance);
}
#Override
public void onProviderDisabled(String arg0) {}
#Override
public void onProviderEnabled(String arg0) {}
#Override
public void onStatusChanged(String arg0, int arg1, Bundle arg2) {}
}
#ProximityReceiver.java
package com.example.proximityalert;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.location.LocationManager;
import android.util.Log;
import android.widget.Toast;
public class ProximityReciever extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// Key for determining whether user is leaving or entering
String key = LocationManager.KEY_PROXIMITY_ENTERING;
//Gives whether the user is entering or leaving in boolean form
boolean state = intent.getBooleanExtra(key, false);
if(state){
// Call the Notification Service or anything else that you would like to do here
Log.i("MyTag", "Welcome to my Area");
Toast.makeText(context, "Welcome to my Area", Toast.LENGTH_SHORT).show();
}else{
//Other custom Notification
Log.i("MyTag", "Thank you for visiting my Area,come back again !!");
Toast.makeText(context, "Thank you for visiting my Area,come back again !!", Toast.LENGTH_SHORT).show();
}
}
}
*#the probleme is when i run the program , the BroadcastReceiver(ProximityReciever) never never called by the system even if i'm veryyy close to the proximit point, and even if the debugger shows me that distance between the two locations is < 1000m :/
I just figured out somthing about this topic and why the addProximityAlert sames to be not working, I'm sharing this with you because I noticed that some people asked the same question before and they don't get any answer!
The answer was just in front of me but i didn't pay attention to it, so when i was reading the Android officiel documentation (here) i saw this sentence "Due to the approximate nature of position estimation, if the device passes through the given area briefly, it is possible that no Intent will be fired"
what is that mean? it means when you are testing your app on the AVD and u send a gps coordinates(latitude, longitude) from the DDMS to AVD its really hard to
simulate the real aspect of a gps, (because in the first place u pick some point to be your proximPoint and just after that you choose anthor point very far from the proximPoint to see if its work) and thats not what it's happing with a real device.
so the solution is to test your app on a real device or with the DDMS try to change the coordiantes very slowly until you are in the zone wanted.

Simple OpenGL ES 2.0 app on Android displaying blank screen: why?

So I'm following the book Open GL ES 2 for Android by Kevin Brothaler and I'm trying out the first chapter's project, which is basically coloring the screen red. I set up by Samsung Galaxy Note 3 so I can debug my app on there, and also set up an emulator that uses the host GPU for rendering. Also, I forced GPU rendering on my phone. I copied the code he had exactly into my eclipse project. Here's the code for reference:
package com.firstopenglproject.android;
import android.app.Activity;
import android.app.ActivityManager;
import android.content.Context;
import android.content.pm.ConfigurationInfo;
import android.opengl.GLSurfaceView;
//import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
public class FirstOpenGLProjectActivity extends Activity {
private static final String TAG = FirstOpenGLProjectActivity.class.getSimpleName();
private GLSurfaceView glSurfaceView;
private boolean rendererSet = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "Before calling super.onCreate()");
super.onCreate(savedInstanceState);
Log.d(TAG, "Before creating a new GLSurfaceView");
glSurfaceView = new GLSurfaceView(this);
Log.d(TAG, "Creating activity manager");
final ActivityManager activityManager =
(ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
Log.d(TAG, "Creating configuration info");
final ConfigurationInfo configurationInfo =
activityManager.getDeviceConfigurationInfo();
Log.d(TAG, "Getting supportsEs2 boolean");
final boolean supportsEs2 = configurationInfo.reqGlEsVersion >= 0x20000;
// || (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1
// && (Build.FINGERPRINT.startsWith("generic")
// || Build.FINGERPRINT.startsWith("unknown")
// || Build.MODEL.contains("google_sdk")
// || Build.MODEL.contains("Emulator")
// || Build.MODEL.contains("Android SDK built for x86")));
Log.d(TAG, "supportsEs2 = " + supportsEs2);
if (supportsEs2) {
// Request an OpenGLES2 compatible context
glSurfaceView.setEGLContextClientVersion(2);
glSurfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 0);
// Assign our renderer
glSurfaceView.setRenderer(new FirstOpenGLProjectRenderer());
rendererSet = true;
Toast.makeText(this, "Device supports OpenGL ES 2.0", Toast.LENGTH_LONG).show();
Log.d(TAG, "rendererSet is true");
} else {
Log.d(TAG, "OGLES2.0 not supported");
Toast.makeText(this, "This device does not support OpenGL ES 2.0", Toast.LENGTH_LONG).show();
return;
}
}
#Override
protected void onPause() {
super.onPause();
if (rendererSet) {
glSurfaceView.onPause();
}
}
#Override
protected void onResume() {
super.onResume();
if (rendererSet) {
glSurfaceView.onResume();
}
}
}
The logging tasks were ones that I added so that I can see whether the code is executing properly, and it is: I see all these log messages in LogCat. Here's the code for the renderer:
package com.firstopenglproject.android;
import static android.opengl.GLES20.GL_COLOR_BUFFER_BIT;
import static android.opengl.GLES20.glClear;
import static android.opengl.GLES20.glClearColor;
import static android.opengl.GLES20.glViewport;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.opengl.GLSurfaceView.Renderer;
public class FirstOpenGLProjectRenderer implements Renderer {
private static final String TAG = FirstOpenGLProjectRenderer.class.getSimpleName();
/*
* GLSurfaceView calls this when its time to draw a frame. We must
* draw something, even if its only to clear the screen. The rendering buffer
* will be swapped and displayed on the screen after this method returns,
* so if we don't draw anything, we'll probably get a bad flickering effect.
* */
#Override
public void onDrawFrame(GL10 arg0) {
// clear the rendering surface
glClear(GL_COLOR_BUFFER_BIT);
}
/*
* GLSurfaceView calls this after the surface is created and whenever the size has
* changed. A size change can occur when switcheing from portrait to landscape
* and vice versa.
*/
#Override
public void onSurfaceChanged(GL10 glUnused, int width, int height) {
// set the openGL viewport to fill the entire surface
glViewport(0, 0, width, height);
}
/*
* GLSurfaceView calls this when the surface is created. This happens the first
* time our application is run, and it may also be called when the device wakes
* up or when the user switches back to our activity. In practice, this means that
* this method may be called multiple times while our application is still running.
*/
#Override
public void onSurfaceCreated(GL10 arg0, EGLConfig arg1) {
glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
}
}
As you can see, I only use 3 calls to static methods in the GLES20 package. When I run this app on my phone and on my emulator I get a blank screen: what is going on? I've been banging my head on the table for the last 2 hours about this, and this is as simple as it could possibly get. It's supposed to display a red screen. Thanks a bunch!
you are not setting the view in your OnCreate() method at the end of that method add:
setContentView(glSurfaceView);

Categories