Android compass showing only view but not moving as expected on a few devices.
This is getting frustrating now. I just completed an app which shows a compass. It was working fine on my Samsung s4 and a few other devices, but when I send the apk file for testing the worst just came out that compass is not working on a few devices, including client device. Till then, I have tried 2, 3 different type of codes which I found on stackoverflow and a few other sites. All of them are working fine on my s4 but not on the client's device.
I'm sharing this code.
I've tested this code in some android 6.0 devices too and it was working just fine. I'm totally not getting where's the error.
Any help will be highly appreciated
public class QiblaActivity extends AppCompatActivity implements SensorEventListener {
private ImageView qiblaNSEW, qiblaIcon;
private float currentDegree = 0f;
private float currentDegree1 = 0f;
RelativeLayout back_Rel, bulb_Rel;
// device sensor manager
private SensorManager mSensorManager;
TextView degreeTV;
AdRequest adRequest;
double angle;
GPSTracker gpsTracker;
Location location;
private static final int PERMS_REQUEST_CODE = 123;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_qibla);
Utils.statusBarColor(getWindow(), QiblaActivity.this);
back_Rel = (RelativeLayout) findViewById(R.id.back_Rel);
bulb_Rel = (RelativeLayout) findViewById(R.id.bulb_Rel);
bulb_Rel.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(QiblaActivity.this, QuranBulbActivity.class);
startActivity(intent);
}
});
back_Rel.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
finish();
}
}
);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (hasPermissions())
{
gpsTracker = new GPSTracker(this);
if (gpsTracker.canGetLocation()) {
startQibla();
}
}
else
{
requestPerms();
}
} else {
gpsTracker = new GPSTracker(this);
if (gpsTracker.canGetLocation()) {
startQibla();
} else {
gpsTracker.showSettingsAlert();
}
}
}
private void startQibla() {
qiblaNSEW = (ImageView) findViewById(R.id.qibla_n_s_e_w);
qiblaIcon = (ImageView) findViewById(R.id.qibla_icon);
degreeTV = (TextView) findViewById(R.id.degree_TV);
mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
setAds();
angle = getAngle();
gpsTracker = new GPSTracker(this);
location = gpsTracker.getLocation();
Log.d("angle", angle + "");
}
#Override
protected void onResume() {
super.onResume();
mSensorManager.registerListener(this, mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION),
SensorManager.SENSOR_DELAY_GAME);
/* mSensorManager.registerListener(this, mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE),
SensorManager.SENSOR_DELAY_NORMAL);*/
}
#Override
protected void onPause() {
super.onPause();
mSensorManager.unregisterListener(this);
}
#Override
public void onSensorChanged(SensorEvent sensorEvent) {
float degree = Math.round(sensorEvent.values[0]);
degreeTV.setText((Float.toString(Math.round(degree - angle)) + "").replace(".0", "").replace("-", ""));
// create a rotation animation (reverse turn degree degrees)
RotateAnimation ra = new RotateAnimation(
currentDegree,
-degree,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF,
0.5f);
// how long the animation will take place
ra.setDuration(210);
// set the animation after the end of the reservation status
ra.setFillAfter(true);
// Start the animation
qiblaNSEW.startAnimation(ra);
currentDegree = -degree;
float tempDegreeNorth = degree;
if (tempDegreeNorth > 180) {
tempDegreeNorth = 360 - tempDegreeNorth;
} else {
tempDegreeNorth = 0 - tempDegreeNorth;
}
Log.d(" north - angle - total", tempDegreeNorth + " - " + angle + " - " + Math.round(tempDegreeNorth + angle));
RotateAnimation raa = new RotateAnimation(
Math.round(tempDegreeNorth + angle),
0.0f,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF,
0.5f);
// how long the animation will take place
raa.setDuration(210);
// set the animation after the end of the reservation status
raa.setFillAfter(true);
qiblaIcon.startAnimation(raa);
currentDegree1 = -tempDegreeNorth;
}
private double getAngle() {
GPSTracker gpsTracker = new GPSTracker(this);
double lat1 = toRad(gpsTracker.getLocation().getLatitude());
double lat2 = toRad(21.4266700);
double lon1 = toRad(gpsTracker.getLocation().getLongitude());
double lon2 = toRad(39.8261100);
double dLon = (lon2 - lon1);
double y = sin(dLon) * cos(lat2);
double x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dLon);
double brng = Math.toDegrees(atan2(y, x));
brng = (brng + 360);
brng = (brng > 360) ? (brng - 360) : brng;
return brng;
}
double toRad(double value) {
value = value * Math.PI / 180;
return value;
}
#Override
public void onAccuracyChanged(Sensor sensor, int i) {
}
private void setAds() {
final AdView adViews = (AdView) this.findViewById(R.id.adView);
adRequest = new AdRequest.Builder()
.addTestDevice("253A8ECF2C80597926D6578953E69959").build();
adViews.loadAd(adRequest);
}
private boolean hasPermissions() {
int res = 0;
//string array of permissions,
String[] permissions = new String[]{Manifest.permission.ACCESS_FINE_LOCATION};
for (String perms : permissions) {
res = checkCallingOrSelfPermission(perms);
if (!(res == PackageManager.PERMISSION_GRANTED)) {
return false;
}
}
return true;
}
private void requestPerms() {
String[] permissions = new String[]{Manifest.permission.ACCESS_FINE_LOCATION};
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(permissions, PERMS_REQUEST_CODE);
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
boolean allowed = true;
switch (requestCode) {
case PERMS_REQUEST_CODE:
for (int res : grantResults) {
// if user granted all permissions.
allowed = allowed && (res == PackageManager.PERMISSION_GRANTED);
}
break;
default:
// if user not granted permissions.
allowed = false;
break;
}
if (allowed) {
//user granted all permissions we can perform our task.
} else {
// we will give warning to user that they haven't granted permissions.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION)) {
Toast.makeText(this, "GPS Permissions denied.", Toast.LENGTH_SHORT).show();
}
}
}
}
}
Related
Due to the power consuming GPS data, I would like to calculate the device speed with only the accelerometer x,y and z data. I have read a lot of questions about this topic and I tried many set-ups to find a satisfactory solution to calculate the speed when my device is in my car.
It seems so simple but nothing works, which drives me crazy.
Been trying the Sensor.TYPE_LINEAR_ACCELERATION and the Sensor.TYPE_ACCELEROMETER with removed gravity. Tried a Low Pass Filter on the Linear acceleration data. Unfortunately all with no succes.
Looks like the calculated speed is correct but testing in my car the calculated speed doesn't get higher then about 2 m/s.
below a code snip
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION);
public void onSensorChanged(SensorEvent event) {
if (event.sensor == mAccelerometer) {
if (timestamp != 0) {
final float dT = (event.timestamp - timestamp) * NS2S;
lax = event.values[0];
lay = event.values[1];
laz = event.values[2];
vx = vxo + lax * dT ;
vy = vyo + lay * dT ;
vz = vzo + laz * dT ;
speed = (float) (Math.sqrt(vx*vx + vy*vy + vz*vz)) ;
if (speed < 0.01) {speed = 0 ; }
tv_speed.setText(String.valueOf(speed));
}
timestamp = event.timestamp;
}
}
Hope someone can help, thanks a lot.
It's possible to compute distance and speed using only accelerometer, but with three conditions:
1. Linear movement - trajectory must be straight.
2. Slope of the road must be constant.
3. You must perform calibration procedure before start.
Where can you use this method with such restrictions - it's up to you... Now, how to do it:
We need something, implementing SensorEventListener interface. For the future use, let's add following abstract class:
public abstract class Accelerometer implements SensorEventListener {
protected float lastX;
protected float lastY;
protected float lastZ;
public abstract Point getPoint();
public void onAccuracyChanged(Sensor arg0, int arg1) {
}
}
and this will be our SensorEventListener:
public class XYZAccelerometer extends Accelerometer {
private static final int BUFFER_SIZE = 500;
// calibration
private float dX = 0;
private float dY = 0;
private float dZ = 0;
// buffer variables
private float X;
private float Y;
private float Z;
private int cnt = 0;
// returns last SenorEvent parameters
public Point getLastPoint(){
return new Point(lastX, lastY, lastZ, 1);
}
// returrns parameters, using buffer: average acceleration
// since last call of getPoint().
public Point getPoint(){
if (cnt == 0){
return new Point(lastX, lastY, lastZ, 1);
}
Point p = new Point(X, Y, Z, cnt);
reset();
return p;
}
// resets buffer
public void reset(){
cnt = 0;
X = 0;
Y = 0;
Z = 0;
}
public void onSensorChanged(SensorEvent se) {
float x = se.values[SensorManager.DATA_X] + dX;
float y = se.values[SensorManager.DATA_Y] + dY;
float z = se.values[SensorManager.DATA_Z] + dZ;
lastX = x;
lastY = y;
lastZ = z;
X+= x;
Y+= y;
Z+= z;
if (cnt < BUFFER_SIZE-1) {
cnt++;
} else
{
reset();
}
}
public int getCnt(){
return cnt;
}
public void setdX(float dX) {
this.dX = dX;
}
public void setdY(float dY) {
this.dY = dY;
}
public void setdZ(float dZ) {
this.dZ = dZ;
}
}
Calibrating accelerometer must be called before each experiment. Phone orientation must not be changed while measuring.
To calibrate accelerometer, i use this class:
public class Calibrator {
final static int UPDATE_INTERVAL = 400;
final static int ITERATIONS = 5;
Handler hRefresh;
XYZAccelerometer acc;
int eventNumber;
private LinkedList calData;
public Calibrator(Handler hRefresh, XYZAccelerometer acc, int eventNumber) {
this.hRefresh = hRefresh;
this.acc = acc;
this.eventNumber = eventNumber;
}
public void calibrate() {
final Timer calTimer = new Timer();
calData = new LinkedList();
acc.setdX(0);
acc.setdY(0);
acc.setdZ(0);
calTimer.scheduleAtFixedRate(
new TimerTask() {
public void run() {
addCalData(calData);
if (calData.size() > ITERATIONS) {
calTimer.cancel();
try {
calSensor(calData);
} catch (Exception ex) {
try {
throw ex;
} catch (Exception ex1) {
hRefresh.sendEmptyMessage(5);
}
}
hRefresh.sendEmptyMessage(eventNumber);
}
}
},
0,
UPDATE_INTERVAL);
}
private void addCalData(LinkedList cD) {
Point p = acc.getPoint();
cD.add(p);
acc.reset();
}
private void calSensor(LinkedList cD) throws Exception {
if (cD.size() < ITERATIONS-1) {
throw new Exception("not enough data to calibrate");
}
float x = 0;
float y = 0;
float z = 0;
// Don't use first measure
for (int i = 1; i < cD.size(); ++i) {
x += cD.get(i).getX();
y += cD.get(i).getY();
z += cD.get(i).getZ();
}
x = x / (cD.size() - 1);
y = y / (cD.size() - 1);
z = z / (cD.size() - 1);
acc.setdX(-x);
acc.setdY(-y);
acc.setdZ(-z);
}
}
maintenance class to keep data of one measure
public class Point {
private float x = 0;
private float y = 0;
private float z = 0;
private int cnt = 1;
public float getX() {
return x/(float)cnt;
}
public float getY() {
return y/(float)cnt;
}
public float getZ() {
return z/(float)cnt;
}
public Point(float x, float y, float z, int cnt) {
this.x = x;
this.y = y;
this.z = z;
this.cnt = cnt;
}
public float getForce(){
return getX()*getX()+getY()*getY()+getZ()*getZ();
}
}
And class to process data of measure
public class MeasurePoint {
private float x;
private float y;
private float z;
private float speedBefore;
private float speedAfter;
private float distance;
private float acceleration;
private long interval;
private Point averagePoint;
public MeasurePoint(float x, float y, float z, float speedBefore, long interval, Point averagePoint) {
this.x = x;
this.y = y;
this.z = z;
this.speedBefore = speedBefore;
this.interval = interval;
this.averagePoint = averagePoint;
speedAfter = 0;
calc();
}
private void calc(){
//Acceleration as projection of current vector on average
acceleration = this.x*averagePoint.getX() +
this.y*averagePoint.getY() +
this.z*averagePoint.getZ();
acceleration = acceleration / ((float)Math.sqrt(averagePoint.getForce()));
float t = ((float)interval / 1000f);
speedAfter = speedBefore + acceleration * t;
distance = speedBefore*t + acceleration*t*t/2;
}
public String getStoreString(){
String s = "write here whatever you want";
return s;
}
// add getters
}
This one - to store and save data array
public class MeasureData {
// points from accelerometr
private LinkedList accData;
private LinkedList data;
// timer interval of generating points
private long interval;
public MeasureData(long interval) {
this.interval = interval;
accData = new LinkedList ();
data = new LinkedList ();
}
public void addPoint(Point p){
accData.add(p);
}
public void process(){
for(int i = 0; i < accData.size(); ++i){
Point p = accData.get(i);
float speed = 0;
if(i > 0){
speed = data.get(i-1).getSpeedAfter();
}
data.add(new MeasurePoint(p.getX(), p.getY(), p.getZ(), speed, interval, getAveragePoint()));
}
}
public boolean saveExt(Context con, String fname) throws Throwable {
try {
File file = new File(con.getExternalFilesDir(null), fname);
FileOutputStream os = new FileOutputStream(file);
OutputStreamWriter out = new OutputStreamWriter(os);
for (int i = 0; i < data.size(); ++i) {
MeasurePoint m = data.get(i);
out.write(m.getStoreString());
}
out.close();
} catch (Throwable t) {
throw (t);
}
return true;
}
private Point getAveragePoint() {
float x = 0;
float y = 0;
float z = 0;
for(int i = 0; i < accData.size(); ++i){
Point p = accData.get(i);
x += p.getX();
y += p.getY();
z += p.getZ();
}
return new Point(x, y, z, 1);
}
public float getLastSpeed(){
return data.getLast().getSpeedAfter();
}
public float getLastSpeedKm(){
float ms = getLastSpeed();
return ms*3.6f;
}
}
And, finally, how to use all this in your activity(I cleaned it up a lot, sorry if it will not complie - fill free to write it in comments:
public class TestActivity extends Activity {
static final int TIMER_DONE = 2;
static final int START = 3;
static final int CAL_TIMER_DONE = 4;
static final int ERROR = 5;
private StartCatcher mStartListener;
private XYZAccelerometer xyzAcc;
private SensorManager mSensorManager;
private static final long UPDATE_INTERVAL = 500;
private static final long MEASURE_TIMES = 20;
private Timer timer;
private TextView tv;
private Button testBtn;
int counter;
private MeasureData mdXYZ;
/** handler for async events*/
Handler hRefresh = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case TIMER_DONE:
onMeasureDone();
String es1 = Float.toString(Math.round(mdXYZ.getLastSpeedKm()*100)/100f);
tv.append(" END SPEED " + es1 + " " + es2 + " \n");
enableButtons();
break;
case START:
tv.append(" START");
timer = new Timer();
timer.scheduleAtFixedRate(
new TimerTask() {
public void run() {
dumpSensor();
}
},
0,
UPDATE_INTERVAL);
break;
case ERROR:
Toast.makeText(getApplicationContext(), "ERROR", Toast.LENGTH_SHORT).show();
break;
}
}
};
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
tv = (TextView) findViewById(R.id.txt);
testBtn = (Button) findViewById(R.id.btn);
}
#Override
protected void onResume() {
super.onResume();
tv.append("\n ..");
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
setAccelerometer();
setStartCatcher();
mSensorManager.registerListener(xyzAcc,
mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_GAME);
}
#Override
protected void onPause() {
mSensorManager.unregisterListener(xyzAcc);
super.onPause();
}
public void onButtonTest(View v) {
disableButtons();
mdXYZ = new MeasureData(UPDATE_INTERVAL);
counter = 0;
tv.setText("");
tv.append("Calibrating");
Calibrator cal = new Calibrator(hRefresh, xyzAcc, START);
cal.calibrate();
}
void dumpSensor() {
++counter;
mdXYZ.addPoint(xyzAcc.getPoint());
hRefresh.sendEmptyMessage(TICK);
if (counter > MEASURE_TIMES) {
timer.cancel();
hRefresh.sendEmptyMessage(TIMER_DONE);
}
}
private void enableButtons() {
testBtn.setEnabled(true);
}
private void setAccelerometer() {
xyzAcc = new XYZAccelerometer();
mSensorManager.registerListener(xyzAcc,
mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_UI);
}
private void disableButtons() {
testBtn.setEnabled(false);
}
private void onMeasureDone() {
try {
mdXYZ.process();
long now = System.currentTimeMillis();
mdXYZ.saveExt(this, Long.toString(now) + ".csv");
} catch (Throwable ex) {
Toast.makeText(this, ex.getMessage().toString(), Toast.LENGTH_SHORT);
}
}
}
<serviceLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<serviceButton
android:id="#+id/btn"
android:text="TEST"
android:layout_width="300px"
android:layout_height="200px"
android:onClick="onButtonTest" />
<serviceTextView
android:id = "#+id/txt"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text=":"
/>
<service/LinearLayout>
Although at the developer.android.com site it is stated clearly that
you could use the linear accelerometer to see how fast your car is going"
But I did not find anything (in testing or in examples or code) that showed this is really true.
Now, unfortunately, I am convinced that it is not possible to calculate the speed of a car with the linear accelerometer.
Please see the below code to get the velocity using accelerometer
public class SensorTestActivity extends Activity implements SensorEventListener {
double calibration = Double.NaN;
private SensorManager sensorManager;
private boolean color = false;
private TextView view;
private long lastUpdate;
float appliedAcceleration = 0;
float currentAcceleration = 0;
float velocity = 0;
Date lastUpdatedate;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
view = findViewById(R.id.textView);
// view.setBackgroundColor(Color.GREEN);
lastUpdatedate = new Date(System.currentTimeMillis());
sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
lastUpdate = System.currentTimeMillis();
}
#Override
public void onSensorChanged(SensorEvent event) {
// if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
// getAccelerometer(event);
// }
double x = event.values[0];
double y = event.values[1];
double z = event.values[2];
double a = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2) + Math.pow(z, 2));
if (calibration == Double.NaN)
calibration = a;
else {
updateVelocity();
currentAcceleration = (float)a;
}
}
private void getAccelerometer(SensorEvent event) {
float[] values = event.values;
// Movement
float x = values[0];
float y = values[1];
float z = values[2];
float accelationSquareRoot = (x * x + y * y + z * z)
/ (SensorManager.GRAVITY_EARTH * SensorManager.GRAVITY_EARTH);
long actualTime = event.timestamp;
if (accelationSquareRoot >= 2) //
{
if (actualTime - lastUpdate < 200) {
return;
}
lastUpdate = actualTime;
// Toast.makeText(this, "Device was shuffed", Toast.LENGTH_SHORT)
// .show();
if (color) {
view.setBackgroundColor(Color.GREEN);
} else {
view.setBackgroundColor(Color.RED);
}
color = !color;
view.setText("SPEEDDDDD=== "+accelationSquareRoot);
// Log.i("SensorTestActivity","SPEEDDDDD=== "+accelationSquareRoot+" ");
}
}
private void updateVelocity() {
// Calculate how long this acceleration has been applied.
Date timeNow = new Date(System.currentTimeMillis());
long timeDelta = timeNow.getTime()-lastUpdatedate.getTime();
lastUpdatedate.setTime(timeNow.getTime());
// Calculate the change in velocity at the
// current acceleration since the last update.
float deltaVelocity = appliedAcceleration * (timeDelta/1000);
appliedAcceleration = currentAcceleration;
// Add the velocity change to the current velocity.
velocity += deltaVelocity;
final double mph = (Math.round(100*velocity / 1.6 * 3.6))/100;
Log.i("SensorTestActivity","SPEEDDDDD=== "+mph+" "+velocity);
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
#Override
protected void onResume() {
super.onResume();
// register this class as a listener for the orientation and
// accelerometer sensors
sensorManager.registerListener(this,
sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_NORMAL);
}
#Override
protected void onPause() {
// unregister listener
super.onPause();
sensorManager.unregisterListener(this);
}
}
I am working on a project in which I am showing two random location and the path between them.I have used this tutorial to accomplish.
Now i want to show the moving image from one location to another.I have already put markers on that two locations.and also I have saved the position in an arraylist.
I had found some similar posts but couldn't solve my issue.
Here is my code for moving the drawable:
mMap.setOnMarkerClickListener(new GoogleMap.OnMarkerClickListener() {
final Handler handler = new Handler();
int i = 0;
#Override
public boolean onMarkerClick(Marker marker) {
// System.out.println("Marker size:- " + MarkerPoints.size());
handler.post(new Runnable() {
#Override
public void run() {
BitmapDescriptor icon = BitmapDescriptorFactory.fromResource(R.drawable.truck_16);
while (i < MarkerPoints.size()) {
MarkerOptions markerOptions = new MarkerOptions().position(MarkerPoints.get(i))
.title("Current Location")
icon(icon);
System.out.println(MarkerPoints.get(i));
mMap.addMarker(markerOptions);
i++;
handler.postDelayed(this, 3000);
}
}
});
return true;
}
});
private double bearingBetweenLocations(LatLng latLng1, LatLng latLng2) {
final double PI = 3.14159;
final double lat1 = latLng1.latitude * PI / 180;
final double long1 = latLng1.longitude * PI / 180;
final double lat2 = latLng2.latitude * PI / 180;
final double long2 = latLng2.longitude * PI / 180;
final double dLon = (long2 - long1);
final double y = Math.sin(dLon) * Math.cos(lat2);
final double x = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1)
* Math.cos(lat2) * Math.cos(dLon);
double brng = Math.atan2(y, x);
brng = Math.toDegrees(brng);
brng = (brng + 360) % 360;
return brng;
}
Suppose you have current and destination co-ordinates like below.
private LatLng CURRENT_LOC = new LatLng(23.013171, 72.522300);
private LatLng DESTINATION_LOC = new LatLng(23.013481, 72.522496);
After that add marker on google map
if (googleMap != null)
{
BitmapDescriptor icon = BitmapDescriptorFactory.fromResource(R.drawable.truck_16);
MarkerOptions current = new MarkerOptions().position(CURRENT_LOC).title("Current Point");
current_marker = googleMap.addMarker(current);
current_marker.setIcon(icon);
current_marker.setFlat(true);
MarkerOptions destination = new MarkerOptions().position(DESTINATION_LOC).title("Destination Point");
destination_marker = googleMap.addMarker(destination);
destination_marker.setFlat(true);
}
And move marker on click
#Override
public void onClick(View v)
{
switch (v.getId())
{
case R.id.btn_move:
float rotate = (float) bearingBetweenLocations(CURRENT_LOC, DESTINATION_LOC);
rotateMarker(rotate);
break;
}
}
below all are methods that move marker from current location to destnation
private double bearingBetweenLocations(LatLng latLng1,LatLng latLng2)
{
double PI = 3.14159;
double lat1 = latLng1.latitude * PI / 180;
double long1 = latLng1.longitude * PI / 180;
double lat2 = latLng2.latitude * PI / 180;
double long2 = latLng2.longitude * PI / 180;
double dLon = (long2 - long1);
double y = Math.sin(dLon) * Math.cos(lat2);
double x = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1)
* Math.cos(lat2) * Math.cos(dLon);
double brng = Math.atan2(y, x);
brng = Math.toDegrees(brng);
brng = (brng + 360) % 360;
return brng;
}
public void rotateMarker(float rotate)
{
if (current_marker != null)
{
//final LatLngInterpolator latLngInterpolator = new LatLngInterpolator.LinearFixed();
ValueAnimator valueAnimator = new ValueAnimator();
//final LatLng startPosition = current_marker.getPosition();
final float startRotation = current_marker.getRotation();
final float angle = 180 - Math.abs(Math.abs(startRotation - rotate) - 180);
final float right = WhichWayToTurn(startRotation, rotate);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
{
#Override
public void onAnimationUpdate(ValueAnimator animation)
{
try
{
if (current_marker == null) // oops... destroying map during animation...
{
return;
}
float v = animation.getAnimatedFraction();
//newPosition = latLngInterpolator.interpolate(v, startPosition, toLatLng(location));
float rotation = startRotation + right * v * angle;
current_marker.setRotation(rotation);
//current_marker.setPosition(newPosition);
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
});
valueAnimator.addListener(new AnimatorListenerAdapter()
{
#Override
public void onAnimationEnd(Animator animation)
{
//current_marker.setPosition(newPosition);
animateMarker(current_marker, DESTINATION_LOC, false);
}
});
valueAnimator.setFloatValues(0, 1);
valueAnimator.setDuration(1000);
valueAnimator.start();
}
}
public void animateMarker(final Marker marker, final LatLng toPosition, final boolean hideMarker)
{
final Handler handler = new Handler();
final long start = SystemClock.uptimeMillis();
Projection proj = googleMap.getProjection();
Point startPoint = proj.toScreenLocation(marker.getPosition());
final LatLng startLatLng = proj.fromScreenLocation(startPoint);
final long duration = 5000;
final Interpolator interpolator = new LinearInterpolator();
handler.post(new Runnable() {
#Override
public void run() {
long elapsed = SystemClock.uptimeMillis() - start;
float t = interpolator.getInterpolation((float) elapsed / duration);
double lng = t * toPosition.longitude + (1 - t) * startLatLng.longitude;
double lat = t * toPosition.latitude + (1 - t) * startLatLng.latitude;
marker.setPosition(new LatLng(lat, lng));
if (t < 1.0) {
// Post again 16ms later.
handler.postDelayed(this, 16);
} else {
if (hideMarker) {
marker.setVisible(false);
} else {
marker.setVisible(true);
}
}
}
});
}
private float WhichWayToTurn(float currentDirection, float targetDirection)
{
float diff = targetDirection - currentDirection;
if (Math.abs(diff) == 0)
{
return 0;
}
if(diff > 180)
{
return -1;
}
else
{
return 1;
}
}
Hope this would help you.
Finally I found a way to accomplish this.May be this is not the best way but it solves the problem.I am posting this so in future if someone needs to do stuff like that,It can be helpful.
I have store all the points in an ArrayList called MarkerPoints that we get from the API and use it to draw the image on ever point.
Here is the code:
public class MyActivity extends FragmentActivity implements Runnable
{
private Thread thread = null;
volatile boolean isRunning;
private ArrayList<LatLng> MarkerPoints; //This arrayList contains all points that are on the route
int i = 0;
Marker marker;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_on_trip_maps);
isRunning = true;
}
#Override
public void run() {
while (isRunning) {
runOnUiThread(new Runnable() {
#Override
public void run() {
update();
}
});
control();
}
}
public void update() {
if (marker != null) {
marker.remove();
}
BitmapDescriptor icon = BitmapDescriptorFactory.fromResource(R.drawable.truck_16);
marker = mMap.addMarker(new MarkerOptions().position(MarkerPoints.get(i))
.title("Current Location")
.icon(icon));
System.out.println(MarkerPoints.get(i));
i++;
if (i > MarkerPoints.size() - 1) {
isRunning = false;
}
}
public void control() {
try {
thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
This will give the moving effect.
I am using a plasio turbo x to test my osmdroid sample. I am also testing using a moto g. In moto g the map rotation which is according to the compass head up is working fine, but in plasio one the compass starts to spin and map also spins, they don't get stable. You can see the logcat here(it is very big, stackoverflow not letting me add it here).
Following is my class in which I have used compass:
public class MainActivity extends FragmentActivity implements LocationListener, IOrientationConsumer,MapEventsReceiver {
private CompassOverlay mCompassOverlay = null;
private MyLocationNewOverlay mLocationOverlay;
IOrientationProvider compass = null;
int deviceOrientation = 0;
MapView mMapView;
float gpsspeed;
float gpsbearing;
float lat = 0;
float lon = 0;
float alt = 0;
long timeOfFix = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = getIntent();
final double lat1 = Double.parseDouble(intent.getStringExtra("lat1"));
final double long1 = Double.parseDouble(intent.getStringExtra("long1"));
final double lat2 = 25.633;
final double long2 = 71.094;
//important! set your user agent to prevent getting banned from the osm servers
org.osmdroid.tileprovider.constants.OpenStreetMapTileProviderConstants.setUserAgentValue(BuildConfig.APPLICATION_ID);
mMapView = (MapView) findViewById(R.id.map);
mMapView.setTileSource(TileSourceFactory.MAPNIK);
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
mCompassOverlay = new CompassOverlay(this, new InternalCompassOrientationProvider(this),
mMapView);
mCompassOverlay.enableCompass();
mMapView.getOverlays().add(this.mCompassOverlay);
addOverlays();
GeoPoint startPoint = new GeoPoint(lat1, long1);
IMapController mapController = mMapView.getController();
mapController.setZoom(9);
mapController.setCenter(startPoint);
Marker startMarker = new Marker(mMapView);
startMarker.setPosition(startPoint);
startMarker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM);
mMapView.getOverlays().add(startMarker);
RoadManager roadManager = new OSRMRoadManager(this);
ArrayList<GeoPoint> waypoints = new ArrayList<GeoPoint>();
waypoints.add(startPoint);
GeoPoint endPoint = new GeoPoint(lat2, long2);
Marker endMarker = new Marker(mMapView);
endMarker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM);
mMapView.getOverlays().add(endMarker);
waypoints.add(endPoint);
Road road = roadManager.getRoad(waypoints);
Polyline roadOverlay = RoadManager.buildRoadOverlay(road);
mMapView.getOverlays().add(roadOverlay);
mMapView.invalidate();
}
public void addOverlays() {
mLocationOverlay = new MyLocationNewOverlay(mMapView);
mLocationOverlay.setEnableAutoStop(false);
mLocationOverlay.enableFollowLocation();
mLocationOverlay.enableMyLocation();
this.mMapView.getOverlayManager().add(mLocationOverlay);
mMapView.setBuiltInZoomControls(true);
mMapView.setMultiTouchControls(true);
mMapView.setTilesScaledToDpi(true);
}
#Override
protected void onResume() {
super.onResume();
//lock the device in current screen orientation
int orientation;
int rotation = ((WindowManager) this.getSystemService(
Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
switch (rotation) {
case Surface.ROTATION_0:
orientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
this.deviceOrientation = 0;
break;
case Surface.ROTATION_90:
this.deviceOrientation = 90;
orientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
break;
case Surface.ROTATION_180:
this.deviceOrientation = 180;
orientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
break;
default:
this.deviceOrientation = 270;
orientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
break;
}
this.setRequestedOrientation(orientation);
LocationManager lm = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
try {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, (LocationListener) this);
lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, (LocationListener) this);
} catch (Exception ex) {
}
compass = new InternalCompassOrientationProvider(this);
compass.startOrientationProvider(this);
mMapView.getController().zoomTo(14);
}
#Override
public void onLocationChanged(Location location) {
if (mMapView == null)
return;
//after the first fix, schedule the task to change the icon
//mMapView.getController().setCenter(new GeoPoint(location.getLatitude(), location.getLongitude()));
mMapView.invalidate();
gpsbearing = location.getBearing();
gpsspeed = location.getSpeed();
lat = (float) location.getLatitude();
lon = (float) location.getLongitude();
alt = (float) location.getAltitude(); //meters
timeOfFix = location.getTime();
}
#Override
public void onStatusChanged(String s, int i, Bundle bundle) {
}
#Override
public void onProviderEnabled(String s) {
}
#Override
public void onProviderDisabled(String s) {
}
#Override
protected void onPause() {
super.onPause();
compass.stopOrientationProvider();
LocationManager lm = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
try {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
lm.removeUpdates(this);
} catch (Exception ex) {
}
//unlock the orientation
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
}
Float trueNorth = 0f;
#Override
public void onOrientationChanged(final float orientationToMagneticNorth, IOrientationProvider source) {
GeomagneticField gf = new GeomagneticField(lat, lon, alt, timeOfFix);
trueNorth = orientationToMagneticNorth + gf.getDeclination();
gf=null;
synchronized (trueNorth) {
if (trueNorth > 360.0f) {
trueNorth = trueNorth - 360.0f;
}
//use gps bearing instead of the compass
if (gpsspeed > 0.01f) {
float t = (360 - gpsbearing - this.deviceOrientation);
if (t < 0) {
t += 360;
}
if (t > 360) {
t -= 360;
}
mMapView.setMapOrientation(t);
} else {
//this part adjusts the desired map rotation based on device orientation and compass heading
float t = (360 - trueNorth - this.deviceOrientation);
if (t < 0) {
t += 360;
}
if (t > 360) {
t -= 360;
}
mMapView.setMapOrientation(t);
}
this.runOnUiThread(new Runnable() {
#Override
public void run() {
if (this!=null ) {
Toast.makeText(MainActivity.this, "GPS Speed: " + gpsspeed + "m/s GPS Bearing: " + gpsbearing +
"\nDevice Orientation: " + (int) deviceOrientation + " Compass heading: " + (int) orientationToMagneticNorth + "\n" +
"True north: " + trueNorth.intValue() + " Map Orientation: " + (int) mMapView.getMapOrientation() + "\n", Toast.LENGTH_SHORT).show();
}
}
});
}
}
#Override
public boolean singleTapConfirmedHelper(GeoPoint geoPoint) {
return false;
}
#Override
public boolean longPressHelper(GeoPoint geoPoint) {
return false;
}
}
I need help with onSensorChanged(SensorEvent event). I can get a toast message when device is facedown (y axis) 0 to 180.but can not get it to work going the other way on the (y axis) -0 to -180 faceup. Any help is greatly appreciated.
Thanks for your interest,
Mike
Relevant code follows:
public class MainActivity extends Activity implements SensorEventListener {
private SensorManager mSensorManager;
private Sensor mRotationSensor;
private double[] values;
private String TAG;
private static final int SENSOR_DELAY = 500 * 1000; // 500ms
private static final int FROM_RADS_TO_DEGS = -57;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
mSensorManager = (SensorManager) getSystemService(Activity.SENSOR_SERVICE);
mRotationSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR);
mSensorManager.registerListener(this, mRotationSensor, SENSOR_DELAY);
} catch (Exception e) {
Toast.makeText(this, "Hardware compatibility issue", Toast.LENGTH_LONG).show();
}
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// TODO Auto-generated method stub
}
#Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor == mRotationSensor) {
if (event.values.length > 4) {
float[] truncatedRotationVector = new float[4];
System.arraycopy(event.values, 0, truncatedRotationVector, 0, 4);
update(truncatedRotationVector);
} else {
update(event.values);
}
}
}
private void update(float[] vectors) {
float[] rotationMatrix = new float[9];
SensorManager.getRotationMatrixFromVector(rotationMatrix, vectors);
int worldAxisX = SensorManager.AXIS_X;
int worldAxisZ = SensorManager.AXIS_Z;
float[] adjustedRotationMatrix = new float[9];
SensorManager.remapCoordinateSystem(rotationMatrix, worldAxisX, worldAxisZ, adjustedRotationMatrix);
float[] orientation = new float[3];
SensorManager.getOrientation(adjustedRotationMatrix, orientation);
float pitch = orientation[1] * FROM_RADS_TO_DEGS;
float roll = orientation[2] * FROM_RADS_TO_DEGS;
((TextView)findViewById(R.id.pitch)).setText("Pitch: "+pitch);
((TextView)findViewById(R.id.roll)).setText("Roll: "+roll);
if (pitch <= 81 && pitch >= 50) {
// mostly vertical
Toast.makeText(this, "Device Face Down ", Toast.LENGTH_SHORT).show();
}
{
if (pitch < -81&& pitch >= -50) {
Toast.makeText(this, "Device Face Up", Toast.LENGTH_SHORT).show();
}} }
I am working on a glassware where I have a image shown in my activity. I also managed it to zoom into the image by using slide gestures on the thouchpad. What I still need to do scrolling through this zoomed image.
So my question is is their any way to get some kind of gestureevent for turning your head
I have seen a google glass dart crosshair example at
https://www.youtube.com/watch?v=pGhamZnj6V0
but if I understand the way this works right it uses some kind of browser/webtechnology
but the way the browser gets this information could properly help me too.
Or should I switch from my imageview to a web-control in my activity and try to load my image embedded into this control? If yes how can I handle the zoom function their?
I don’t believe there is a gesture event that is triggered by the system when you move your head. However, you can implement your own using the Accelerometer API provided in Android. Something like this might work:
double lastX = 0;
double lastY = 0;
// Set up the accelerometer
SensorManager manager = (SensorManager) getSystemService(SENSOR_SERVICE);
manager.registerListener(this, sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL);
#Override
public void onSensorChanged(SensorEvent event) {
// Check for correct sensor
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
// Get current acceleration values
double currentX = event.values[0];
double currentY = event.values[1];
// Calculate delta values
double newX = x - lastX;
double newY = y - lastY;
// Set last values
lastX = newX;
lastY = newY;
// Move the view!
moveView(newX, newY);
}
}
public void moveView(double x, double y) {
view.setX(x);
view.setY(y);
}
You will need to modify this code to make it work in your setup, but it should give you an idea of how to start.
I used the following library.
The library only supports down/left/right as it is but I added some code to make it recognize the upwards gesture too.
Also because I had to edit the code myself and wasn't able to create a updated library out of the library I linked. I made a new package in my project and just pasted all the needed code there.
This is how my HeadGestureDetector looks after I added some code
import java.util.List;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.util.Log;
import HeadGestureDetector.*;
import HeadGestureDetector.Constants;
public class HeadGestureDetector implements SensorEventListener {
private static final int MATRIX_SIZE = 16;
private float[] inR = new float[MATRIX_SIZE];
private float[] outR = new float[MATRIX_SIZE];
private float[] I = new float[MATRIX_SIZE];
private float[] orientationValues = new float[3];
private float[] magneticValues = new float[3];
private float[] accelerometerValues = new float[3];
private float[] orientationVelocity = new float[3];
private SensorManager mSensorManager;
private OnHeadGestureListener mListener;
static enum State {
IDLE, SHAKE_TO_RIGHT, SHAKE_BACK_TO_LEFT, SHAKE_TO_LEFT, SHAKE_BACK_TO_RIGHT, GO_DOWN, BACK_UP, GO_UP, BACK_DOWN
}
private State mState = State.IDLE;
private long mLastStateChanged = -1;
private static final long STATE_TIMEOUT_NSEC = 1000 * 1000 * 1000;
public HeadGestureDetector(Context context) {
mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
}
private static final int[] REQUIRED_SENSORS = { Sensor.TYPE_MAGNETIC_FIELD, Sensor.TYPE_ACCELEROMETER,
Sensor.TYPE_GYROSCOPE };
private static final int[] SENSOR_RATES = { SensorManager.SENSOR_DELAY_NORMAL, SensorManager.SENSOR_DELAY_NORMAL,
SensorManager.SENSOR_DELAY_NORMAL };
public void start() {
for (int i = 0; i < REQUIRED_SENSORS.length; i++) {
int sensor_type = REQUIRED_SENSORS[i];
Sensor sensor = null;
List<Sensor> sensors = mSensorManager.getSensorList(sensor_type);
if (sensors.size() > 1) {
// Google Glass has two gyroscopes: "MPL Gyroscope" and "Corrected Gyroscope Sensor". Try the later one.
sensor = sensors.get(1);
} else {
sensor = sensors.get(0);
}
Log.d(Constants.TAG, "registered:" + sensor.getName());
mSensorManager.registerListener(this, sensor, SENSOR_RATES[i]);
}
}
public void stop() {
mSensorManager.unregisterListener(this);
}
public void setOnHeadGestureListener(OnHeadGestureListener listener) {
this.mListener = listener;
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// TODO Auto-generated method stub
}
#Override
public void onSensorChanged(SensorEvent event) {
if (event.accuracy == SensorManager.SENSOR_STATUS_UNRELIABLE) {
// Log.w(Constants.TAG, "Unreliable event...");
}
int sensorType = event.sensor.getType();
if (sensorType == Sensor.TYPE_MAGNETIC_FIELD) {
magneticValues = event.values.clone();
return;
}
if (sensorType == Sensor.TYPE_ACCELEROMETER) {
accelerometerValues = event.values.clone();
SensorManager.getRotationMatrix(inR, I, accelerometerValues, magneticValues);
SensorManager.remapCoordinateSystem(inR, SensorManager.AXIS_X, SensorManager.AXIS_Z, outR);
SensorManager.getOrientation(outR, orientationValues);
return;
}
if (sensorType == Sensor.TYPE_GYROSCOPE) {
if (event.accuracy == SensorManager.SENSOR_STATUS_UNRELIABLE) {
// Log.w(Constants.TAG, "Unreliable gyroscope event...");
// return;
}
orientationVelocity = event.values.clone();
// state timeout check
if (event.timestamp - mLastStateChanged > STATE_TIMEOUT_NSEC && mState != State.IDLE) {
Log.d(Constants.TAG, "state timeouted");
mLastStateChanged = event.timestamp;
mState = State.IDLE;
}
// Log.d(Constants.TAG, Arrays.toString(orientationValues));
// Log.d(Constants.TAG, "V:" + Arrays.toString(orientationVelocity));
// check if glass is put on
if (!isPutOn(orientationValues, orientationVelocity)) {
Log.d(Constants.TAG, "Looks like glass is off?");
}
int maxVelocityIndex = maxAbsIndex(orientationVelocity);
if (!isStable(orientationValues, orientationVelocity)) {
// Log.d(Constants.TAG, "V:" + Arrays.toString(orientationVelocity));
}
if (isStable(orientationValues, orientationVelocity)) {
// Log.d(Constants.TAG, "isStable");
} else if (maxVelocityIndex == 0) {
if (orientationVelocity[0] < -MIN_MOVE_ANGULAR_VELOCITY) {
if (mState == State.IDLE) {
// Log.d(Constants.TAG, "isNod");
mState = State.GO_DOWN;
mLastStateChanged = event.timestamp;
if (mListener != null) {
mListener.onNod();
}
}
}
}
if (orientationVelocity[0] > MIN_MOVE_ANGULAR_VELOCITY) {
if (mState == State.IDLE) {
mState = State.GO_UP;
mLastStateChanged = event.timestamp;
if (mListener != null) {
mListener.onHey();
}
}
}
else if (maxVelocityIndex == 1) {
if (orientationVelocity[1] < -MIN_MOVE_ANGULAR_VELOCITY) {
if (mState == State.IDLE) {
// Log.d(Constants.TAG, Arrays.toString(orientationValues));
// Log.d(Constants.TAG, "V:" + Arrays.toString(orientationVelocity));
mState = State.SHAKE_TO_RIGHT;
mLastStateChanged = event.timestamp;
if (mListener != null) {
mListener.onShakeToRight();
}
}
} else if (orientationVelocity[1] > MIN_MOVE_ANGULAR_VELOCITY) {
if (mState == State.IDLE) {
// Log.d(Constants.TAG, Arrays.toString(orientationValues));
// Log.d(Constants.TAG, "V:" + Arrays.toString(orientationVelocity));
mState = State.SHAKE_TO_LEFT;
mLastStateChanged = event.timestamp;
if (mListener != null) {
mListener.onShakeToLeft();
}
}
}
}
}
}
private static final float MIN_MOVE_ANGULAR_VELOCITY = 1.00F;
private static final float MAX_STABLE_RADIAN = 0.10F;
private static final float MAX_PUT_ON_PITCH_RADIAN = 0.45F;
private static final float MAX_PUT_ON_ROLL_RADIAN = 0.75F;
private static final float STABLE_ANGULAR_VELOCITY = 0.10F;
private static boolean isStable(float[] orientationValues, float[] orientationVelocity) {
if (Math.abs(orientationValues[1]) < MAX_STABLE_RADIAN
&& Math.abs(orientationVelocity[0]) < STABLE_ANGULAR_VELOCITY
&& Math.abs(orientationVelocity[1]) < STABLE_ANGULAR_VELOCITY
&& Math.abs(orientationVelocity[2]) < STABLE_ANGULAR_VELOCITY) {
return true;
}
return false;
}
private static boolean isPutOn(float[] orientationValues, float[] orientationVelocity) {
if (orientationValues[1] < MAX_PUT_ON_PITCH_RADIAN && Math.abs(orientationValues[2]) < MAX_PUT_ON_ROLL_RADIAN) {
return true;
}
return false;
}
private static int maxAbsIndex(float[] array) {
int n = array.length;
float maxValue = Float.MIN_VALUE;
int maxIndex = -1;
for (int i = 0; i < n; i++) {
float val = Math.abs(array[i]);
if (val > maxValue) {
maxValue = val;
maxIndex = i;
}
}
return maxIndex;
}
}
My OnHeadGestureListener class
public interface OnHeadGestureListener {
void onHey();
void onNod();
void onShakeToLeft();
void onShakeToRight();
}
and my Constants class
public class Constants {
public static final String TAG = "HeadGestureDetector";
}
Create those 3 classes in your projects and you should be able to use the head gestures
for it to work you need to add implements OnHeadGestureListener to your class
declare private GestureDetector mGestureDetector
in your onCreate()
mHeadGestureDetector = new HeadGestureDetector(this);
mHeadGestureDetector.setOnHeadGestureListener(this);
lastly in your onResume
mHeadGestureDetector.start();
and in your onPause
mHeadGestureDetector.stop();
I wrote a piece of code for this detector to trigger touchpad gestures. So when you look up glass thinks you swiped down on the touchpad. This code can be found here.