Google Cardboard Android

Google Cardboard is a device which experience virtual reality in a simple, fun, and inexpensive way. Cardboard main aim to provide virtual reality (VR) tools to allow everyone to enjoy VR in a simple, fun, and natural way.
Cardboard SDK tool enable android and unity application to quickly start creating virtual reality (VR) apps or adapt your existing application for virtual reality (VR).
The cardboard SDK tools provide a simple platform for android and unity so you can focus on building your new immersive experience
Cardboard SDK for Android :- Build apps that display 3D scenes with binocular rendering, track and react to head movements, and interact with apps through magnet input.
Cardboard SDK for Unity :- Easily adapt an existing Unity 3D app for virtual reality or build your own VR experience from scratch.
How It Works with Cardboard SDK for Android :-
The Cardboard SDK toolkit enable android developer familiar with OpenGL to quickly start creating VR applications. SDK toolkit provide many task includes : Lens distortion correction, Head tracking, 3D calibration, Side-by-side rendering, Stereo geometry configuration, User input event handling xperience.
The Cardboard SDK requires manifest tags :- Firstly we give permission to cardboard
<uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="android.permission.VIBRATE" />
android.permission.NFC permission is required by the Cardboard SDK to access Cardboard's NFC tag.
android.permission.VIBRATE permission is required by our demo app to make the phone vibrate to inform the user that something has happened.
We give a permission according to our requirement.
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />  
android.permission.READ_EXTERNAL_STORAGE   and android.permission.WRITE_EXTERNAL_STORAGE. These permissions are required by the Cardboard SDK to pair the user's phone to their VR viewer.
The minimum requirement to start cardboard application min SDK Version 16 ( this line indicates that the device must be running API Level 16 (Jellybean) or higher) and target API target SDK Version 19.
<uses-sdk android:minSdkVersion="16"
        android:targetSdkVersion="19" />
The activity's required screen orientation is "landscape." This is the orientation you must set for VR apps. The view used by the Cardboard SDK, CardBoard, only renders on fullscreen and landscape (landscape, reverseLandscape, sensorLandscape) modes.
android:screenOrientation="landscape"
The setting android:configChanges="orientation|keyboardHidden" is also recommended, but not mandatory.For example
<uses-feature android:glEsVersion="0x00030000"
        android:required="true" />
The intent-filter and specifically com.google.intent.category.CARDBOARD state that this activity is compatible with Cardboard-like viewers. This category is used by the Cardboard App to list compatible apps installed on the user's phone.
Extend CardboardActivity - First we extend the main class through CardboardActivity. The starting point for coding a cardboard application is CardboardActivity. CardboardActivity is the base activity that provides easy integration with Cardboard devices. It exposes events to interact with Cardboards and handles many of the details commonly required when creating an activity for VR rendering. CardboardActivity uses sticky immersive mode, in which the system UI is hidden, and the content takes up the whole screen. This is a requirement for a VR app, since CardboardView will only render when the activity is in fullscreen mode.
Implement CardboardView.StereoRenderer - Then we implement the CardboardView.StereoRenderer. CardboardView.StereoRenderer Interface for renderers that delegate all stereoscopic rendering details to the view. Implementors should simply render a view as they would normally do using the provided transformation parameters. All stereoscopic rendering and distortion correction details are abstracted from the renderer and managed internally by the view.
public extends CardboardActivity implementsCardboardView.StereoRenderer {

}
Define a CardboardView with Xml File -  All user interface elements in an Android app are built using views. The Cardboard SDK for Android provides its own view,CardboardView , which is a convenience extension of GLSurfaceView that can be used for VR rendering. CardboardView renders content in stereo. You can defines a CardboardView to in its activity layout xml file in the following way:
<com.google.vrtoolkit.cardboard.CardboardView
    android:id="@+id/cardboard_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_centerInParent="true"/>
Then in the main activity class it initializes the CardboardView in the onCreate() method:
public class Main extends CardboardActivity implements CardboardView.StereoRenderer {
    @Override
       void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        CardboardView cardboardView =    (CardboardView)findViewById(R.id.cardboard_view);
        cardboardView.setRenderer(this);
        setCardboardView(cardboardView);
  }

Render the view - Once you get the CardboardView you associate it with a renderer, and then you associate the CardboardView with the activity. CardboardView.StereoRenderer includes these key methods
onNewFrame() - called every time that app renders.
onDrawEye() - called for each eye with different eye parameters.
Implementing these is similar to what you would normally do for an OpenGL application.
Implement onNewFrame - Use the onNewFrame() method to to encode rendering logic before the individual eyes are rendered. Any per-frame operations not specific to a single view should happen here. This is a good place to update your model. In this snippet, the variable mHeadView contains the position of the head.
/**
* Prepares OpenGL ES before we draw a frame.
*@param headTransform The head transformation in the new frame.
 */
        public void onNewFrame(HeadTransform headTransform) {
    ...
        headTransform.getHeadView(mHeadView, 0);
    ...
 }

Implement onDrawEye - Implement onDrawEye() to perform per-eye configuration. This is the meat of the rendering code, and very similar to building a regular OpenGL ES2 application. The following snippet shows how to get the view transformation matrix, and also the perspective transformation matrix. You need to make sure that you render with low latency. The Eye object contains the transformation and projection matrices for the eye. This is the sequence of events.
/**
 * Draws a frame for an eye.
 *
 * @param eye The eye to render. Includes all required transformations.
 */
@Override
public void onDrawEye(Eye eye) {
.......
}

Handling inputs -  The Cardboard viewer includes a push button which uses a magnet. When you push the magnet, the magnetic field changes and is detected by the magnetometer of your phone. These magnet events are detected by the Cardboard SDK for you. To provide custom behavior when the user pulls the magnet, override CardboardActivity.onCardboardTrigger() in your app's activity.
/**
 * Increment the score, hide the object, and give feedback if the user pulls the magnet while
 * looking at the anythings
*/
@Override
public void onCardboardTrigger() {
...............
}

Google Cardboard Sensor



A- MagnetSensor.OnCardboardTriggerListener -
public static interface MagnetSensor.OnCardboardTriggerListener- Known Indirect Subclasses CardboardActivity Interface for listeners of Cardboard trigger events.
Public Methods-
public abstract void onCardboardTrigger ()
SensorEventProvider public interface
B- SensorEventProvider - Known Indirect Subclasses DeviceSensorLooper Public interface to provide sensor events (e.g. from a device or from recorded data) to a set of listeners.
Public Methods-
public abstract void registerListener (SensorEventListener listener)- Registers a listener to the SensorEvent broadcasted for the given sensor.
Parameters-
listener- A SensorEventListener object that will listen to sensor updates. See Also unregisterListener(SensorEventListener)
public abstract void start ()- Start the sensor provider.
public abstract void stop ()- Stop the sensor provider.
public abstract void unregisterListener (SensorEventListener listener)- Unregisters a listener to the SensorEvent broadcasted for the given sensor.
Parameters-
listener SensorEventListener object to be unregistered. See Also registerListener(SensorEventListener)
C- DeviceSensorLooper public class DeviceSensorLooper - This class registers two sensor listeners for accelerometer and gyroscope to the device SensorManager and broadcast all received SensorEvent to registered listeners. This class spuns its on thread when start() is called.
Inherited Methods-
From class java.lang.Object
From interface com.google.vrtoolkit.cardboard.sensors.SensorEventProvider
Public Constructors-
public DeviceSensorLooper (SensorManager sensorManager)- Default constructor.
Parameter-
sensorManager -Android sensor manager that will be used to register and unregister the listeners.
Public Methods-
public void registerListener (SensorEventListener listener)- Registers a listener to the SensorEvent broadcasted for the given sensor.
Parameters-
listener- A SensorEventListener object that will listen to sensor updates.
public void start ()- This registers two SensorEventListener and start a Looper.
public void stop ()- Stops the looper and deregister the listener from the sensor manager.
public void unregisterListener (SensorEventListener listener)- Unregisters a listener to the SensorEvent broadcasted for the given sensor.
Parameters- 
listener- SensorEventListener object to be unregistered.
D- HeadTracker-  This is a public class. HeadTracker Provides head tracking information from the device IMU.
Inherited Methods- 
From class java.lang.Object
Public Constructors-
public HeadTracker (SensorEventProvider sensorEventProvider, Clock clock, Display display)-Default constructor.
Parameters-
sensorEventProvider- provides SensorEvents to the head tracker.
clock- globaly consistent clock that should be shared by all system that needs a synchronous time.
display- device display to get access to the static rotation of the screen.
Public Methods-
public static HeadTracker createFromContext (Context context) -Factory constructor that creates a SensorEventProvider from the device SensorManager. It uses the system clock as global clock.
Parameters-
context- global context
public void getLastHeadView (float[] headView, int offset)- Provides the most up-to-date transformation matrix.
Parameters- 
headView- An array representing a 4x4 transformation matrix in column major order.
offset- Offset in the array where data should be written. Throws IllegalArgumentException If there is not enough space to write the result.
public void startTracking ()- Starts reading sensor data for head tracking.
public void stopTracking ()- Stops reading sensor data for head tracking.
E- MagnetSensor -This is public class. MagnetSensor Magnetometer sensor detector for the cardboard trigger. Provides cardboard trigger events from the device magnetometer to listeners.
Nested Classes -
interface- MagnetSensor.OnCardboardTriggerListener- Interface for listeners of Cardboard trigger events.
Inherited Methods-
From class java.lang.Object
Public Constructors-
public MagnetSensor (Context context)- Creates a magnet sensor using the provided context.
Parameters-
context- Context to use.
Public Methods-
public void setOnCardboardTriggerListener(MagnetSensor.OnCardboardTriggerListener listener)- Sets a listener for Cardboard trigger events. Any events are posted to the listener in the same thread this method was called from.
Parameters-
listener-Listener for to set.
public void start ()- Starts reading sensor data and providing for trigger events.
public void stop ()- Stops reading sensor data and providing for trigger events.
F- SystemClock- This is a  public class .SystemClock Implementation of the public interface Clock using the system clock.
Inherited Methods-
From class java.lang.Object
From interface com.google.vrtoolkit.cardboard.sensors.Clock
Public Constructors- 
public SystemClock ()
Public Methods 
public long nanoTime ()- Return System time in NanoSeconds.

Google Cardboard Classes

A- CardboardActivity - CardboardActivity is public class and Base activity that provides easy integration with Cardboard devices. Exposes events to interact with Cardboards and handles many of the details commonly required when creating an Activity for VR rendering.
Some public methods-
public boolean areVolumeKeysDisabled () - Tells if the volume keys are currently being disabled by CardboardActivity Note that volume keys can be disabled by other child activities even if this method reports they are not disabled and returns true if the volume keys are currently being disabled by CardboardActivity. Throws IllegalStateException (If the current volume keys mode is invalid).
public CardboardView getCardboardView () - Returns the Cardboard view associated with this activity. Returns the CardboardView object associated with this activity. Can be null.
public int getVolumeKeysMode ()- Provides the current mode for managing the volume keys. and returns a CardboardActivity.VolumeKeys constant defining the current mode for managing the volume keys.
public void onCardboardTrigger ()- Override to detect when the Cardboard trigger was pulled and released. Provides click-like events when the device is inside a Cardboard.
public void setCardboardView (CardboardView cardboardView) - Associates a Cardboard view with this activity. This method does not set or change the content view, but associates the activity with a CardboardView and ensures it receives any required activity lifecycle notifications. This is automatically done if setContentView is used to directly set a CardboardView object. Should be called if the CardboardView is set in any other way (e.g. from a layout resource).
Parameters-
cardboardView- The Cardboard view to associate with. Can be null.
public void setVolumeKeysMode (int mode) - Sets the way in which volume keys should be managed. Volume keys can be accidentally pressed while the device is inserted into a Cardboard. To avoid or reduce this, different modes are provided to disable them.
Parameters-
Mode - One of the VolumeKeys constants defining how the volume keys should be managed.
protected void updateCardboardDeviceParams (CardboardDeviceParams newParams)- Requests an update of the parameters for the current Cardboard device. Compares against existing configuration and updates if the new parameters differ. This method requires a CardboardView to be already set. See setCardboardView.
Parameters-
newParams- New Cardboard device params to set.
B-CardboardActivity.VolumeKeys - Defines the constants with options for managing the volume keys. For use with setVolumeKeysMode.
public static final int DISABLED- Volume keys should be disabled and Constant Value: 1
public static final int NOT_DISABLED- Volume keys should not be disabled and Constant Value: 0
C-CardboardDeviceParams- This is public class. CardboardDeviceParams Defines the physical parameters of a Cardboard-compatible device. The model assumes the following for any Cardboard device:
1. Lenses are parallel to the screen of the inserted device.
2. The center of each lens is at the same height from the bottom of the inserted device.
3. Lenses are symmetrically placed with respect to the center of the inserted device screen.
4. The size of the area visible from the center of each lens is the same. These parameters might be different for variations of different devices or lenses. For simplicity, they can be stored in the NFC tag of the Cardboard.
Public Constructors -
public CardboardDeviceParams () - Initializes Cardboard device parameters to default Cardboard v1.0.0 values. Consider using HeadMountedDisplayManager to access Cardboard devices parameters more optimized for your headset.
public CardboardDeviceParams (CardboardDeviceParams params)- Creates a copy of an existing device params object.
Parameters-
Params - Device parameters to copy.
Public Methods-
public static CardboardDeviceParams createFromInputStream (InputStream inputStream)- Initializes the physical parameters of a Cardboard device from an InputStream. Caller is responsible for closing stream and returns a new Cardboard device parameters object or null in case of error. Parameters-
inputStream - input stream containing device params.
public static CardboardDeviceParams createFromNfcContents (NdefMessage tagContents)- Initializes physical parameters from the contents of a Cardboard NFC tag and returns a new Cardboard device parameters object or null in case of error.
Parameters-
tagContents- Contents of the Cardboard NFC tag.
public static CardboardDeviceParams createFromUri (Uri uri)- Initializes the physical parameters of a Cardboard device from a Uri and returns new Cardboard device parameters object or null in case of error.
Parameters-
Uri - Uri to read the parameters from.
public boolean equals (Object other)- Compares this instance with the specified object and indicates if they are equal and returns true if the objects are equal, false otherwise.
Parameters-
Other - The object to compare this instance with.
public Distortion getDistortion ()- Returns the lens distortion model and returns the lens distortion model.
public boolean getHasMagnet ()- Returns whether or not the cardboard device has a magnet and returns True if a magnet exists, false otherwise.
public float getInterLensDistance () - Returns the inter lens distance for the device and returns the inter lens distance in meters.
public FieldOfView getLeftEyeMaxFov ()- Returns the left eye's maximum field of view visible through the lens. The actual rendered field of view will be limited by this and also by the size of the screen. When rendering, a mirrored field of view is expected to be applied to the right eye and returns the left eye's maximum field of view.
public String getModel ()- Returns the device model string and returns a string identifying the device model.
public float getScreenToLensDistance () - Returns the screen to lens distance in meters and returns the screen to lens distance in meters.
public String getVendor ()- Returns the device vendor string and returns a string identifying the device vendor and returns a string identifying the device vendor.
public float getVerticalDistanceToLensCenter ()- Returns the vertical distance to the lens center and returns t he vertical distance to the lens center from the bottom of the inserted device, measured in meters.
public static boolean isCardboardUri (Uri uri)- Return true if given URI identifies a Cardboard device.
public void setHasMagnet (boolean magnet)- Sets whether this cardboard device has a magnet. public void setInterLensDistance (float interLensDistance)- Sets the inter lens distance of the device.
Parameters-
interLensDistance - The distance between the center of each lens in meters.
public void setModel (String model)- Sets the device model string.
Parameters-
Model- The device model string to set.
public void setScreenToLensDistance (float screenToLensDistance)- Sets the distance from the screen to the optical center of the lens. This value impacts the the scale applied when rendering. Parameters-
screenToLensDistance- The screen to lens distance in meters.
public void setVendor (String vendor)- Sets the device vendor string.
Parameters-
Vendor-The vendor string to set.
public void setVerticalDistanceToLensCenter (float verticalDistanceToLensCenter)- Sets the vertical distance to the lens center.
Parameters-
verticalDistanceToLensCenter- The vertical distance from the center of the lenses to the bottom of the inserted device. Measured in meters.
public String toString ()- Returns a string containing a concise, human-readable description of this object and returns a printable representation of this object.
public Uri toUri ()- Encodes the current Cardboard device parameters into a Uri. The returned Uri can be written into the Cardboard NFC tag, a file, or encoded in a QR code. Additional extra parameters can be added to the returned URL by using the Uri.buildUpon() andUri.Builder.appendQueryParameter(key, value) methods. The parameter key name URI_KEY_PARAMS is reserved. Returns a Uri encoding the current Cardboard device parameters. public boolean writeToOutputStream (OutputStream outputStream)- Attempts to write the parameters into the given output stream.Caller is responsible for closing stream and returns whether the parameters were successfully written.
Parameters-
outputStream- OutputStream in which the parameters are stored.
D- CardboardView- This is a public class, CardboardView Convenience extension of GLSurfaceView that can be used for VR rendering. Designed to work in full screen mode with a landscape or reverse landscape orientation. This view can be used as a normal GLSurfaceView by implementing one of its rendering interfaces:
CardboardView.StereoRenderer: abstracts all stereoscopic rendering details from the renderer. • CardboardView.Renderer: for complex engines that need to handle all stereo rendering details by themselves.
The CardboardView.StereoRenderer interface is recommended for all applications that can make use of it, while the CardboardView.Renderer interface is discouraged and should only be used if really needed. The view allows switching from VR mode to normal rendering mode in stereo renderers at any time by calling thesetVRModeEnabled method.
Interface-
1- CardboardView.Renderer- Interface for renderers who need to handle all the stereo rendering details by themselves.
2- CardboardView.StereoRenderer- Interface for renderers that delegate all stereoscopic rendering details to the view.
Constructors-
CardboardView (Context context)
CardboardView (Context context, AttributeSet attrs)
Public Methods -
public boolean getAlignmentMarkerEnabled ()- Returns whether the alignment marker is drawn. Returns true if the alignment marker is enabled, false otherwise. Enabled by default.
public CardboardDeviceParams getCardboardDeviceParams ()- Returns the physical parameters of the current Cardboard device. This is a convenience method for getHeadMountedDisplay().getCardboardDeviceParams(). Changes to the returned object do not have any affect on rendering. To make them effective use theupdateCardboardDeviceParams method. Returns the physical parameters of the current Cardboard device.
public void getCurrentEyeParams (HeadTransform head, Eye leftEye, Eye rightEye,Eye monocular)- Retrieves the current parameters for each eye. This method is designed for API users that have their own rendering loop and cannot use the standardCardboardView.Renderer and CardboardView.StereoRenderer interfaces. Its use is discouraged for other purposes for performance reasons. If a renderer has been set and a renderer thread is used, this call will block until the renderer thread is able to provide the required data.
Parameters-
Head - Where the head transformation will be written. Cannot be null.
leftEye - Where the left eye parameters will be written, only if VR mode is enabled.
rightEye - Where the right eye parameters will be written, only if VR mode is enabled.
Monocular - Where the monocular parameters will be written, only if VR mode is disabled.
public boolean getDistortionCorrectionEnabled ()- Gets whether distortion correction is enabled. Returns true if distortion correction is enabled, false otherwise.
public HeadMountedDisplay getHeadMountedDisplay ()- Returns the current head mounted display this view is rendering for. Contains various parameters about the screen and Cardboard device that combined make up the head mounted display. Note that changing the returned object will not make any changes to rendering. For that purpose theupdateCardboardDeviceParams and updateScreenParams methods should be used instead. Returns The parameters of the target head mounted display.
public float getInterpupillaryDistance ()- Gets the interpupillary distance. The Cardboard framework currently assumes that user IPD matches inter-lens distance of the viewing device. Returns The current interpupillary distance in meters.
public boolean getRestoreGLStateEnabled ()- Returns whether or not the application's GL state after postprocessing is restored. Returns true if GL state restoration is currently enabled, false otherwise. Enabled by default.
public ScreenParams getScreenParams ()- Returns the screen parameters of the inserted device. This is a convenience method for getHeadMountedDisplay().getScreenParams(). Changes to the returned object do not have any affect on rendering. To make them effective use theupdateScreenParams method. Returns the screen parameters of the inserted device.
public boolean getSettingsButtonEnabled ()- Returns whether the settings button is drawn. Returns true if the settings button is enabled, false otherwise. Enabled by default.
public boolean getVRMode ()- Returns the current VR mode setting. Returns true if VR mode is currently enabled, false otherwise. Enabled by default.
public boolean getVignetteEnabled ()- Returns whether or not vignetting is enabled. Returns true if vignetting is currently enabled, false otherwise. Enabled by default.
public void onPause ()- Informs the view that the activity has been paused.
public void onResume ()- Informs the view that the activity has been resumed.
public void setAlignmentMarkerEnabled (boolean enabled)- Enables or disables drawing a vertical line dividing the viewport in half. This is designed to help users correctly align the cardboard to the screen. Only applies when VR mode is enabled.
Parameters-
Enabled - true to enable drawing the alignment marker, false to disable.
public void setDistortionCorrectionEnabled (boolean enabled)- Sets whether distortion correction is enabled. Enabled by default. Changes will be effective from the first frame after this call. Parameters Enabled - true to enable distortion correction, false to disable.
public void setDistortionCorrectionTextureFormat (int textureFormat, int textureType)- Sets the format of the texture to use for distortion correction.
Parameters-
textureFormat - GL constant describing the texture format in glTexImage2D.
textureType - GL constant describing the texture data type in glTexImage2D.
public void setRenderer (CardboardView.StereoRenderer renderer)- Sets a renderer that delegates all details about stereoscopic rendering to the view. Only one renderer should be set during the entire lifetime of this object. See the StereoRenderer interface for details.
Parameters-
Renderer- Stereo renderer to set.
public void setRenderer (CardboardView.Renderer renderer)- Sets a renderer that handles all stereoscoping rendering details by itself. Only one renderer should be set during the entire lifetime of this object. See the Renderer interface for details.
Parameters-
Renderer- Renderer to set. Cannot be null.
public void setRestoreGLStateEnabled (boolean enabled)- Enables or disables restoration of the application's GL state after postprocessing. CardboardView may perform certain postprocessing steps at the end of each frame. For example, application imagery might be rendered into a texture instead of on-screen. If this flag is enabled, the framework ensures that the GL state at the beginning of the next frame is equivalent to the GL state at the end of the last frame. Enabled by default. If disabled, applications may gain a performance boost but can't make any assumptions about the following subset of the GL state machine at the beginning of each frame:
• Viewport
• Clear color
• Active texture unit
• Shader program that is being used
• Vertex attributes (pointers and whether or not they are enabled)
• Whether GL_CULL_FACE and GL_SCISSOR_TEST are enabled
• Bindings for GL_ARRAY_BUFFER and GL_ELEMENT_ARRAY_BUFFER
• Binding for GL_TEXTURE_2D in texture unit 0
There are two exceptions:
1. The currently bound frame buffer will always be restored, regardless of the state of this setting.
2. Vertex attribute bindings are never restored. Any calls to glVertexAttribPointer at the end of last frame will not be in effect anymore at the beginning of next frame.
Parameters-
Enable - true to enable GL state restoration, false to disable.
public void setSettingsButtonEnabled (boolean enabled)- Enables or disables drawing a settings button at the bottom center of the screen. Tapping the button sends the user to the Google Cardboard app where they can configure user parameters and Cardboard viewer parameters. The configuration will automatically apply to all of the user's apps that are using the vrtoolkit. Only applies when VR mode is enabled.
Parameters-
enabled - true to enable drawing the settings button, false to disable.
public void setVRModeEnabled (boolean enabled)- Enables or disables VR rendering mode. Controls stereo rendering and distortion correction. Enabled by default. Changes will be effective from the first frame after this call. If disabled, no interpupillary distance will be applied to the eye transformations and automatic distortion correction will not take place. Changes will be applied to the next frames being drawn. See the documentation of the Renderer and StereoRenderer interfaces for details on how they are affected by VR mode.
Parameters-
enabled - true to enable VR mode, false to disable.
public void setVignetteEnabled (boolean enabled)- Enables or disables vignetting around the frame edge. If this flag is enabled, the distortion shader applies a darkening effect to the edges of the visible viewport, simulating vignetting. Enabled by default.
Parameters-
Enabled - true to enable vignette effect, false to disable.
public void undistortTexture (int inputTexture)- Undistorts the provided texture by rendering into the current output buffer. This method is designed for API users that have their own rendering loop and cannot use the standardCardboardView.Renderer and CardboardView.StereoRenderer interfaces. Its use is discouraged for other purposes. If a renderer has been set, texture undistortion will take place in the renderer thread. Otherwise the operation will happen in the calling thread. It is the responsibility of the caller to ensure the validity of the texture in the GL context of the thread where is used.
Parameters-
inputTexture- Texture name to undistort.
public void updateCardboardDeviceParams (CardboardDeviceParams cardboardDeviceParams)- Updates the physical parameters of the Cardboard device used for rendering. Changes will be effective from the first frame after this call.
Parameters-
cardboardDeviceParams - Physical parameters of a Cardboard-compatible device. Ignores the request if the object is null or same as current.
public void updateScreenParams (ScreenParams screenParams)- Updates the screen parameters used for rendering. Updates the screen parameters of the device inserted in the Cardboard. Changes will be effective from the first frame after this call.
Parameters-
screenParams - Parameters to update. Ignored if null.
E- Constants -Static class containing useful constants. public static final String CARDBOARD_CATEGORY Apps that use vrtoolkit should include this category (along with action MAIN) in their AndroidManifest.xml. An Activity tagged with this category will show up in the list of Cardboard apps in the Cardboard launcher.
Example -
intent filter: Constant Value: "com.google.intent.category.CARDBOARD"
public static final String VERSION - The vrtoolkit version. Constant Value: "0.5.0"
F- Distortion- This is public class Distortion. Defines all required parameters to correct the distortion caused by the lenses.
Public Constructors -
public Distortion ()
public Distortion (Distortion other)- Constructs a copy of another distortion object.
Parameters-
Other - The distortion object to copy from.
Public Methods-
public float distort (float radius)- Distorts a radius by its distortion factor from the center of the lenses. Returns the distorted radius in tan-angle units.
Parameters-
Radius - Radius from the lens center in tan-angle units.
public float distortInverse (float radius)- Calculates the inverse distortion for a radius. Allows to compute the original undistorted radius from a distorted one. See also getApproximateInverseDistortion() for a faster but potentially less accurate method. Returns The undistorted radius in tan-angle units. 
Parameters-
Radius - Distorted radius from the lens center in tan-angle units.
public float distortionFactor (float radius)- Returns the distortion factor of a point. Returns The distortion factor. Multiply by this factor to distort points.
Parameters -
radius - Radius of the point from the lens center in tan-angle units.
public boolean equals (Object other)- Compares this instance with the specified object and indicates if they are equal. Returns true if the objects are equal, false otherwise.
Parameters-
other - The object to compare this instance with.
public Distortion getApproximateInverseDistortion (float maxRadius)- Builds an inverse-distortion object with least-squares-fitted coefficients. This is intended for implementing application-side custom distortion. Use .getCoefficients() on the returned object to retrieve the inverse distortion function's coefficients. This is an approximate inverse, and using .distort() on the returned object will be faster but less accurate than using the distortInverse() method on the original. For useful results, the input distortion must be well-behaved in the 0..maxRadius range. Returns New distortion object. Parameters-
maxRadius - Maximum supported radius in tan-angle units. Should be set to match the maximum expected field of view angle.
public float[] getCoefficients ()-Returns the current coefficients for lens distortion correction. Returns A floating point array with the current barrel distortion coefficients.
public void setCoefficients (float[] coefficients)- Sets the coefficients for lens distortion correction. The coefficients Ki correspond to the pincushion distortion equation:
p' = p (1 + K1 r^2 + K2 r^4 + ... + Kn r^(2n))
Where r is the distance from the optical center, p the input point and p' the output point.
Parameters-
coefficients - Barrel distortion coefficients to set.
public String toString ()- Returns a string containing a concise, human-readable description of this object. Returns a printable representation of this object.
G- DistortionRenderer- public class DistortionRenderer Encapsulates the rendering operations to correct lens distortion. This class is not thread-safe. For performance reasons, exposed public methods in this class are assumed to run in mutual exclusion (e.g. in the same or non-overlapping threads).
Public Constructors-
public DistortionRenderer ()
Public Methods-
public void afterDrawFrame ()- Performs distortion correction. Must be called after drawing a frame to correct its distortion. Note that this method is only allowed to modify the parts of the OpenGL state machine which are backed up and restored using a GLStateBackup object.
public void beforeDrawFrame ()- Performs the required setup to correct distortion. Must be called before drawing a frame that should be undistorted.
public boolean haveViewportsChanged ()- Checks if the distortion-corrected dimensions of the viewports have changed since the last call to updateViewports. Returns true if the dimensions have changed, false otherwise.
public void onFovChanged (HeadMountedDisplay hmd, FieldOfView leftFov,FieldOfView rightFov, float virtualEyeToScreenDistance)- To be called when a change in the field of view of any eye happens. Must be called at least once prior to beforeDrawFrame(). Calling this method between beforeDrawFrame() andafterDrawFrame() calls will raise an IllegalStateException. This method might recompute the mesh used for distortion correction, but no changes involving GL calls will take place until beforeDrawFrame() is called.
Parameters-
Hmd - The head mounted display.
leftFov - The field of view of the left eye.
rightFov - The field of view of the right eye.
virtualEyeToScreenDistance - The virtual-eye-to-screen distance in meters.
public void setRestoreGLStateEnabled (boolean enabled)- Enables or disables restoration of the application's GL state after postprocessing. If this flag is enabled, the framework ensures that the GL state at the beginning of the next frame is equivalent to the GL state at the end of the last frame. Enabled by default.
Parameters-
Enabled - true to enable GL state restoration, false to disable.
public void setTextureFormat (int textureFormat, int textureType)- Sets the format of the texture to use for distortion correction. Calling this method between beforeDrawFrame() and afterDrawFrame() calls will raise anIllegalStateException.
Parameters-
textureFormat- GL constant describing the texture format in glTexImage2D.
textureType- GL constant describing the texture data type in glTexImage2D.
public void setVignetteEnabled (boolean enabled)- Enables or disables vignetting around frame edge. If this flag is enabled, the distortion shader applies a darkening effect to the edges of the visible viewport, simulating vignetting. Enabled by default.
Parameters-
Enabled - true to enable vignette effect, false to disable.
public void undistortTexture (int textureId)- Undistorts the provided texture by rendering into the current output target.
Parameters-
textureId - Texture to undistort.
public void updateViewports (Viewport leftViewport, Viewport rightViewport)- Updates the eye viewports to their effective dimensions after distortion correction.
Parameters-
leftViewport - Object updated with the viewport for the left eye.
rightViewport - Object updated with the viewport for the right eye.
H- Eye-This is public class Eye Describes the stereoscopic rendering details of an eye.
Public Constructors-
public Eye (int type)- Creates a new set of eye parameters.
Parameters- 
Type - One of the Eye.Type constants describing the eye this object refers to. Behavior is undefined if an invalid eye constant is provided.
Public Methods-
public float[] getEyeView ()- Returns a matrix that transforms from the camera to the current eye. This matrix should premultiply the camera matrix. Assumes a scale of 1 world unit = 1 meter when applying the interpupillary distance. If this not your case, make sure to call android.opengl.Matrix.scaleM on this matrix to correct it. The transformation includes head tracking rotation, position shift and interpupillary distance shift. Use this if you just want to get an eye view from your normal view. Returns  A 4x4 column-major representing the transformation from the camera to this eye.
public FieldOfView getFov ()- Returns the field of view for this eye. Use the getFov().toPerspectiveMatrix method to generate the appropriate perspective projection matrix to use. Returns the field of view for this eye.
public float[] getPerspective (float zNear, float zFar)- Convenience method that returns the perspective projection matrix for this eye. Calls getFov().toPerspectiveMatrix to generate the perspective matrix to use. Returns a 4x4 column-major matrix representing the perspective projection for this eye.
Parameters-
zNear - Near Z plane to use in the projection.
zFar - Far Z plane to use in the projection.
public int getType ()- Returns the eye type this object refers to. Returns the current eye as one of the Eye.Type constants.
public Viewport getViewport ()- Returns the viewport for this eye. Returns viewport to use when rendering this eye.
public void setProjectionChanged ()- Forces to clean up any cached projection matrices. Called by the framework when projection parameters change between frames. Should be called if the eye's field of view object returned by getFov() is changed.

Google Cardboard Interfaces


Library Cardboard Api - com.google.vrtoolkit.cardboard
A- CardboardView.Renderer -  Interface for renderers who need to handle all the stereo rendering details by themselves. They are following methods-
  • onDrawFrame(HeadTransform headTransform, Eye leftEye, Eye rightEye) - Requests to draw a new frame. The implementor is assumed to handle all stereoscopic details by itself by making use of the provided head transformation and eye parameters. If distortion correction is enabled the GL context will be set to draw into a framebuffer backed by a texture at the time of this call. If an implementor needs to change the current framebuffer, it must be reset back afterwards to the one obtained via glGetIntegerv(GL_FRAMEBUFFER_BINDING, ...) at the beginning of this call. If VR mode is disabled, instead of providing the parameters of two eyes, the left eye will contain monocular rendering parameters and the right eye will be null. No distortion correction will take place in that case. For monocular rendering, the implementor should feel free to ignore the FieldOfView and instead create a perspective matrix with whatever field of view is desired for monocular rendering (ScreenParams.getWidth()/ScreenParams.getHeight() can provide the aspect ratio). This method will not be called if the view is not a fullscreen landscape view.
    Parameters
    headTransform -The head transformation for this frame, independent to any eyes.
    leftEye -Parameters of the left eye, or a single eye if VR mode is disabled. 
    rightEye- Parameters of the right eye, or null if VR mode is disabled.
  • onFinishFrame (Viewport viewport) - onFinishFrame is called before a frame is finished. By the time of this call, the frame contents have been already drawn and, if enabled, distortion correction has been applied. This method allows to perform additional overlay rendering over the frame results. For example, it could be used to draw markers that help users to properly center their device screens in their Cardboards. A viewport object describing the bounds of the full surface is provided, but not set in the GL context. Renderer implementors are responsible of setting the viewport if needed. This method will not be called if the view is not a fullscreen landscape view.
  • Parameters- 
    Viewport - Viewport of the full GL surface. To be set by renderers if needed.
  • onRendererShutdown () -   Called on the renderer thread when the thread is shutting down. Allows releasing GL resources and performing shutdown operations in the renderer thread. Called only if there was a previous call to onSurfaceCreated.
  • onSurfaceChanged (int width, int height) - Called when there is a change in the surface dimensions. Viewport, field of view and projection details are automatically updated. By default, rendering will be disabled if the view is not a fullscreen landscape view. This is determined by comparing the full-view surface dimensions against the screen size expectations defined in ScreenParams. Although discouraged, these expectations can be changed by calling the updateScreenParams method.
  • Parameters - 
    Width -New width of the surface in pixels. 
    Height- New height of the surface in pixels

  • onSurfaceCreated (EGLConfig config) - Called when the surface is created or recreated.
  • Parameters- 
    Config -The EGL configuration used when creating the surface.
B- CardBoardView.StereoRenderer- Interface for renderers that delegate all stereoscopic rendering details to the view. Implementors should simply render a view as they would normally do using the provided transformation parameters. All stereoscopic rendering and distortion correction details are abstracted from the renderer and managed internally by the view.

  • onDrawEye (Eye eye) - Requests to draw the contents from the point of view of an eye. If distortion correction is enabled the GL context will be set to draw into a framebuffer backed by a texture at the time of this call, so if an implementor need to change the framebuffer for some rendering stage then the implementor must reset the framebuffer to the one obtained via glGetIntegerv(GL_FRAMEBUFFER_BINDING, ...) afterwards. If VR mode is disabled the onDrawEye method will be called only once with parameters to draw a monocular system and distortion correction will not take place. For monocular rendering, the implementor should feel free to ignore the FieldOfView and instead create a perspective matrix with whatever field of view is desired (ScreenParams.getWidth()/ScreenParams.getHeight() can provide the aspect ratio). See the setVRModeEnabled method for details. This method will not be called if the view is not a fullscreen landscape view. See onSurfaceChanged for details.
  • Parameters- 
    eye -The eye to render, including the transformations to be applied.
  • onFinishFrame (Viewport viewport) - Called before a frame is finished. By the time of this call, the frame contents have been already drawn and, if enabled, distortion correction has been applied. This method allows to perform additional overlay rendering over the frame results. For example, it could be used to draw markers that help users to properly center their device screens in their Cardboards. Any rendering in this step is relative to the full surface, not to any single eye view. A viewport object describing the bounds of the full surface is provided and automatically set in the current GL context. This method will not be called if the view is not a fullscreen landscape view. See onSurfaceChanged for details.
  • Parameters -
    Viewport- Viewport of full GL surface. Automatically set before this call.
  • onNewFrame (HeadTransform headTransform) - Called when a new frame is about to be drawn. Allows to differenciate between rendering eye views and different frames. Any per-frame operations not specific to a single view should happen here.
  • Parameters-
    headTransform- The head transformation in the new frame.
  • onRendererShutdown () - Called on the renderer thread when the thread is shutting down. Allows releasing GL resources and performing shutdown operations in the renderer thread. Called only if there was a previous call to onSurfaceCreated.
  •  onSurfaceChanged (int width, int height) - Called when there is a change in the surface dimensions. All values are relative to the size required to render a single eye. If VR mode is enabled this will be the size to render one of the eyes. If VR mode is disabled this will be the size of the full surface. Viewport, field of view and projection details are automatically updated. By default, rendering will be disabled if the view is not a fullscreen landscape view. This is determined by comparing the full-view surface dimensions against the screen size expectations defined in ScreenParams. Although discouraged, these expectations can be changed by calling the updateScreenParams method. Note that for stereo renderers the reported surface size corresponds to a single eye, which has half the width of the full view surface when VR mode is enabled.
  • Parameters-
    Width- New width of the surface for a single eye in pixels.
    Height- New height of the surface for a single eye in pixels. 
  • onSurfaceCreated (EGLConfig config) - Called when the surface is created or recreated.
  • Parameters- 
    Config- The EGL configuration used when creating the surface.

Cardboard App Launcher Example


Cardboard App Launcher is an Android app launcher designed for use with the Google Cardboard virtual reality head mounted display. Cardboard App Launcher is intended to replace a regular launcher when the user places their device inside a Google Cardboard viewer.
Unlike a regular Android launcher, Cardboard App Launcher uses side by side 3D to display a launcher interface that is usable while the phone is placed in Google Cardboard. The launcher can be controlled simply by the user moving his or her head and "clicking" with the magnetic ring or "hovering" over an icon to launch the corresponding application. Cardboard App Launcher attempts to only display apps that are compatible with Google Cardboard, but in the case that it fails to list a specific app, the user can select it in the settings menus. When the user exits Cardboard Home, it brings them back to their regular launcher, making for a fairly seamless experience. This project enables users to know about the use of VR Cardboard and its overall functioning.
Equipment Required – VR Cardboard, NFC enabled device.
How to use the above functionality for end users?
The following steps involved in the use of VR application for Cardboard App Launcher functionality are listed below:
Step 1- Start the application on your mobile devices.
Step 2- The Application will ask the user to put the device into the cardboard.
Step 3- Pull the magnet to see the cardboard icon.
Step 4-You will find the cardboard app.
How to develop this application on Eclipse?
It is very simple for developers to make this application go live. Follow the below given steps to achieve your goal:
Step 1- Click on New in the File Menu Bar.
Step 2- Go to the Android Application Project in the drop down.
Step 3- A pop-up will appear showing the Application Name in which you have to enter CardboardAppLauncher.Similarly, enter the project name as CardboardAppLauncher, you can also keep a different project name.
 Similarly, enter the package name as cardboard.app.launcher, this also you can keep with a different package name. 
Step 4- The Minimum Required SDK should be API 16: Android 4.1 (Jelly Bean), target SDK you can keep as much as you want.


Step 5- Click the Next Button thrice and Choose Blank Activity, again click on Next and enter Activity Name as LauncherActivity.
Step 6- Enter Layout Name as activity_game  and click on Finish button.


Step 7: Now, download the cardboard.jar
Step 8- Go to the manifest file to give following permissions:

Ø  <uses-sdk android:minSdkVersion="16"/> indicates that the device must be running API Level 16 (Jellybean) or higher.
Ø  <uses-sdk android:targetSdkVersion="19"/> indicates our app is targetting API Level 19 (KitKat).
Ø  <uses-feature android:glEsVersion="0x00020000" android:required="true" /> indicates that the device must support OpenGL ES 2.0 to run the demo app.
Ø  android:screenOrientation="landscape" indicates that the activity's required screen orientation is "landscape." This is the orientation you must set for VR apps. The view used by the Cardboard SDK, CardboardView, only renders on fullscreen and landscape (landscapereverseLandscapesensorLandscape) modes.
Ø  The setting android:configChanges="orientation|keyboardHidden" is also recommended, but not mandatory.
Ø  android.permission.NFC permission is required by the Cardboard SDK to access Cardboard's NFC tag.
Ø android.permission.READ_EXTERNAL_STORAGE and 
android.permission.WRITE_EXTERNAL_STORAGE. These permissions are required by the Cardboard SDK to pair the user's phone to their VR viewer.
Ø  android.permission.VIBRATE permission is required by our demo app to make the phone vibrate to inform the user that something has happened.
Ø    android.permission.RECORD_AUDIO permission is required by our demo app to record the audio of the device.
Ø    Define  <category android:name="android.intent.category.HOME" />
Ø  indicates that when you press home button, your app will be listed as an option to launch the launcher home or your home activity (along with all the applications which have this category in their manifest for an activity).

Ø  <category android:name="android.intent.category.DEFAULT"/>Setting Category to Default doesn't mean that this Activity will be used by default when your app launches. The Activity just says to system that " Oh I could be started, even if the starter Intent's category is set to Nothing at all ! "
Step 9- Right click on the source file à New à Class à SeekBarPreference à Finish.
Step 10- Now, create the SeekBarPreference class with the help of DialogPreference which is described below:
A base class for Preference objects that are dialog-based. These preferences will, when clicked, open a dialog showing the actual preference controls.
A SeekBar is an extension of ProgressBar that adds a draggable thumb. The user can touch the thumb and drag left or right to set the current progress level or use the arrow keys. Placing focusable widgets to the left or right of a SeekBar is discouraged.
Clients of the SeekBar can attach a SeekBar.OnSeekBarChangeListener to be notified of the user's actions. The demo app's SeekBarPreference extends DialogPreference. SeekBarPreference implements the SeekBar.OnSeekBarChangeListener, OnClickListener.
The following code begins –
package cardboard.app.launcher;
import android.app.AlertDialog;
import android.content.Context;
import android.os.Bundle;
import android.preference.DialogPreference;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.TextView;

public class SeekBarPreference extends DialogPreference implements SeekBar.OnSeekBarChangeListener, OnClickListener
{
    // ---------------------------------------------------------------------------------
    // Private attributes :
    private static final String androidns="http://schemas.android.com/apk/res/android";

    private SeekBar mSeekBar;
    private TextView mSplashText,mValueText;
    private Context mContext;

    private String mDialogMessage, mSuffix;
    private int mDefault, mMax, mValue = 0;
    // ---------------------------------------------------------------------------------
    // Constructor :
    public SeekBarPreference(Context context, AttributeSet attrs) {

        super(context,attrs);
        mContext = context;

        // Get string value for dialogMessage :
        int mDialogMessageId = attrs.getAttributeResourceValue(androidns, "dialogMessage", 0);
        if(mDialogMessageId == 0) mDialogMessage = attrs.getAttributeValue(androidns, "dialogMessage");
        else mDialogMessage = mContext.getString(mDialogMessageId);

        // Get string value for suffix (text attribute in xml file) :
        int mSuffixId = attrs.getAttributeResourceValue(androidns, "text", 0);
        if(mSuffixId == 0) mSuffix = attrs.getAttributeValue(androidns, "text");
        else mSuffix = mContext.getString(mSuffixId);

        // Get default and max seekbar values :
        mDefault = attrs.getAttributeIntValue(androidns, "defaultValue", 0);
        mMax = attrs.getAttributeIntValue(androidns, "max", 100);
    }
    // ---------------------------------------------------------------------------------
    // DialogPreference methods :
    @Override
    protected View onCreateDialogView() {

        LinearLayout.LayoutParams params;
        LinearLayout layout = new LinearLayout(mContext);
        layout.setOrientation(LinearLayout.VERTICAL);
        layout.setPadding(6,6,6,6);

        mSplashText = new TextView(mContext);
        mSplashText.setPadding(30, 10, 30, 10);
        if (mDialogMessage != null)
            mSplashText.setText(mDialogMessage);
        layout.addView(mSplashText);

        mValueText = new TextView(mContext);
        mValueText.setGravity(Gravity.CENTER_HORIZONTAL);
        mValueText.setTextSize(32);
        params = new LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.FILL_PARENT,
                LinearLayout.LayoutParams.WRAP_CONTENT);
        layout.addView(mValueText, params);

        mSeekBar = new SeekBar(mContext);
        mSeekBar.setOnSeekBarChangeListener(this);
        layout.addView(mSeekBar, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));

        if (shouldPersist())
            mValue = getPersistedInt(mDefault);

        mSeekBar.setMax(mMax);
        mSeekBar.setProgress(mValue);

        return layout;
    }

    @Override
    protected void onBindDialogView(View v) {
        super.onBindDialogView(v);
        mSeekBar.setMax(mMax);
        mSeekBar.setProgress(mValue);
    }

    @Override
    protected void onSetInitialValue(boolean restore, Object defaultValue)
    {
        super.onSetInitialValue(restore, defaultValue);
        if (restore)
            mValue = shouldPersist() ? getPersistedInt(mDefault) : 0;
        else
            mValue = (Integer)defaultValue;
    }
    // ----------------------------------------------------------------------------------
    // OnSeekBarChangeListener methods :
    @Override
    public void onProgressChanged(SeekBar seek, int value, boolean fromTouch)
    {
        String t = String.valueOf(value);
        mValueText.setText(mSuffix == null ? t : t.concat(" " + mSuffix));
    }

    @Override
    public void onStartTrackingTouch(SeekBar seek) {}
    @Override
    public void onStopTrackingTouch(SeekBar seek) {}

    public void setMax(int max) { mMax = max; }
    public int getMax() { return mMax; }

    public void setProgress(int progress) {
        mValue = progress;
        if (mSeekBar != null)
            mSeekBar.setProgress(progress);
    }
    public int getProgress() { return mValue; }
    // ---------------------------------------------------------------------------------
    // Set the positive button listener and onClick action :
    @Override
    public void showDialog(Bundle state) {

        super.showDialog(state);

        Button positiveButton = ((AlertDialog) getDialog()).getButton(AlertDialog.BUTTON_POSITIVE);
        positiveButton.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {

        if (shouldPersist()) {

            mValue = mSeekBar.getProgress();
            persistInt(mSeekBar.getProgress());
            callChangeListener(Integer.valueOf(mSeekBar.getProgress()));
        }

        ((AlertDialog) getDialog()).dismiss();
    }
    // ----------------------------------------------------------------------------------

}
Step 11-The Application item is created to define the icons position, gravity, and its type whose code is as follows:
package cardboard.app.launcher;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;

public class ApplicationItem {
    public int x = 0;
    public Rect pos = new Rect();
    public Bitmap icon;
    public Bitmap iconGry;
    public String name = "";
    public int z = 10;
    public ApplicationInfo appInfo;
    private Intent launchIntent;
    private Context context;

    public ApplicationItem (Rect pos, ApplicationInfo appInfo, PackageManager pkgMan, Context context) {
        this.pos = pos;
        this.icon = ((BitmapDrawable) appInfo.loadIcon(pkgMan)).getBitmap();
        this.iconGry = getGrayscaleBitmap(this.icon);
        this.name = pkgMan.getApplicationLabel(appInfo).toString();
        this.appInfo = appInfo;
        this.launchIntent = pkgMan.getLaunchIntentForPackage(appInfo.packageName);
        this.context = context;
    }
 public ApplicationItem (Rect pos, Bitmap icon, int type, PackageManager pkgMan, Context context) {
        this.pos = pos;
        this.icon = icon;
        this.iconGry = getGrayscaleBitmap(this.icon);
        if (type == 0) {
            this.name = "Exit Google Cardboard";
            if (LauncherActivity.preferences.getBoolean("use_as_home", true)) {
                this.launchIntent = new Intent(Intent.ACTION_MAIN);
                this.launchIntent.addCategory(Intent.CATEGORY_HOME);
                this.launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                this.launchIntent.setClassName("android", "com.android.internal.app.ResolverActivity");
            }
            else {
                Intent intent = new Intent(Intent.ACTION_MAIN);
                intent.addCategory(Intent.CATEGORY_HOME);
                String currentHomePackage = pkgMan.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY).activityInfo.packageName;
                this.launchIntent = pkgMan.getLaunchIntentForPackage(currentHomePackage);
            }
        }
        else if (type == 1) {
            this.name = "Preferences";
            this.launchIntent = new Intent(context, SettingsActivity.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        }
        else if (type == 2) {
            this.name = "Adjust Volume";
            this.launchIntent = new Intent(context, SettingsActivity.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        }
        this.context = context;
    }

    private Bitmap getGrayscaleBitmap(Bitmap color) {
        ColorMatrix colorMatrix = new ColorMatrix();
        colorMatrix.setSaturation(0);
        ColorMatrixColorFilter colorMatrixFilter = new ColorMatrixColorFilter(colorMatrix);
        Bitmap grayscale = color.copy(Bitmap.Config.ARGB_8888, true);
        Paint paint = new Paint();
        paint.setColorFilter(colorMatrixFilter);
        Canvas canvas = new Canvas(grayscale);
        canvas.drawBitmap(grayscale, 0, 0, paint);
        return grayscale;
    }

    public void move (int deltaTime) {
        pos.left += deltaTime / 1000;
    }

    public void launch () {
        context.startActivity(launchIntent);
        android.os.Process.killProcess(android.os.Process.myPid());
    }
 }

Step 12- Now, create the folder with xml in the res folder inside which two xml  files will be defined whose code is as follows:
Pref_general.xml à
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<CheckBoxPreference
        android:key="launch_on_hover"
        android:title="@string/pref_title_launch_on_hover"
        android:summary="@string/pref_description_launch_on_hover"
        android:defaultValue="true" />

    <CheckBoxPreference
        android:key="use_as_home"
        android:title="@string/pref_title_use_as_home"
        android:summary="@string/pref_description_use_as_home"
        android:defaultValue="true" />

    <EditTextPreference
        android:key="package_names_to_add"
        android:title="@string/pref_title_package_names"
        android:summary="@string/pref_description_package_names"
        android:defaultValue="@string/pref_default_package_names"
        android:selectAllOnFocus="false"
        android:inputType="textNoSuggestions"
        android:singleLine="true"
        android:maxLines="1" />

    <EditTextPreference
        android:key="blacklist"
        android:title="@string/pref_title_blacklist"
        android:summary="@string/pref_description_blacklist"
        android:defaultValue="@string/pref_default_blacklist"
        android:selectAllOnFocus="false"
        android:inputType="textNoSuggestions"
        android:singleLine="true"
        android:maxLines="1" />

    <cardboard.app.launcher.SeekBarPreference
        android:key="interpupilary_distance"
        android:title="@string/pref_title_interpupilary_distance"
        android:summary="@string/pref_description_interpupilary_distance"
        android:dialogMessage="@string/pref_description_interpupilary_distance"
        android:defaultValue="50"
        android:max="100" />

    <CheckBoxPreference
        android:key="vibrate_on_selection"
        android:title="@string/pref_title_vibrate"
        android:defaultValue="true" />

    <CheckBoxPreference
        android:key="disable_volume_buttons"
        android:title="@string/pref_title_disable_volume_buttons"
        android:summary="@string/pref_description_disable_volume_buttons"
        android:defaultValue="false" />

        <CheckBoxPreference
        android:key="draw_wallpaper"
        android:title="@string/pref_title_draw_wallpaper"
        android:summary="@string/pref_description_draw_wallpaper"
        android:defaultValue="true" />

    <CheckBoxPreference
        android:key="listen_for_voice"
        android:title="@string/pref_title_listen_for_voice"
        android:summary="@string/pref_description_listen_for_voice"
        android:defaultValue="true" />

</PreferenceScreen>
Pref_headers.xml à
<preference-headers xmlns:android="http://schemas.android.com/apk/res/android">
 <!-- These settings headers are only used on tablets. -->
 <header android:fragment="cardboard.app.launcher.SettingsActivity$GeneralPreferenceFragment"
        android:title="@string/pref_header_general" />
 </preference-headers>
Step 13- The Setting activity has been created with the help of Preference activity which is described as follows:
This is the base class for an activity to show a hierarchy of preferences to the user. Prior to HONEYCOMB this class only allowed the display of a single set of preference; this functionality should now be found in the new PreferenceFragment class.  The Code is as follows:
package cardboard.app.launcher;
import java.util.List;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Build;
import android.os.Bundle;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceCategory;
import android.preference.PreferenceFragment;
import android.preference.PreferenceManager;

/**
 * A {@link PreferenceActivity} that presents a set of application settings. On
 * handset devices, settings are presented as a single list. On tablets,
 * settings are split by category, with category headers shown to the left of
 * the list of settings.
 * <p>
 * See <a href="http://developer.android.com/design/patterns/settings.html">
 * Android Design: Settings</a> for design guidelines and the <a
 * href="http://developer.android.com/guide/topics/ui/settings.html">Settings
 * API Guide</a> for more information on developing a Settings UI.
 */
public class SettingsActivity extends PreferenceActivity {
    /**
     * Determines whether to always show the simplified settings UI, where
     * settings are presented in a single list. When false, settings are shown
     * as a master/detail two-pane view on tablets. When true, a single pane is
     * shown on tablets.
     */
    private static final boolean ALWAYS_SIMPLE_PREFS = false;


    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);

        setupSimplePreferencesScreen();
    }

    /**
     * Shows the simplified settings UI if the device configuration if the
     * device configuration dictates that a simplified, single-pane UI should be
     * shown.
     */
    private void setupSimplePreferencesScreen() {
        if (!isSimplePreferences(this)) {
            return;
        }

        // In the simplified UI, fragments are not used at all and we instead
        // use the older PreferenceActivity APIs.

        // Add 'general' preferences.
        PreferenceCategory fakeHeader = new PreferenceCategory(this);
        fakeHeader.setTitle(R.string.pref_header_general);
        addPreferencesFromResource(R.xml.pref_general);
    }

    /** {@inheritDoc} */
    @Override
    public boolean onIsMultiPane() {
        return isXLargeTablet(this) && !isSimplePreferences(this);
    }

    /**
     * Helper method to determine if the device has an extra-large screen. For
     * example, 10" tablets are extra-large.
     */
    private static boolean isXLargeTablet(Context context) {
        return (context.getResources().getConfiguration().screenLayout
        & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_XLARGE;
    }

    /**
     * Determines whether the simplified settings UI should be shown. This is
     * true if this is forced via {@link #ALWAYS_SIMPLE_PREFS}, or the device
     * doesn't have newer APIs like {@link PreferenceFragment}, or the device
     * doesn't have an extra-large screen. In these cases, a single-pane
     * "simplified" settings UI should be shown.
     */
    private static boolean isSimplePreferences(Context context) {
        return ALWAYS_SIMPLE_PREFS
                || Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB
                || !isXLargeTablet(context);
    }

    /** {@inheritDoc} */
    @Override
    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    public void onBuildHeaders(List<Header> target) {
        if (!isSimplePreferences(this)) {
            loadHeadersFromResource(R.xml.pref_headers, target);
        }
    }

    /**
     * A preference value change listener that updates the preference's summary
     * to reflect its new value.
     */
    private static Preference.OnPreferenceChangeListener sBindPreferenceSummaryToValueListener = new Preference.OnPreferenceChangeListener() {
        @Override
        public boolean onPreferenceChange(Preference preference, Object value) {
            String stringValue = value.toString();

            if (preference instanceof ListPreference) {
                // For list preferences, look up the correct display value in
                // the preference's 'entries' list.
                ListPreference listPreference = (ListPreference) preference;
                int index = listPreference.findIndexOfValue(stringValue);

                // Set the summary to reflect the new value.
                preference.setSummary(
                        index >= 0
                                ? listPreference.getEntries()[index]
                                : null);

            } else {
                // For all other preferences, set the summary to the value's
                // simple string representation.
                preference.setSummary(stringValue);
            }
            return true;
        }
    };

    /**
     * Binds a preference's summary to its value. More specifically, when the
     * preference's value is changed, its summary (line of text below the
     * preference title) is updated to reflect the value. The summary is also
     * immediately updated upon calling this method. The exact display format is
     * dependent on the type of preference.
     *
     * @see #sBindPreferenceSummaryToValueListener
     */
    private static void bindPreferenceSummaryToValue(Preference preference) {
        // Set the listener to watch for value changes.
        preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener);

        // Trigger the listener immediately with the preference's
        // current value.
        sBindPreferenceSummaryToValueListener.onPreferenceChange(preference,
                PreferenceManager
                        .getDefaultSharedPreferences(preference.getContext())
                        .getString(preference.getKey(), ""));
    }

    /**
     * This fragment shows general preferences only. It is used when the
     * activity is showing a two-pane settings UI.
     */
    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    public static class GeneralPreferenceFragment extends PreferenceFragment {
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            addPreferencesFromResource(R.xml.pref_general);

            // Bind the summaries of EditText/List/Dialog/Ringtone preferences
            // to their values. When their values change, their summaries are
            // updated to reflect the new value, per the Android Design
            // guidelines.
            bindPreferenceSummaryToValue(findPreference("package_names_to_add"));
            bindPreferenceSummaryToValue(findPreference("example_list"));
        }
    }

    @Override
    public void onBackPressed () {
        startActivity(new Intent(getApplicationContext(), LauncherActivity.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
    }

    /**
     * This fragment shows notification preferences only. It is used when the
     * activity is showing a two-pane settings UI.
     */
}
Step 14- Open the class LauncherActivity as defined below:
CardboardActivity is the starting point for coding a cardboard app. CardboardActivity is the base activity that provides easy integration with Cardboard devices. It exposes events to interact with Cardboards and handles many of the details commonly required when creating an activity for VR rendering.
Note that CardboardActivity uses sticky immersive mode, in which the system UI is hidden, and the content takes up the whole screen. This is a requirement for a VR app, since CardboardView will only render when the activity is in fullscreen mode. See Using Immersive Full-Screen Mode for more discussion of this feature.
The demo app's LauncherActivity extends CardboardActivity. LauncherActivity implements the SensorEventListener SensorManager- lets you access the device's sensors. Get an instance of this class by calling Context.getSystemService() with the argument SENSOR_SERVICE. Always make sure to disable sensors you don't need, especially when your activity is paused. Failing to do so can drain the battery in just a few hours. Note that the system will not disable sensors automatically when the screen turns off.
In this demo use MagnetSensor. This is public class. MagnetSensor Magnetometer sensor detector for the cardboard trigger. Provides cardboard trigger events from the device magnetometer to listeners.
MagnetSensor magnetSensor = new MagnetSensor(getApplicationContext());
        MagnetSensor.OnCardboardTriggerListener magnetTriggerListener = new MagnetSensor.OnCardboardTriggerListener() {
            @Override
            public void onCardboardTrigger() {
                gameView.magnetPull();
            }
        };
        magnetSensor.setOnCardboardTriggerListener(magnetTriggerListener);
        magnetSensor.start();

In NFC Sensor  -Provide access to Near Field Communication (NFC) functionality.

NfcSensor.OnCardboardNfcListener nfcListener = new NfcSensor.OnCardboardNfcListener() {
     &n*bsp;      @Override
            public void onInsertedIntoCardboard(CardboardDeviceParams cardboardDeviceParams) {

            }

            @Override
            public void onRemovedFromCardboard() {
                installedApps.get(installedApps.size() - 1).launch();
            }

        };

Now, please go through the whole code as mentioned below:
package cardboard.app.launcher;
import java.util.ArrayList;
import java.util.List;
import android.app.WallpaperManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.media.AudioManager;
import android.os.Bundle;
import android.os.Vibrator;
import android.preference.PreferenceManager;
import android.speech.RecognitionListener;
import android.speech.RecognizerIntent;
import android.speech.SpeechRecognizer;
import android.view.Display;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.Toast;

import com.google.vrtoolkit.cardboard.CardboardActivity;
import com.google.vrtoolkit.cardboard.CardboardDeviceParams;
import com.google.vrtoolkit.cardboard.sensors.HeadTracker;
import com.google.vrtoolkit.cardboard.sensors.MagnetSensor;
import com.google.vrtoolkit.cardboard.sensors.NfcSensor;

public class LauncherActivity extends CardboardActivity implements
              SensorEventListener {

       public static final double TAU = Math.PI * 2;
       private MyView gameView = null;
       public static ArrayList<ApplicationItem> installedApps = new ArrayList<ApplicationItem>();
       public int iconCenter = 0;
       public float rotationalOffset = 0;
       public static float accelData = 0f;
       public static float rawAccelData = 0f;
       public static float rawGyroData = 0f;
       public static float accelDataOld = 0f;
       private SensorManager mSensorManager;
       private Sensor mAccelerometer;
       private Sensor mGyroscope;
       private HeadTracker headTracker;
       private boolean forceAccelerometer = false;
       private float tweenStep = 0;
       public static SharedPreferences preferences;
       public Vibrator mVibrator;
       private Bitmap wallpaper;

       private boolean drawWallpaper = true;
       private boolean startingApp = false;
       private ApplicationItem appToLaunch = null;
       private SpeechRecognizer speechRecog = null;
       private Intent recognizerIntent = null;
       private boolean readyToListen = false;
       private boolean listening = false;
       private int originalVolume = 0;
       public boolean volumePanelExpanded = false;
       public int volumePanelPosition = 0;
       public int volumePanelKnobPosition = 0;
       public int volumePanelWidth = 1;

       private final int APP_SPACING = 115;
       private final float TWEEN_TIMING = 0.5f * 60;
       private final String[] LAUNCH_COMMANDS = { "open", "launch", "play",
                     "start", "begin" };
       private final String[] EXIT_COMMANDS = { "exit", "close", "quit", "stop" };
       private final String[] SETTINGS_COMMANDS = { "preferences", "settings",
                     "options" };

       @Override
       protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              preferences = PreferenceManager
                           .getDefaultSharedPreferences(getBaseContext());
              gameView = new MyView(this);
              setContentView(gameView);

              makeImmersive();

              if (!isMyAppLauncherDefault()
                           && preferences.getBoolean("use_as_home", true)) {
                     Intent intent = new Intent(Intent.ACTION_MAIN);
                     intent.addCategory(Intent.CATEGORY_HOME);
                     intent.setClassName("android",
                                  "com.android.internal.app.ResolverActivity");
                     startActivity(intent);
              }

              installedApps.clear();

              drawWallpaper = preferences.getBoolean("draw_wallpaper", true);
              // get installed apps
              List<ApplicationInfo> packages = getPackageManager()
                           .getInstalledApplications(PackageManager.GET_META_DATA);
              for (int i = 0; i < packages.size(); i++) {
                     if ((packages.get(i).packageName.toLowerCase()
                                  .contains("cardboard")
                                  || packages.get(i).packageName.toLowerCase().contains(
                                                "dive")
                                  || packages.get(i).packageName.toLowerCase().contains("vr")
                                  || packages.get(i).packageName.toLowerCase().contains(
                                                "virtual") || packages.get(i).packageName
                                  .toLowerCase().contains("reality"))

                                  && !packages.get(i).packageName
                                                .equals("cardboard.app.launcher")) {
                           String[] ignoreNames = preferences.getString("blacklist", "")
                                         .split(", ");
                           boolean appOnBlacklist = false;
                           for (int j = 0; j < ignoreNames.length; j++) {
                                  if (getPackageManager()
                                                .getApplicationLabel(packages.get(i)).toString()
                                                .toLowerCase().equals(ignoreNames[j].toLowerCase())) {
                                         appOnBlacklist = true;
                                  }
                           }
                           if (!appOnBlacklist)
                                  installedApps.add(new ApplicationItem(new Rect(
                                                (installedApps.size() - 1) * APP_SPACING, 315, 92,
                                                92), packages.get(i), getPackageManager(),
                                                getBaseContext()));
                     } else {
                           String[] packageNames = preferences.getString(
                                         "package_names_to_add", "").split(", ");
                           for (int j = 0; j < packageNames.length; j++) {
                                  if (getPackageManager()
                                                .getApplicationLabel(packages.get(i)).toString()
                                                .toLowerCase()
                                                .equals(packageNames[j].toLowerCase())
                                                && !packages.get(i).packageName
                                                              .equals("cardboard.app.launcher")) {
                                         installedApps.add(new ApplicationItem(new Rect(
                                                       (installedApps.size() - 1) * APP_SPACING, 315,
                                                       92, 92), packages.get(i), getPackageManager(),
                                                       getBaseContext()));
                                  }
                           }
                     }
              }
              installedApps.add(new ApplicationItem(new Rect(
                           (installedApps.size() - 1) * APP_SPACING, 315, 92, 92),
                           BitmapFactory.decodeResource(getResources(),
                                         R.drawable.volume_icon), 2, getPackageManager(),
                           getBaseContext()));
              installedApps.add(new ApplicationItem(new Rect(
                           (installedApps.size() - 1) * APP_SPACING, 315, 92, 92),
                           BitmapFactory.decodeResource(getResources(),
                                         R.drawable.settings_icon), 1, getPackageManager(),
                           getBaseContext()));
              installedApps.add(new ApplicationItem(new Rect(
                           (installedApps.size() - 1) * APP_SPACING, 315, 92, 92),
                           BitmapFactory.decodeResource(getResources(),
                                         R.drawable.exit_icon), 0, getPackageManager(),
                           getBaseContext()));

              iconCenter = (int) ((((installedApps.size() + 1) / 2) - 4.5) * APP_SPACING);

              mVibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);

              SensorEventListener mSensorListener = new SensorEventListener() {
                     @Override
                     public void onAccuracyChanged(Sensor arg0, int arg1) {
                     }

                     @Override
                     public void onSensorChanged(SensorEvent event) {
                           Sensor sensor = event.sensor;
                           if (sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
                                  accelDataOld = rawAccelData;
                                  rawAccelData = event.values[1];
                                  tweenStep = (rawAccelData - accelData) / TWEEN_TIMING;
                           } else if (sensor.getType() == Sensor.TYPE_GYROSCOPE) {
                                  rawGyroData += event.values[0];
                           }
                     }
              };

              mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
              mGyroscope = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
              mAccelerometer = mSensorManager
                           .getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
              mSensorManager.registerListener(mSensorListener, mGyroscope,
                           SensorManager.SENSOR_DELAY_NORMAL);
              mSensorManager.registerListener(mSensorListener, mAccelerometer,
                           SensorManager.SENSOR_DELAY_NORMAL);
              headTracker = new HeadTracker(getApplicationContext());
              headTracker.startTracking();

              MagnetSensor magnetSensor = new MagnetSensor(getApplicationContext());
              MagnetSensor.OnCardboardTriggerListener magnetTriggerListener = new MagnetSensor.OnCardboardTriggerListener() {
                     @Override
                     public void onCardboardTrigger() {
                           gameView.magnetPull();
                     }
              };
              magnetSensor.setOnCardboardTriggerListener(magnetTriggerListener);
              magnetSensor.start();

              // NfcSensor nfcSensor = NfcSensor.getInstance(getApplicationContext());
              NfcSensor.OnCardboardNfcListener nfcListener = new NfcSensor.OnCardboardNfcListener() {
                     @Override
                     public void onInsertedIntoCardboard(
                                  CardboardDeviceParams cardboardDeviceParams) {

                     }

                     @Override
                     public void onRemovedFromCardboard() {
                           installedApps.get(installedApps.size() - 1).launch();
                     }
              };

              AudioManager mgr = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
              originalVolume = mgr.getStreamVolume(AudioManager.STREAM_MUSIC);
              if (preferences.getBoolean("listen_for_voice", true))
                     mgr.setStreamVolume(AudioManager.STREAM_MUSIC, 0,
                                  AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);

              if (preferences.getBoolean("listen_for_voice", true)) {
                     RecognitionListener recognitionListener = new RecognitionListener() {
                           @Override
                           public void onReadyForSpeech(Bundle bundle) {

                           }

                           @Override
                           public void onBeginningOfSpeech() {
                                  listening = true;
                           }

                           @Override
                           public void onRmsChanged(float v) {

                           }

                           @Override
                           public void onBufferReceived(byte[] bytes) {

                           }

                           @Override
                           public void onEndOfSpeech() {
                                  listening = false;
                           }

                           @Override
                           public void onError(int i) {

                           }

                           @Override
                           public void onResults(Bundle bundle) {
                                  checkForCommands(bundle);
                                  listening = false;
                           }

                           @Override
                           public void onPartialResults(Bundle bundle) {
                                  checkForCommands(bundle);
                           }

                           private void checkForCommands(Bundle bundle) {
                                  ArrayList<String> voiceText = bundle
                                                .getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
                                  for (int i = 0; i < voiceText.size(); i++) {
                                         if (voiceText.get(i).toLowerCase()
                                                       .contains("okay cardboard")
                                                       && voiceText.get(i).toLowerCase()
                                                                     .split("okay cardboard").length > 0) {
                                                String request = voiceText.get(i).toLowerCase()
                                                              .split("okay cardboard")[1].toLowerCase()
                                                              .replace(" ", "");
                                                print(request);
                                                for (int j = 0; j < LAUNCH_COMMANDS.length; j++) {
                                                       if (request.contains(LAUNCH_COMMANDS[j])) {
                                                              print(request);
                                                              for (int k = 0; k < installedApps.size(); k++) {
                                                                     if (request.contains(installedApps
                                                                                  .get(k).name.toLowerCase()
                                                                                  .replace(" ", ""))) {
                                                                           mVibrator.vibrate(90);
                                                                           installedApps.get(k).launch();
                                                                           return;
                                                                     }
                                                              }
                                                       }
                                                }
                                                for (int j = 0; j < EXIT_COMMANDS.length; j++) {
                                                       if (request.contains(EXIT_COMMANDS[j])) {
                                                              installedApps.get(installedApps.size() - 1)
                                                                           .launch();
                                                              return;
                                                       }
                                                }
                                                for (int j = 0; j < SETTINGS_COMMANDS.length; j++) {
                                                       if (request.contains(SETTINGS_COMMANDS[j])) {
                                                              installedApps.get(installedApps.size() - 2)
                                                                           .launch();
                                                              return;
                                                       }
                                                }
                                         }
                                  }
                           }

                           @Override
                           public void onEvent(int i, Bundle bundle) {

                           }
                     };

                     if (recognizerIntent == null) {
                           Toast.makeText(LauncherActivity.this, "No Voice Avalible ",
                                         Toast.LENGTH_LONG).show();
                     } else {
                           recognizerIntent = RecognizerIntent
                                         .getVoiceDetailsIntent(getBaseContext());
                           recognizerIntent
                                         .putExtra(
                                                       RecognizerIntent.EXTRA_SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS,
                                                       30000);
                           recognizerIntent
                                         .putExtra(
                                                       RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS,
                                                       30000);
                           recognizerIntent
                                         .putExtra(
                                                       RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS,
                                                       30000);
                           speechRecog = SpeechRecognizer
                                         .createSpeechRecognizer(getBaseContext());
                           speechRecog.setRecognitionListener(recognitionListener);
                           readyToListen = true;
                           listening = true;

                           speechRecog.startListening(recognizerIntent);
                     }
              }

              wallpaper = ((BitmapDrawable) WallpaperManager.getInstance(this)
                           .getDrawable()).getBitmap();

       }

       private void print(String request) {
              System.out.println(request);
       }

       private void updateTweens() {
              accelData += tweenStep;
       }

       private void prepareToLaunch(ApplicationItem app) {
              appToLaunch = app;
              startingApp = true;
       }

       private void launchApp() {
              startingApp = false;
              if (appToLaunch.name.equals("Adjust Volume")) {
                     // Bring up volume adjustment panel
                     // if (originalVolume == 0) {
                     // AudioManager audioManager = (AudioManager)
                     // getSystemService(Context.AUDIO_SERVICE);
                     // originalVolume =
                     // audioManager.getStreamMaxVolume(audioManager.STREAM_MUSIC);
                     // }
                     // else
                     // originalVolume = 0;
                     volumePanelExpanded = true;
                     volumePanelPosition = (int) ((gameView.headFloats[0] - rotationalOffset) * 500);
                     AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
                     volumePanelKnobPosition = (originalVolume / audioManager
                                  .getStreamMaxVolume(audioManager.STREAM_MUSIC)) * 100;

                     // Ready to launch other app
                     gameView.appStartAnimationPosition = 0;
              } else {
                     AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
                     audioManager.setStreamVolume(AudioManager.STREAM_MUSIC,
                                  originalVolume, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);

                     appToLaunch.launch();
              }
       }

       private void makeImmersive() {
              if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
                     getWindow().getDecorView().setSystemUiVisibility(
                                  View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                                                | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                                                | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                                                | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                                                | View.SYSTEM_UI_FLAG_FULLSCREEN
                                                | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
              }
       }

       public boolean isMyAppLauncherDefault() {
              IntentFilter filter = new IntentFilter(Intent.ACTION_MAIN);
              filter.addCategory(Intent.CATEGORY_HOME);

              List<IntentFilter> filters = new ArrayList<IntentFilter>();
              filters.add(filter);

              // the packageName of your application
              String packageName = getPackageName();
              List<ComponentName> preferredActivities = new ArrayList<ComponentName>();
              final PackageManager packageManager = getPackageManager();

              // You can use name of your package here as third argument
              packageManager.getPreferredActivities(filters, preferredActivities,
                           null);

              for (ComponentName activity : preferredActivities) {
                     if (packageName.equals(activity.getPackageName())) {
                           return true;
                     }
              }
              return false;
       }

       @Override
       public boolean onKeyDown(int keyCode, KeyEvent event) {
              if (keyCode == KeyEvent.KEYCODE_BACK)
                     return true;
              else if ((keyCode == KeyEvent.KEYCODE_VOLUME_DOWN || keyCode == KeyEvent.KEYCODE_VOLUME_UP)
                           && preferences.getBoolean("disable_volume_buttons", false))
                     return true;
              else
                     return super.onKeyDown(keyCode, event);
       }

       @Override
       public boolean onCreateOptionsMenu(Menu menu) {
              // Inflate the menu; this adds items to the action bar if it is present.
              getMenuInflater().inflate(R.menu.game, menu);
              return true;
       }

       @Override
       public boolean onOptionsItemSelected(MenuItem item) {
              // Handle action bar item clicks here. The action bar will
              // automatically handle clicks on the Home/Up button, so long
              // as you specify a parent activity in AndroidManifest.xml.
              int id = item.getItemId();
              return (id == R.id.action_settings || super.onOptionsItemSelected(item));
       }

       protected void onResume() {
              super.onResume();
              mSensorManager.registerListener(this, mAccelerometer,
                           SensorManager.SENSOR_DELAY_NORMAL);
              makeImmersive();
       }

       protected void onPause() {
              super.onPause();
              mSensorManager.unregisterListener(this);
       }

       @Override
       public void onSensorChanged(SensorEvent sensorEvent) {

       }

       @Override
       public void onAccuracyChanged(Sensor sensor, int i) {

       }

       public class MyView extends View {
              private Paint paint = new Paint();
              private int width = 0;
              private int height = 0;
              private Rect cursorPosition = new Rect(width / 2 - 1, height / 2 - 1,
                           width / 2 + 1, height / 2 + 1);
              private int appStartAnimationPosition = 0;
              private Rect freeAllocate = new Rect();

              long timeOfLastFrame = 0;

              public MyView(Context context) {
                     super(context);

                     paint.setStyle(Paint.Style.FILL);
                     width = getWidth() / 2;
                     volumePanelWidth = width - 480;
                     height = getHeight();
                     timeOfLastFrame = System.currentTimeMillis();

                     gameLoop();
              }

              private int selectedApp = -1;
              private long timeSelected = -1;
              private final long selectionTime = 200;

              private void gameLoop() {
                     move();
                     updateTweens();
                     if (width == 0) {
                           width = getWidth() / 2;
                           volumePanelWidth = width - 480;
                           height = getHeight();
                           cursorPosition = new Rect(width / 2 - 1, 0, width / 2 + 1,
                                         height);
                     }

                     if (selectedApp == -1) {
                           for (int i = 0; i < installedApps.size(); i++) {
                                  freeAllocate.set(installedApps.get(i).x,
                                                installedApps.get(i).pos.top,
                                                installedApps.get(i).x
                                                              + installedApps.get(i).pos.right,
                                                installedApps.get(i).pos.top
                                                              + installedApps.get(i).pos.bottom);
                                  if (Rect.intersects(cursorPosition, freeAllocate)) {
                                         selectedApp = i;
                                         timeSelected = 0;
                                  }
                           }
                     } else {
                           timeSelected++;
                           if (timeSelected > selectionTime) {
                                  if (preferences.getBoolean("launch_on_hover", true)) {
                                         if (preferences
                                                       .getBoolean("vibrate_on_selection", true))
                                                mVibrator.vibrate(50);
                                         // installedApps.get(selectedApp).launch();
                                         prepareToLaunch(installedApps.get(selectedApp));
                                  }
                           }
                           freeAllocate.set(
                                         installedApps.get(selectedApp).x,
                                         installedApps.get(selectedApp).pos.top,
                                         installedApps.get(selectedApp).x
                                                       + installedApps.get(selectedApp).pos.right,
                                         installedApps.get(selectedApp).pos.top
                                                       + installedApps.get(selectedApp).pos.bottom);
                           if (!Rect.intersects(cursorPosition, freeAllocate)) {
                                  selectedApp = -1;
                                  timeSelected = -1;
                           }
                     }

                     if (startingApp) {
                           if (appStartAnimationPosition > width / 2
                                         && appStartAnimationPosition > height / 2) {
                                  launchApp();
                           } else {
                                  appStartAnimationPosition += 30;
                           }
                     }

                     if (readyToListen /* && !listening */
                                  && preferences.getBoolean("listen_for_voice", true)) {
                           listening = true;
                           speechRecog.startListening(recognizerIntent);
                     }

                     // cause redraw
                     invalidate();
              }

              public void magnetPull() {
                     if (volumePanelExpanded) {
                           // set volume
                           volumePanelExpanded = false;
                           AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
                           originalVolume = (int) (audioManager
                                         .getStreamMaxVolume(audioManager.STREAM_MUSIC) * (Math
                                         .abs(volumePanelKnobPosition - volumePanelWidth) / (float) volumePanelWidth));
                     } else if (selectedApp != -1) {
                           if (preferences.getBoolean("vibrate_on_selection", true))
                                  mVibrator.vibrate(50);
                           prepareToLaunch(installedApps.get(selectedApp));
                     } else {
                           // reset rotation
                           rotationalOffset = headFloats[0];
                     }
              }

              float headMatrix[] = new float[16];
              float headFloats[] = new float[3];

              private void move() {
                     if (volumePanelExpanded) {
                           // volumePanelKnobPosition = (int) (((headFloats[0] -
                            // rotationalOffset) * 500) / volumePanelPosition) * 100;
                           volumePanelKnobPosition = (int) ((gameView.headFloats[0] - rotationalOffset) * 500)
                                         - volumePanelPosition;
                           volumePanelKnobPosition = (volumePanelKnobPosition < 0) ? 0
                                         : volumePanelKnobPosition;
                           volumePanelKnobPosition = (volumePanelKnobPosition > volumePanelWidth) ? volumePanelWidth
                                         : volumePanelKnobPosition;
                     }
                     for (int i = 0; i < installedApps.size(); i++) {
                           installedApps.get(i).pos.top = (height / 2)
                                         - (installedApps.get(i).pos.bottom / 2);
                           if (rawGyroData == 0.0000f || forceAccelerometer
                                         || headTracker == null) {
                                  installedApps.get(i).x = (int) (installedApps.get(i).pos.left + (accelData * 100))
                                                - iconCenter;
                           } else {
                                  headTracker.getLastHeadView(headMatrix, 0);
                                  headFloats = getEulerFromMat(headMatrix);

                                 
                                  installedApps.get(i).x = (int) (installedApps.get(i).pos.left + ((headFloats[0] - rotationalOffset) * 500))
                                                - iconCenter;
                           }
                     }
              }

              float normalizeRotation(float rot) {
                     if (rot > TAU)
                           rot -= TAU;
                     else if (rot < -TAU)
                           rot += TAU;
                     else
                           return rot;

                     return normalizeRotation(rot);
              }

              float[] getEulerFromMat(float[] rotMatrix) {
                     float x, y, z;

                     float _11, _12, _13, _14;
                     float _21, _22, _23, _24;
                     float _31, _32, _33, _34;
                     float _41, _42, _43, _44;

                     _11 = rotMatrix[0];
                     _12 = rotMatrix[1];
                     _13 = rotMatrix[2];
                     _14 = rotMatrix[3];

                     _21 = rotMatrix[4];
                     _22 = rotMatrix[5];
                     _23 = rotMatrix[6];
                     _24 = rotMatrix[7];

                     _31 = rotMatrix[8];
                     _32 = rotMatrix[9];
                     _33 = rotMatrix[10];
                     _34 = rotMatrix[11];

                     _41 = rotMatrix[12];
                     _42 = rotMatrix[13];
                     _43 = rotMatrix[14];
                     _44 = rotMatrix[15];

                     if (_11 == 1.0f) {
                           x = (float) Math.atan2(_13, _34);
                           y = 0;
                           z = 0;

                     } else if (_11 == -1.0f) {
                           x = (float) Math.atan2(_13, _34);
                           y = 0;
                           z = 0;
                     } else {

                           x = (float) Math.atan2(-_31, _11);
                           y = (float) Math.asin(_21);
                           z = (float) Math.atan2(-_23, _22);
                     }

                     float[] _return = { x, y, z };
                     return _return;
              }

              float[] getMatFromEuler(float[] eulerAngles) {
                     float x = eulerAngles[0], y = eulerAngles[1], z = eulerAngles[2];

                     float _11 = 0, _12 = 0, _13 = 0, _14 = 0;
                     float _21 = 0, _22 = 0, _23 = 0, _24 = 0;
                     float _31 = 0, _32 = 0, _33 = 0, _34 = 0;
                     float _41 = 0, _42 = 0, _43 = 0, _44 = 0;

                     float transMatrix[] = new float[16];

                     float X[][] = new float[3][3];
                     float Y[][] = new float[3][3];
                     float Z[][] = new float[3][3];

                     X[2][2] = (float) Math.cos(x);
                     X[2][3] = (float) -Math.sin(x);
                     X[3][2] = (float) Math.sin(x);
                     X[3][3] = (float) Math.cos(x);

                     Y[1][1] = (float) Math.cos(y);
                     Y[1][3] = (float) Math.sin(y);
                     Y[3][1] = (float) -Math.sin(y);
                     Y[3][3] = (float) Math.cos(y);

                     Z[1][1] = (float) Math.cos(z);
                     Z[1][2] = (float) -Math.sin(z);
                     Z[2][1] = (float) Math.sin(z);
                     Z[2][2] = (float) Math.cos(z);

                     float[][] _rotMatrix = matrixMultiply(matrixMultiply(Z, Y), X);
                     // int k = 0;
                     // for (int i = 0; i < _rotMatrix.length; i++) {
                     // for (int j = 0; j < _rotMatrix[i].length; j++) {
                     // transMatrix[k] = _rotMatrix[i][j];
                     // k++;
                     // }
                     // transMatrix[k] = 0;
                     // k++;
                     // }
                     // transMatrix[12] = 0;
                     // transMatrix[13] = 0;
                     // transMatrix[14] = 0;
                     // transMatrix[15] = 1;

                     transMatrix[0] = _rotMatrix[0][0];
                     transMatrix[1] = _rotMatrix[0][1];
                     transMatrix[2] = _rotMatrix[0][2];
                     transMatrix[3] = 0;

                     transMatrix[4] = _rotMatrix[1][0];
                     transMatrix[5] = _rotMatrix[1][1];
                     transMatrix[6] = _rotMatrix[1][2];
                     transMatrix[7] = 0;

                     transMatrix[8] = _rotMatrix[2][0];
                     transMatrix[9] = _rotMatrix[2][1];
                     transMatrix[10] = _rotMatrix[2][2];
                     transMatrix[11] = 0;

                     transMatrix[12] = 0;
                     transMatrix[13] = 0;
                     transMatrix[14] = 0;
                     transMatrix[15] = 1;

                     return transMatrix;
              }

              public float[][] matrixMultiply(float[][] A, float[][] B) {

                     int aRows = A.length;
                     int aColumns = A[0].length;
                     int bRows = B.length;
                     int bColumns = B[0].length;

                     if (aColumns != bRows) {
                           throw new IllegalArgumentException("A:Rows: " + aColumns
                                         + " did not match B:Columns " + bRows + ".");
                     }

                     float[][] C = new float[aRows][bColumns];
                     for (int i = 0; i < 2; i++) {
                           for (int j = 0; j < 2; j++) {
                                  C[i][j] = 0.00000f;
                           }
                     }

                     for (int i = 0; i < aRows; i++) { // aRow
                           for (int j = 0; j < bColumns; j++) { // bColumn
                                  for (int k = 0; k < aColumns; k++) { // aColumn
                                         C[i][j] += A[i][k] * B[k][j];
                                  }
                           }
                     }

                     return C;
              }

              Display dis = ((WindowManager) getApplicationContext()
                           .getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
              Bitmap lEyeBit = Bitmap.createBitmap(dis.getWidth() / 2,
                           dis.getHeight(), Bitmap.Config.ARGB_8888);
              Bitmap rEyeBit = Bitmap.createBitmap(dis.getWidth() / 2,
                           dis.getHeight(), Bitmap.Config.ARGB_8888);
              Canvas lEye = new Canvas(lEyeBit);
              Canvas rEye = new Canvas(rEyeBit);

              @Override
              protected void onDraw(Canvas canvas) {
                     super.onDraw(canvas);
                     int radius;
                     radius = 100;

                     paint.setColor(Color.BLACK);
                     canvas.drawPaint(paint);

                     // draw left eye
                     if (drawWallpaper) {
                           freeAllocate.set(0, 0, width, height);
                           lEye.drawBitmap(wallpaper, null, freeAllocate, paint);
                     } else {
                           paint.setColor(Color.BLACK);
                           lEye.drawPaint(paint);
                     }

                     paint.setAntiAlias(true);

                     paint.setColor(Color.parseColor("#CD5C5C"));
                     if (preferences.getBoolean("launch_on_hover", true))
                           lEye.drawCircle(width / 2, height / 2, radius
                                         * ((float) timeSelected / selectionTime), paint);
                     paint.setStyle(Paint.Style.STROKE);
                     paint.setStrokeWidth(3);
                     lEye.drawCircle(width / 2, height / 2, radius, paint);
                     paint.setStyle(Paint.Style.FILL);
                     if (startingApp) {
                           lEye.drawCircle(width / 2, height / 2,
                                         appStartAnimationPosition, paint);
                     }
                     for (int i = 0; i < installedApps.size(); i++) {
                           if (installedApps.get(i).x < width
                                         && installedApps.get(i).x
                                                       + installedApps.get(i).pos.right > 0) {
                                  if (i != selectedApp || volumePanelExpanded) {
                                         freeAllocate.set(
                                                       installedApps.get(i).x - 1,
                                                       installedApps.get(i).pos.top,
                                                       installedApps.get(i).x - 1
                                                                     + installedApps.get(i).pos.right,
                                                       installedApps.get(i).pos.top
                                                                     + installedApps.get(i).pos.bottom);
                                         lEye.drawBitmap(installedApps.get(i).iconGry, null,
                                                       freeAllocate, paint);
                                  }
                           }
                     }
                     if (volumePanelExpanded) {
                           paint.setColor(Color.argb(200, 100, 100, 100));
                           if (100 - (int) ((headFloats[0] - rotationalOffset) * 500) > width / 2 - 25) // overscroll
                                                                                                                                                                     // to
                                                                                                                                                                     // the
                                                                                                                                                                     // right
                                  freeAllocate.set(width / 2 - width - 200 - 25,
                                                height / 2 - 25, width / 2 + 25, height / 2 + 25);
                           else if (100 + (int) ((headFloats[0] - rotationalOffset) * 500) > width / 2 - 25) // overscroll
                                                                                                                                                                            // to
                                                                                                                                                                            // the
                                                                                                                                                                            // left
                                  freeAllocate.set(width / 2 - 25, height / 2 - 25, width,
                                                height / 2 + 25);
                           else
                                  freeAllocate
                                                .set(100 + (int) ((headFloats[0] - rotationalOffset) * 500),
                                                              height / 2 - 25,
                                                              width
                                                                           - 100
                                                                           + (int) ((headFloats[0] - rotationalOffset) * 500),
                                                              height / 2 + 25);
                           lEye.drawRoundRect(new RectF(freeAllocate), 50f, 50f, paint);

                           paint.setColor(Color.rgb(0, 100, 255));
                           if (120 + (int) ((headFloats[0] - rotationalOffset) * 500) > width / 2 - 5)
                                  freeAllocate.set(width / 2 - 5, height / 2 - 5, width,
                                                height / 2 + 5);
                           else if (width - 120
                                         + (int) ((headFloats[0] - rotationalOffset) * 500) < width / 2 + 5)
                                  freeAllocate.set(width / 2 - width - 240, height / 2 - 5,
                                                width / 2 - 5, height / 2 + 5);
                           else
                                  freeAllocate
                                                .set(120 + (int) ((headFloats[0] - rotationalOffset) * 500),
                                                              height / 2 - 5,
                                                              width
                                                                           - 120
                                                                           + (int) ((headFloats[0] - rotationalOffset) * 500),
                                                              height / 2 + 5);
                           lEye.drawRect(freeAllocate, paint);

                           paint.setColor(Color.rgb(0, 50, 255));
                           lEye.drawCircle(width / 2, height / 2, 14, paint);
                     }
                     if (!volumePanelExpanded && selectedApp != -1) {
                           freeAllocate
                                         .set(installedApps.get(selectedApp).x + 1
                                                       + installedApps.get(selectedApp).z - 14,
                                                       installedApps.get(selectedApp).pos.top - 14,
                                                       installedApps.get(selectedApp).x
                                                                     + 1
                                                                     + installedApps.get(selectedApp).z
                                                                     + installedApps.get(selectedApp).pos.right
                                                                     + 28,
                                                       installedApps.get(selectedApp).pos.top
                                                                     + installedApps.get(selectedApp).pos.bottom
                                                                     + 28);
                           lEye.drawBitmap(installedApps.get(selectedApp).icon, null,
                                         freeAllocate, paint);
                           paint.setTextAlign(Paint.Align.CENTER);
                           paint.setColor(Color.WHITE);
                           paint.setTextSize(20);
                           lEye.drawText(
                                         installedApps.get(selectedApp).name,
                                         installedApps.get(selectedApp).x
                                                       + (installedApps.get(selectedApp).pos.right / 2),
                                         installedApps.get(selectedApp).pos.top + 120, paint);
                     }

                     // draw right eye
                     if (drawWallpaper) {
                           freeAllocate.set(0, 0, width, height);
                           rEye.drawBitmap(wallpaper, null, freeAllocate, paint);
                     } else {
                           paint.setColor(Color.BLACK);
                           rEye.drawPaint(paint);
                     }
                     paint.setColor(Color.parseColor("#CD5C5C"));
                     if (preferences.getBoolean("launch_on_hover", true))
                           rEye.drawCircle(width / 2, height / 2, radius
                                         * ((float) timeSelected / selectionTime), paint);
                     paint.setStyle(Paint.Style.STROKE);
                     paint.setStrokeWidth(3);
                     rEye.drawCircle(width / 2, height / 2, radius, paint);
                     paint.setStyle(Paint.Style.FILL);
                     if (startingApp) {
                           rEye.drawCircle(width / 2, height / 2,
                                         appStartAnimationPosition, paint);
                     }
                     for (int i = 0; i < installedApps.size(); i++) {
                           if (installedApps.get(i).x < width
                                         && installedApps.get(i).x
                                                       + installedApps.get(i).pos.right > 0) {
                                  if (i != selectedApp || volumePanelExpanded) {
                                         freeAllocate.set(
                                                       installedApps.get(i).x - 1,
                                                       installedApps.get(i).pos.top,
                                                       installedApps.get(i).x - 1
                                                                     + installedApps.get(i).pos.right,
                                                       installedApps.get(i).pos.top
                                                                     + installedApps.get(i).pos.bottom);
                                         rEye.drawBitmap(installedApps.get(i).iconGry, null,
                                                       freeAllocate, paint);
                                  }
                           }
                     }
                     if (volumePanelExpanded) {
                           paint.setColor(Color.argb(200, 100, 100, 100));
                           if (100 - (int) ((headFloats[0] - rotationalOffset) * 500) > width / 2 - 25) // overscroll
                                                                                                                                                                     // to
                                                                                                                                                                     // the
                                                                                                                                                                     // right
                                  freeAllocate.set(width / 2 - width - 200 - 25,
                                                height / 2 - 25, width / 2 + 25, height / 2 + 25);
                           else if (100 + (int) ((headFloats[0] - rotationalOffset) * 500) > width / 2 - 25) // overscroll
                                                                                                                                                                            // to
                                                                                                                                                                            // the
                                                                                                                                                                            // left
                                  freeAllocate.set(width / 2 - 25, height / 2 - 25, width,
                                                height / 2 + 25);
                           else
                                  freeAllocate
                                                .set(100 + (int) ((headFloats[0] - rotationalOffset) * 500),
                                                              height / 2 - 25,
                                                              width
                                                                           - 100
                                                                           + (int) ((headFloats[0] - rotationalOffset) * 500),
                                                              height / 2 + 25);
                           rEye.drawRoundRect(new RectF(freeAllocate), 50f, 50f, paint);

                           paint.setColor(Color.rgb(0, 100, 255));
                           if (120 + (int) ((headFloats[0] - rotationalOffset) * 500) > width / 2 - 5)
                                  freeAllocate.set(width / 2 - 5, height / 2 - 5, width,
                                                height / 2 + 5);
                           else if (width - 120
                                         + (int) ((headFloats[0] - rotationalOffset) * 500) < width / 2 + 5)
                                  freeAllocate.set(width / 2 - width - 240, height / 2 - 5,
                                                width / 2 - 5, height / 2 + 5);
                           else
                                  freeAllocate
                                                .set(120 + (int) ((headFloats[0] - rotationalOffset) * 500),
                                                              height / 2 - 5,
                                                              width
                                                                           - 120
                                                                           + (int) ((headFloats[0] - rotationalOffset) * 500),
                                                              height / 2 + 5);
                           rEye.drawRect(freeAllocate, paint);

                           paint.setColor(Color.rgb(0, 50, 255));
                           rEye.drawCircle(width / 2, height / 2, 14, paint);
                     }
                     if (!volumePanelExpanded && selectedApp != -1) {
                           freeAllocate
                                         .set(installedApps.get(selectedApp).x - 1
                                                       - installedApps.get(selectedApp).z - 14 - 4,
                                                       installedApps.get(selectedApp).pos.top - 14,
                                                       installedApps.get(selectedApp).x
                                                                     - 1
                                                                     - installedApps.get(selectedApp).z
                                                                     + installedApps.get(selectedApp).pos.right
                                                                     + 28,
                                                       installedApps.get(selectedApp).pos.top
                                                                     + installedApps.get(selectedApp).pos.bottom
                                                                     + 28);
                           rEye.drawBitmap(installedApps.get(selectedApp).icon, null,
                                         freeAllocate, paint);
                           paint.setTextAlign(Paint.Align.CENTER);
                           paint.setColor(Color.WHITE);
                           paint.setTextSize(20);
                           rEye.drawText(
                                         installedApps.get(selectedApp).name,
                                         installedApps.get(selectedApp).x
                                                       + (installedApps.get(selectedApp).pos.right / 2),
                                         installedApps.get(selectedApp).pos.top + 120, paint);
                     }

                     // render eyes to screen
                     float pupilaryDist = ((100 - preferences.getInt(
                                  "interpupilary_distance", 50)) / 50) * 0.0635f; // this
                       should be the distance between the user's pupils in meters -- 0.0635m is average
                     int shiftImage = (int) (pupilaryDist * 1023.6220472); // for the
                          // OPO, this needs to equal 65
                     // print("An interpupilary distance of " + pupilaryDist +
                     // " is equal to " + shiftImage * 2 + " pixels.");
                     canvas.drawBitmap(lEyeBit, new Rect(0, 0, width, height), new Rect(
                                  shiftImage, 0, width + shiftImage, height), paint);
                     canvas.drawBitmap(rEyeBit, new Rect(shiftImage, 0, width, height),
                                  new Rect(width, 0, getWidth() - shiftImage, height), paint);

                     // draw divider
                     paint.setColor(Color.GRAY);
                     canvas.drawRect(width - 5, 0, width + 5, height, paint);

                     if (appStartAnimationPosition > 0) {
                           paint.setColor(Color.BLACK);
                           paint.setAlpha((int) ((appStartAnimationPosition / (height / 2f)) * 255f));
                           canvas.drawPaint(paint);
                     }

                     gameLoop();
              }

              @Override
              public boolean onTouchEvent(MotionEvent motionEvent) {
                     magnetPull();
                     return false;
              }
       }
}