Cardboard App Launcher Example

03:00 4 Comments


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;
              }
       }
}


Delhi, INDIA

4 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. i want to create same menu in unity3d with google cardboard can you help me on this?

    ReplyDelete
  3. Hi Thanks for the code.How can I achieve to rotate de icons and text?

    ReplyDelete
  4. en mexico http://www.visorcardboardmexico.com.mx/

    ReplyDelete