// -*- mode: java; c-basic-offset: 2; -*- // Copyright 2009-2011 Google, All Rights reserved // Copyright 2011-2012 MIT, All rights reserved // Released under the Apache License, Version 2.0 // http://www.apache.org/licenses/LICENSE-2.0 package com.google.appinventor.components.runtime; import com.google.appinventor.components.annotations.DesignerComponent; import com.google.appinventor.components.annotations.DesignerProperty; import com.google.appinventor.components.annotations.PropertyCategory; import com.google.appinventor.components.annotations.SimpleEvent; import com.google.appinventor.components.annotations.SimpleObject; import com.google.appinventor.components.annotations.SimpleProperty; import com.google.appinventor.components.common.ComponentCategory; import com.google.appinventor.components.common.PropertyTypeConstants; import com.google.appinventor.components.common.YaVersion; import android.content.Context; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; /** * Component providing data from the device's gyroscope sensor. */ @DesignerComponent(version = YaVersion.GYROSCOPESENSOR_COMPONENT_VERSION, description = "<p>Non-visible component that can measure angular velocity in three " + "dimensions in units of degrees per second.</p>" + "<p>In order to function, the component must have its <code>Enabled</code> property set to " + "True, and the device must have a gyroscope sensor.</p>", category = ComponentCategory.SENSORS, nonVisible = true, iconName = "images/gyroscopesensor.png") @SimpleObject public class GyroscopeSensor extends AndroidNonvisibleComponent implements SensorEventListener, Deleteable, OnPauseListener, OnResumeListener { // Properties private boolean enabled; private float xAngularVelocity; // degrees per second private float yAngularVelocity; // degrees per second private float zAngularVelocity; // degrees per second // Sensor information private final SensorManager sensorManager; private final Sensor gyroSensor; private boolean listening; /** * Creates a new GyroscopeSensor component. */ public GyroscopeSensor(ComponentContainer container) { super(container.$form()); // Get sensors, and start listening. sensorManager = (SensorManager) form.getSystemService(Context.SENSOR_SERVICE); gyroSensor = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE); // Begin listening in onResume() and stop listening in onPause(). form.registerForOnResume(this); form.registerForOnPause(this); // Set default property values. Enabled(true); } private void startListening() { if (!listening) { sensorManager.registerListener(this, gyroSensor, SensorManager.SENSOR_DELAY_FASTEST); listening = true; } } private void stopListening() { if (listening) { sensorManager.unregisterListener(this); listening = false; // Throw out sensor information that will go stale. xAngularVelocity = 0; yAngularVelocity = 0; zAngularVelocity = 0; } } // Events /** * GyroscopeChanged event handler. */ @SimpleEvent(description = "Indicates that the gyroscope sensor data has changed. The " + "timestamp parameter is the time in nanoseconds at which the event occurred.") public void GyroscopeChanged( float xAngularVelocity, float yAngularVelocity, float zAngularVelocity, long timestamp) { EventDispatcher.dispatchEvent(this, "GyroscopeChanged", xAngularVelocity, yAngularVelocity, zAngularVelocity, timestamp); } // Properties /** * Available property getter method (read-only property). * * @return {@code true} indicates that a gyroscope sensor is available, * {@code false} that it isn't */ @SimpleProperty(description = "Indicates whether a gyroscope sensor is available.", category = PropertyCategory.BEHAVIOR) public boolean Available() { return sensorManager.getSensorList(Sensor.TYPE_GYROSCOPE).size() > 0; } /** * Enabled property getter method. * * @return {@code true} indicates that the sensor generates events, * {@code false} that it doesn't */ @SimpleProperty(category = PropertyCategory.BEHAVIOR) public boolean Enabled() { return enabled; } /** * Enabled property setter method. * * @param enabled {@code true} enables sensor event generation, * {@code false} disables it */ @DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_BOOLEAN, defaultValue = "True") @SimpleProperty(description = "If enabled, then sensor events will be generated and " + "XAngularVelocity, YAngularVelocity, and ZAngularVelocity properties will have " + "meaningful values.") public void Enabled(boolean enabled) { if (this.enabled != enabled) { this.enabled = enabled; if (enabled) { startListening(); } else { stopListening(); } } } /** * XAngularVelocity property getter method (read-only property). * * <p>To return meaningful values the sensor must be enabled.</p> * * @return current angular velocity around x axis */ @SimpleProperty(description = "The angular velocity around the X axis, in degrees per second.", category = PropertyCategory.BEHAVIOR) public float XAngularVelocity() { return xAngularVelocity; } /** * YAngularVelocity property getter method (read-only property). * * <p>To return meaningful values the sensor must be enabled.</p> * * @return current angular velocity around y axis */ @SimpleProperty(description = "The angular velocity around the Y axis, in degrees per second.", category = PropertyCategory.BEHAVIOR) public float YAngularVelocity() { return yAngularVelocity; } /** * ZAngularVelocity property getter method (read-only property). * * <p>To return meaningful values the sensor must be enabled.</p> * * @return current angular velocity around z axis */ @SimpleProperty(description = "The angular velocity around the Z axis, in degrees per second.", category = PropertyCategory.BEHAVIOR) public float ZAngularVelocity() { return zAngularVelocity; } // SensorListener implementation /** * Responds to changes in the gyroscope sensors. * * @param sensorEvent an event from the gyroscope sensor */ @Override public void onSensorChanged(SensorEvent sensorEvent) { if (enabled) { xAngularVelocity = (float) Math.toDegrees(sensorEvent.values[0]); yAngularVelocity = (float) Math.toDegrees(sensorEvent.values[1]); zAngularVelocity = (float) Math.toDegrees(sensorEvent.values[2]); // Raise event. GyroscopeChanged(xAngularVelocity, yAngularVelocity, zAngularVelocity, sensorEvent.timestamp); } } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { } // Deleteable implementation @Override public void onDelete() { stopListening(); } // OnPauseListener implementation public void onPause() { stopListening(); } // OnResumeListener implementation public void onResume() { if (enabled) { startListening(); } } }