├── .gitignore
├── LICENSE
├── README.md
├── build.gradle
├── gradle.properties
├── gradle
├── LICENSE
├── README
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── library
├── .gitignore
├── build.gradle
├── libs
│ └── libprotobuf-java-2.3-nano.jar
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── java
│ └── com
│ └── google
│ └── vrtoolkit
│ └── cardboard
│ ├── CardboardActivity.java
│ ├── CardboardDeviceParams.java
│ ├── CardboardView.java
│ ├── ConfigUtils.java
│ ├── Constants.java
│ ├── Distortion.java
│ ├── DistortionRenderer.java
│ ├── Eye.java
│ ├── FieldOfView.java
│ ├── GLStateBackup.java
│ ├── HeadMountedDisplay.java
│ ├── HeadMountedDisplayManager.java
│ ├── HeadTransform.java
│ ├── PhoneParams.java
│ ├── ScreenParams.java
│ ├── UiLayer.java
│ ├── UiUtils.java
│ ├── Viewport.java
│ ├── proto
│ ├── CardboardDevice.java
│ └── Phone.java
│ └── sensors
│ ├── Clock.java
│ ├── DeviceSensorLooper.java
│ ├── HeadTracker.java
│ ├── MagnetSensor.java
│ ├── NfcSensor.java
│ ├── SensorEventProvider.java
│ ├── SystemClock.java
│ └── internal
│ ├── GyroBiasEstimator.java
│ ├── Matrix3x3d.java
│ ├── OrientationEKF.java
│ ├── So3Util.java
│ └── Vector3d.java
├── sample
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── google
│ │ └── vrtoolkit
│ │ └── cardboard
│ │ └── samples
│ │ └── treasurehunt
│ │ └── ApplicationTest.java
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── google
│ │ └── vrtoolkit
│ │ └── cardboard
│ │ └── samples
│ │ └── treasurehunt
│ │ ├── CardboardOverlayView.java
│ │ ├── MainActivity.java
│ │ └── WorldLayoutData.java
│ └── res
│ ├── drawable-hdpi
│ └── ic_launcher.png
│ ├── drawable-mdpi
│ └── ic_launcher.png
│ ├── drawable-xhdpi
│ └── ic_launcher.png
│ ├── drawable-xxhdpi
│ └── ic_launcher.png
│ ├── layout
│ └── common_ui.xml
│ ├── mipmap-hdpi
│ └── ic_launcher.png
│ ├── mipmap-mdpi
│ └── ic_launcher.png
│ ├── mipmap-xhdpi
│ └── ic_launcher.png
│ ├── mipmap-xxhdpi
│ └── ic_launcher.png
│ ├── raw
│ ├── grid_fragment.shader
│ ├── light_vertex.shader
│ └── passthrough_fragment.shader
│ └── values
│ └── strings.xml
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | # built application files
2 | *.apk
3 | *.ap_
4 |
5 | # files for the dex VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # generated files
12 | bin/
13 | gen/
14 |
15 | # Local configuration file (sdk path, etc)
16 | local.properties
17 |
18 | # Eclipse project files
19 | .classpath
20 | .project
21 |
22 | # Android Studio
23 | .idea/
24 | .gradle
25 | /*/local.properties
26 | /*/out
27 | build/*
28 | /*/*/build
29 | /*/*/production
30 | *.iml
31 | *.iws
32 | *.ipr
33 | *~
34 | *.swp
35 |
36 | .DS_Store
37 |
38 | .history
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2014, Google Inc.
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 |
6 | Unless required by applicable law or agreed to in writing, software
7 | distributed under the License is distributed on an "AS IS" BASIS,
8 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 | See the License for the specific language governing permissions and
10 | limitations under the License.
11 |
12 |
13 | Apache License
14 | Version 2.0, January 2004
15 | http://www.apache.org/licenses/
16 |
17 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
18 |
19 | 1. Definitions.
20 |
21 | "License" shall mean the terms and conditions for use, reproduction,
22 | and distribution as defined by Sections 1 through 9 of this document.
23 |
24 | "Licensor" shall mean the copyright owner or entity authorized by
25 | the copyright owner that is granting the License.
26 |
27 | "Legal Entity" shall mean the union of the acting entity and all
28 | other entities that control, are controlled by, or are under common
29 | control with that entity. For the purposes of this definition,
30 | "control" means (i) the power, direct or indirect, to cause the
31 | direction or management of such entity, whether by contract or
32 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
33 | outstanding shares, or (iii) beneficial ownership of such entity.
34 |
35 | "You" (or "Your") shall mean an individual or Legal Entity
36 | exercising permissions granted by this License.
37 |
38 | "Source" form shall mean the preferred form for making modifications,
39 | including but not limited to software source code, documentation
40 | source, and configuration files.
41 |
42 | "Object" form shall mean any form resulting from mechanical
43 | transformation or translation of a Source form, including but
44 | not limited to compiled object code, generated documentation,
45 | and conversions to other media types.
46 |
47 | "Work" shall mean the work of authorship, whether in Source or
48 | Object form, made available under the License, as indicated by a
49 | copyright notice that is included in or attached to the work
50 | (an example is provided in the Appendix below).
51 |
52 | "Derivative Works" shall mean any work, whether in Source or Object
53 | form, that is based on (or derived from) the Work and for which the
54 | editorial revisions, annotations, elaborations, or other modifications
55 | represent, as a whole, an original work of authorship. For the purposes
56 | of this License, Derivative Works shall not include works that remain
57 | separable from, or merely link (or bind by name) to the interfaces of,
58 | the Work and Derivative Works thereof.
59 |
60 | "Contribution" shall mean any work of authorship, including
61 | the original version of the Work and any modifications or additions
62 | to that Work or Derivative Works thereof, that is intentionally
63 | submitted to Licensor for inclusion in the Work by the copyright owner
64 | or by an individual or Legal Entity authorized to submit on behalf of
65 | the copyright owner. For the purposes of this definition, "submitted"
66 | means any form of electronic, verbal, or written communication sent
67 | to the Licensor or its representatives, including but not limited to
68 | communication on electronic mailing lists, source code control systems,
69 | and issue tracking systems that are managed by, or on behalf of, the
70 | Licensor for the purpose of discussing and improving the Work, but
71 | excluding communication that is conspicuously marked or otherwise
72 | designated in writing by the copyright owner as "Not a Contribution."
73 |
74 | "Contributor" shall mean Licensor and any individual or Legal Entity
75 | on behalf of whom a Contribution has been received by Licensor and
76 | subsequently incorporated within the Work.
77 |
78 | 2. Grant of Copyright License. Subject to the terms and conditions of
79 | this License, each Contributor hereby grants to You a perpetual,
80 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
81 | copyright license to reproduce, prepare Derivative Works of,
82 | publicly display, publicly perform, sublicense, and distribute the
83 | Work and such Derivative Works in Source or Object form.
84 |
85 | 3. Grant of Patent License. Subject to the terms and conditions of
86 | this License, each Contributor hereby grants to You a perpetual,
87 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
88 | (except as stated in this section) patent license to make, have made,
89 | use, offer to sell, sell, import, and otherwise transfer the Work,
90 | where such license applies only to those patent claims licensable
91 | by such Contributor that are necessarily infringed by their
92 | Contribution(s) alone or by combination of their Contribution(s)
93 | with the Work to which such Contribution(s) was submitted. If You
94 | institute patent litigation against any entity (including a
95 | cross-claim or counterclaim in a lawsuit) alleging that the Work
96 | or a Contribution incorporated within the Work constitutes direct
97 | or contributory patent infringement, then any patent licenses
98 | granted to You under this License for that Work shall terminate
99 | as of the date such litigation is filed.
100 |
101 | 4. Redistribution. You may reproduce and distribute copies of the
102 | Work or Derivative Works thereof in any medium, with or without
103 | modifications, and in Source or Object form, provided that You
104 | meet the following conditions:
105 |
106 | (a) You must give any other recipients of the Work or
107 | Derivative Works a copy of this License; and
108 |
109 | (b) You must cause any modified files to carry prominent notices
110 | stating that You changed the files; and
111 |
112 | (c) You must retain, in the Source form of any Derivative Works
113 | that You distribute, all copyright, patent, trademark, and
114 | attribution notices from the Source form of the Work,
115 | excluding those notices that do not pertain to any part of
116 | the Derivative Works; and
117 |
118 | (d) If the Work includes a "NOTICE" text file as part of its
119 | distribution, then any Derivative Works that You distribute must
120 | include a readable copy of the attribution notices contained
121 | within such NOTICE file, excluding those notices that do not
122 | pertain to any part of the Derivative Works, in at least one
123 | of the following places: within a NOTICE text file distributed
124 | as part of the Derivative Works; within the Source form or
125 | documentation, if provided along with the Derivative Works; or,
126 | within a display generated by the Derivative Works, if and
127 | wherever such third-party notices normally appear. The contents
128 | of the NOTICE file are for informational purposes only and
129 | do not modify the License. You may add Your own attribution
130 | notices within Derivative Works that You distribute, alongside
131 | or as an addendum to the NOTICE text from the Work, provided
132 | that such additional attribution notices cannot be construed
133 | as modifying the License.
134 |
135 | You may add Your own copyright statement to Your modifications and
136 | may provide additional or different license terms and conditions
137 | for use, reproduction, or distribution of Your modifications, or
138 | for any such Derivative Works as a whole, provided Your use,
139 | reproduction, and distribution of the Work otherwise complies with
140 | the conditions stated in this License.
141 |
142 | 5. Submission of Contributions. Unless You explicitly state otherwise,
143 | any Contribution intentionally submitted for inclusion in the Work
144 | by You to the Licensor shall be under the terms and conditions of
145 | this License, without any additional terms or conditions.
146 | Notwithstanding the above, nothing herein shall supersede or modify
147 | the terms of any separate license agreement you may have executed
148 | with Licensor regarding such Contributions.
149 |
150 | 6. Trademarks. This License does not grant permission to use the trade
151 | names, trademarks, service marks, or product names of the Licensor,
152 | except as required for reasonable and customary use in describing the
153 | origin of the Work and reproducing the content of the NOTICE file.
154 |
155 | 7. Disclaimer of Warranty. Unless required by applicable law or
156 | agreed to in writing, Licensor provides the Work (and each
157 | Contributor provides its Contributions) on an "AS IS" BASIS,
158 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
159 | implied, including, without limitation, any warranties or conditions
160 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
161 | PARTICULAR PURPOSE. You are solely responsible for determining the
162 | appropriateness of using or redistributing the Work and assume any
163 | risks associated with Your exercise of permissions under this License.
164 |
165 | 8. Limitation of Liability. In no event and under no legal theory,
166 | whether in tort (including negligence), contract, or otherwise,
167 | unless required by applicable law (such as deliberate and grossly
168 | negligent acts) or agreed to in writing, shall any Contributor be
169 | liable to You for damages, including any direct, indirect, special,
170 | incidental, or consequential damages of any character arising as a
171 | result of this License or out of the use or inability to use the
172 | Work (including but not limited to damages for loss of goodwill,
173 | work stoppage, computer failure or malfunction, or any and all
174 | other commercial damages or losses), even if such Contributor
175 | has been advised of the possibility of such damages.
176 |
177 | 9. Accepting Warranty or Additional Liability. While redistributing
178 | the Work or Derivative Works thereof, You may choose to offer,
179 | and charge a fee for, acceptance of support, warranty, indemnity,
180 | or other liability obligations and/or rights consistent with this
181 | License. However, in accepting such obligations, You may act only
182 | on Your own behalf and on Your sole responsibility, not on behalf
183 | of any other Contributor, and only if You agree to indemnify,
184 | defend, and hold each Contributor harmless for any liability
185 | incurred by, or claims asserted against, such Contributor by reason
186 | of your accepting any such warranty or additional liability.
187 |
188 | END OF TERMS AND CONDITIONS
189 |
190 |
191 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Cardboard Java
2 | =====================
3 | Copyright (c) 2014 Google Inc. All rights reserved.
4 |
5 | Decompiled CardboardSDK 0.5.1.
6 |
7 | The *TreasureHunt* sample project, running fully from source. It compiles and runs on Android Studio 1.0.2. The Cardboard.jar package has been replaced by the decompiled sources. Decompiled using [Luyten](https://github.com/deathmarine/Luyten).
8 |
9 | Inspiration from [raasun's cardboard](https://github.com/raasun/cardboard) (decompilation of an older version of CardboardSDK). According to *raasun*, Google should eventually release the official CardboardSDK source.
10 |
11 | [https://developers.google.com/cardboard/android/get-started](https://developers.google.com/cardboard/android/get-started)
12 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | mavenCentral()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:1.0.0'
9 | }
10 | }
11 |
12 | allprojects {
13 | repositories {
14 | mavenCentral()
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Settings specified in this file will override any Gradle settings
5 | # configured through the IDE.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/gradle/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2007-2011 the original author or authors
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
14 |
--------------------------------------------------------------------------------
/gradle/README:
--------------------------------------------------------------------------------
1 | Retrieved from www.gradle.org/license on June 18, 2014 at 3pm.
2 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsanchezsaez/cardboard-java/df049c9024d275189893330eeb6ad6cf5b32275d/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Apr 10 15:27:10 PDT 2013
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/library/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/library/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 21
5 | buildToolsVersion '21.1.2'
6 |
7 | defaultConfig {
8 | minSdkVersion 16
9 | targetSdkVersion 21
10 | versionCode 1
11 | versionName "1.0"
12 | }
13 |
14 | compileOptions {
15 | sourceCompatibility JavaVersion.VERSION_1_7
16 | targetCompatibility JavaVersion.VERSION_1_7
17 | }
18 |
19 | lintOptions {
20 | abortOnError false
21 | }
22 |
23 | buildTypes {
24 | release {
25 | minifyEnabled false
26 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
27 | }
28 | }
29 | }
30 |
31 | dependencies {
32 | compile fileTree(dir: 'libs', include: ['*.jar'])
33 | }
34 |
--------------------------------------------------------------------------------
/library/libs/libprotobuf-java-2.3-nano.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsanchezsaez/cardboard-java/df049c9024d275189893330eeb6ad6cf5b32275d/library/libs/libprotobuf-java-2.3-nano.jar
--------------------------------------------------------------------------------
/library/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add any project specific keep options here:
2 |
3 | # If your project uses WebView with JS, uncomment the following
4 | # and specify the fully qualified class name to the JavaScript interface
5 | # class:
6 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
7 | # public *;
8 | #}
9 |
--------------------------------------------------------------------------------
/library/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/library/src/main/java/com/google/vrtoolkit/cardboard/CardboardActivity.java:
--------------------------------------------------------------------------------
1 | package com.google.vrtoolkit.cardboard;
2 |
3 | import com.google.vrtoolkit.cardboard.sensors.MagnetSensor;
4 | import com.google.vrtoolkit.cardboard.sensors.NfcSensor;
5 |
6 | import android.app.Activity;
7 | import android.nfc.NdefMessage;
8 | import android.os.Build;
9 | import android.os.Bundle;
10 | import android.os.Handler;
11 | import android.view.KeyEvent;
12 | import android.view.View;
13 | import android.view.ViewGroup;
14 | import android.view.Window;
15 | import android.view.WindowManager;
16 |
17 | public class CardboardActivity extends Activity {
18 |
19 | private static final long NAVIGATION_BAR_TIMEOUT_MS = 2000L;
20 |
21 | private CardboardView mCardboardView;
22 | private MagnetSensor mMagnetSensor;
23 | private NfcSensor mNfcSensor;
24 | private SensorListener sensorListener;
25 | private int mVolumeKeysMode;
26 |
27 | public CardboardActivity() {
28 | super();
29 | sensorListener = new SensorListener();
30 | }
31 |
32 | public void setCardboardView(final CardboardView cardboardView) {
33 | mCardboardView = cardboardView;
34 | if (cardboardView == null) {
35 | return;
36 | }
37 | final NdefMessage tagContents = mNfcSensor.getTagContents();
38 | if (tagContents != null) {
39 | updateCardboardDeviceParams(CardboardDeviceParams.createFromNfcContents(tagContents));
40 | }
41 | }
42 |
43 | public CardboardView getCardboardView() {
44 | return mCardboardView;
45 | }
46 |
47 | public NfcSensor getNfcSensor() {
48 | return mNfcSensor;
49 | }
50 |
51 | public void setVolumeKeysMode(final int mode) {
52 | mVolumeKeysMode = mode;
53 | }
54 |
55 | public int getVolumeKeysMode() {
56 | return mVolumeKeysMode;
57 | }
58 |
59 | public boolean areVolumeKeysDisabled() {
60 | switch (mVolumeKeysMode) {
61 | case VolumeKeys.NOT_DISABLED: {
62 | return false;
63 | }
64 | case VolumeKeys.DISABLED_WHILE_IN_CARDBOARD: {
65 | return this.mNfcSensor.isDeviceInCardboard();
66 | }
67 | case VolumeKeys.DISABLED: {
68 | return true;
69 | }
70 | default: {
71 | throw new IllegalStateException(new StringBuilder()
72 | .append("Invalid volume keys mode ")
73 | .append(mVolumeKeysMode).toString()
74 | );
75 | }
76 | }
77 | }
78 |
79 | public void onInsertedIntoCardboard(final CardboardDeviceParams cardboardDeviceParams) {
80 | this.updateCardboardDeviceParams(cardboardDeviceParams);
81 | }
82 |
83 | public void onRemovedFromCardboard() {
84 | }
85 |
86 | public void onCardboardTrigger() {
87 | }
88 |
89 | protected void updateCardboardDeviceParams(final CardboardDeviceParams newParams) {
90 | if (mCardboardView != null) {
91 | mCardboardView.updateCardboardDeviceParams(newParams);
92 | }
93 | }
94 |
95 | @Override
96 | protected void onCreate(final Bundle savedInstanceState) {
97 | super.onCreate(savedInstanceState);
98 |
99 | requestWindowFeature(Window.FEATURE_NO_TITLE);
100 | getWindow().addFlags(WindowManager.LayoutParams.ALPHA_CHANGED);
101 |
102 | mMagnetSensor = new MagnetSensor(this);
103 | mMagnetSensor.setOnCardboardTriggerListener(sensorListener);
104 | mNfcSensor = NfcSensor.getInstance(this);
105 | mNfcSensor.addOnCardboardNfcListener(sensorListener);
106 |
107 | mNfcSensor.onNfcIntent(this.getIntent());
108 | setVolumeKeysMode(VolumeKeys.DISABLED_WHILE_IN_CARDBOARD);
109 |
110 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
111 | final Handler handler = new Handler();
112 | getWindow().getDecorView().setOnSystemUiVisibilityChangeListener(
113 | new View.OnSystemUiVisibilityChangeListener() {
114 | @Override
115 | public void onSystemUiVisibilityChange(final int visibility) {
116 | if ((visibility & 0x2) == 0x0) {
117 | handler.postDelayed(new Runnable() {
118 | @Override
119 | public void run() {
120 | CardboardActivity.this.setFullscreenMode();
121 | }
122 | }, NAVIGATION_BAR_TIMEOUT_MS);
123 | }
124 | }
125 | });
126 | }
127 | }
128 |
129 | @Override
130 | protected void onResume() {
131 | super.onResume();
132 | if (mCardboardView != null) {
133 | mCardboardView.onResume();
134 | }
135 | mMagnetSensor.start();
136 | mNfcSensor.onResume(this);
137 | }
138 |
139 | @Override
140 | protected void onPause() {
141 | super.onPause();
142 | if (mCardboardView != null) {
143 | mCardboardView.onPause();
144 | }
145 | mMagnetSensor.stop();
146 | mNfcSensor.onPause(this);
147 | }
148 |
149 | @Override
150 | protected void onDestroy() {
151 | mNfcSensor.removeOnCardboardNfcListener(sensorListener);
152 | super.onDestroy();
153 | }
154 |
155 | @Override
156 | public void setContentView(final View view) {
157 | if (view instanceof CardboardView) {
158 | setCardboardView((CardboardView) view);
159 | }
160 | super.setContentView(view);
161 | }
162 |
163 | @Override
164 | public void setContentView(final View view, final ViewGroup.LayoutParams params) {
165 | if (view instanceof CardboardView) {
166 | setCardboardView((CardboardView) view);
167 | }
168 | super.setContentView(view, params);
169 | }
170 |
171 | @Override
172 | public boolean onKeyDown(final int keyCode, final KeyEvent event) {
173 | return ((keyCode == KeyEvent.KEYCODE_VOLUME_UP || keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)
174 | && areVolumeKeysDisabled()) || super.onKeyDown(keyCode, event);
175 | }
176 |
177 | @Override
178 | public boolean onKeyUp(final int keyCode, final KeyEvent event) {
179 | return ((keyCode == KeyEvent.KEYCODE_VOLUME_UP || keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)
180 | && areVolumeKeysDisabled()) || super.onKeyUp(keyCode, event);
181 | }
182 |
183 | @Override
184 | public void onWindowFocusChanged(final boolean hasFocus) {
185 | super.onWindowFocusChanged(hasFocus);
186 | if (hasFocus) {
187 | setFullscreenMode();
188 | }
189 | }
190 |
191 | private void setFullscreenMode() {
192 | getWindow().getDecorView().setSystemUiVisibility(5894);
193 | }
194 |
195 | public abstract static class VolumeKeys {
196 | public static final int NOT_DISABLED = 0;
197 | public static final int DISABLED = 1;
198 | public static final int DISABLED_WHILE_IN_CARDBOARD = 2;
199 | }
200 |
201 | private class SensorListener
202 | implements MagnetSensor.OnCardboardTriggerListener, NfcSensor.OnCardboardNfcListener{
203 | @Override
204 | public void onInsertedIntoCardboard(final CardboardDeviceParams deviceParams) {
205 | CardboardActivity.this.onInsertedIntoCardboard(deviceParams);
206 | }
207 |
208 | @Override
209 | public void onRemovedFromCardboard() {
210 | CardboardActivity.this.onRemovedFromCardboard();
211 | }
212 |
213 | @Override
214 | public void onCardboardTrigger() {
215 | CardboardActivity.this.onCardboardTrigger();
216 | }
217 | }
218 | }
219 |
--------------------------------------------------------------------------------
/library/src/main/java/com/google/vrtoolkit/cardboard/CardboardDeviceParams.java:
--------------------------------------------------------------------------------
1 | package com.google.vrtoolkit.cardboard;
2 |
3 | import android.net.*;
4 | import com.google.vrtoolkit.cardboard.proto.*;
5 | import android.util.*;
6 | import java.nio.*;
7 | import com.google.protobuf.nano.*;
8 | import java.io.*;
9 | import android.nfc.*;
10 |
11 | public class CardboardDeviceParams{
12 | private static final String TAG = "CardboardDeviceParams";
13 | private static final String HTTP_SCHEME = "http";
14 | private static final String URI_HOST_GOOGLE_SHORT = "g.co";
15 | private static final String URI_HOST_GOOGLE = "google.com";
16 | private static final String URI_PATH_CARDBOARD_HOME = "cardboard";
17 | private static final String URI_PATH_CARDBOARD_CONFIG = "cardboard/cfg";
18 | private static final String URI_SCHEME_LEGACY_CARDBOARD = "cardboard";
19 | private static final String URI_HOST_LEGACY_CARDBOARD = "v1.0.0";
20 | private static final Uri URI_ORIGINAL_CARDBOARD_NFC;
21 | private static final Uri URI_ORIGINAL_CARDBOARD_QR_CODE;
22 | private static final String URI_KEY_PARAMS = "p";
23 | private static final int STREAM_SENTINEL = 894990891;
24 | private static final String DEFAULT_VENDOR = "Google, Inc.";
25 | private static final String DEFAULT_MODEL = "Cardboard v1";
26 | private static final float DEFAULT_INTER_LENS_DISTANCE = 0.06f;
27 | private static final float DEFAULT_VERTICAL_DISTANCE_TO_LENS_CENTER = 0.035f;
28 | private static final float DEFAULT_SCREEN_TO_LENS_DISTANCE = 0.042f;
29 | private String mVendor;
30 | private String mModel;
31 | private float mInterLensDistance;
32 | private float mVerticalDistanceToLensCenter;
33 | private float mScreenToLensDistance;
34 | private FieldOfView mLeftEyeMaxFov;
35 | private boolean mHasMagnet;
36 | private Distortion mDistortion;
37 |
38 | public CardboardDeviceParams() {
39 | super();
40 | this.setDefaultValues();
41 | }
42 |
43 | public CardboardDeviceParams(final CardboardDeviceParams params) {
44 | super();
45 | this.copyFrom(params);
46 | }
47 |
48 | public CardboardDeviceParams(final CardboardDevice.DeviceParams params) {
49 | super();
50 | this.setDefaultValues();
51 | if (params == null) {
52 | return;
53 | }
54 | this.mVendor = params.getVendor();
55 | this.mModel = params.getModel();
56 | this.mInterLensDistance = params.getInterLensDistance();
57 | this.mVerticalDistanceToLensCenter = params.getTrayBottomToLensHeight();
58 | this.mScreenToLensDistance = params.getScreenToLensDistance();
59 | this.mLeftEyeMaxFov = FieldOfView.parseFromProtobuf(params.leftEyeFieldOfViewAngles);
60 | if (this.mLeftEyeMaxFov == null) {
61 | this.mLeftEyeMaxFov = new FieldOfView();
62 | }
63 | this.mDistortion = Distortion.parseFromProtobuf(params.distortionCoefficients);
64 | if (this.mDistortion == null) {
65 | this.mDistortion = new Distortion();
66 | }
67 | this.mHasMagnet = params.getHasMagnet();
68 | }
69 |
70 | public static boolean isOriginalCardboardDeviceUri(final Uri uri) {
71 | return CardboardDeviceParams.URI_ORIGINAL_CARDBOARD_QR_CODE.equals((Object)uri) || (CardboardDeviceParams.URI_ORIGINAL_CARDBOARD_NFC.getScheme().equals(uri.getScheme()) && CardboardDeviceParams.URI_ORIGINAL_CARDBOARD_NFC.getAuthority().equals(uri.getAuthority()));
72 | }
73 |
74 | private static boolean isCardboardDeviceUri(final Uri uri) {
75 | return HTTP_SCHEME.equals(uri.getScheme()) && URI_HOST_GOOGLE.equals(uri.getAuthority()) && URI_PATH_CARDBOARD_CONFIG.equals(uri.getPath());
76 | }
77 |
78 | public static boolean isCardboardUri(final Uri uri) {
79 | return isOriginalCardboardDeviceUri(uri) || isCardboardDeviceUri(uri);
80 | }
81 |
82 | public static CardboardDeviceParams createFromUri(final Uri uri) {
83 | if (uri == null) {
84 | return null;
85 | }
86 | if (isOriginalCardboardDeviceUri(uri)) {
87 | Log.d("CardboardDeviceParams", "URI recognized as original cardboard device.");
88 | final CardboardDeviceParams deviceParams = new CardboardDeviceParams();
89 | deviceParams.setDefaultValues();
90 | return deviceParams;
91 | }
92 | if (!isCardboardDeviceUri(uri)) {
93 | Log.w("CardboardDeviceParams", String.format("URI \"%s\" not recognized as cardboard device.", uri));
94 | return null;
95 | }
96 | CardboardDevice.DeviceParams params = null;
97 | final String paramsEncoded = uri.getQueryParameter(URI_KEY_PARAMS);
98 | if (paramsEncoded != null) {
99 | try {
100 | final byte[] bytes = Base64.decode(paramsEncoded, 11);
101 | params = (CardboardDevice.DeviceParams)MessageNano.mergeFrom((MessageNano)new CardboardDevice.DeviceParams(), bytes);
102 | Log.d("CardboardDeviceParams", "Read cardboard params from URI.");
103 | }
104 | catch (Exception e) {
105 | final String s = "CardboardDeviceParams";
106 | final String s2 = "Parsing cardboard parameters from URI failed: ";
107 | final String value = String.valueOf(e.toString());
108 | Log.w(s, (value.length() != 0) ? s2.concat(value) : new String(s2));
109 | }
110 | }
111 | else {
112 | Log.w("CardboardDeviceParams", "No cardboard parameters in URI.");
113 | }
114 | return new CardboardDeviceParams(params);
115 | }
116 |
117 | public static CardboardDeviceParams createFromInputStream(final InputStream inputStream) {
118 | if (inputStream == null) {
119 | return null;
120 | }
121 | try {
122 | final ByteBuffer header = ByteBuffer.allocate(8);
123 | if (inputStream.read(header.array(), 0, header.array().length) == -1) {
124 | Log.e("CardboardDeviceParams", "Error parsing param record: end of stream.");
125 | return null;
126 | }
127 | final int sentinel = header.getInt();
128 | final int length = header.getInt();
129 | if (sentinel != STREAM_SENTINEL) {
130 | Log.e("CardboardDeviceParams", "Error parsing param record: incorrect sentinel.");
131 | return null;
132 | }
133 | final byte[] protoBytes = new byte[length];
134 | if (inputStream.read(protoBytes, 0, protoBytes.length) == -1) {
135 | Log.e("CardboardDeviceParams", "Error parsing param record: end of stream.");
136 | return null;
137 | }
138 | return new CardboardDeviceParams((CardboardDevice.DeviceParams)MessageNano.mergeFrom((MessageNano)new CardboardDevice.DeviceParams(), protoBytes));
139 | }
140 | catch (InvalidProtocolBufferNanoException e) {
141 | final String s = "CardboardDeviceParams";
142 | final String s2 = "Error parsing protocol buffer: ";
143 | final String value = String.valueOf(e.toString());
144 | Log.w(s, (value.length() != 0) ? s2.concat(value) : new String(s2));
145 | }
146 | catch (IOException e2) {
147 | final String s3 = "CardboardDeviceParams";
148 | final String s4 = "Error reading Cardboard parameters: ";
149 | final String value2 = String.valueOf(e2.toString());
150 | Log.w(s3, (value2.length() != 0) ? s4.concat(value2) : new String(s4));
151 | }
152 | return null;
153 | }
154 |
155 | public boolean writeToOutputStream(final OutputStream outputStream) {
156 | try {
157 | final byte[] paramBytes = this.toByteArray();
158 | final ByteBuffer header = ByteBuffer.allocate(8);
159 | header.putInt(STREAM_SENTINEL);
160 | header.putInt(paramBytes.length);
161 | outputStream.write(header.array());
162 | outputStream.write(paramBytes);
163 | return true;
164 | }
165 | catch (IOException e) {
166 | final String s = "CardboardDeviceParams";
167 | final String s2 = "Error writing Cardboard parameters: ";
168 | final String value = String.valueOf(e.toString());
169 | Log.w(s, (value.length() != 0) ? s2.concat(value) : new String(s2));
170 | return false;
171 | }
172 | }
173 |
174 | public static CardboardDeviceParams createFromNfcContents(final NdefMessage tagContents) {
175 | if (tagContents == null) {
176 | Log.w("CardboardDeviceParams", "Could not get contents from NFC tag.");
177 | return null;
178 | }
179 | for (final NdefRecord record : tagContents.getRecords()) {
180 | final CardboardDeviceParams params = createFromUri(record.toUri());
181 | if (params != null) {
182 | return params;
183 | }
184 | }
185 | return null;
186 | }
187 |
188 | private byte[] toByteArray() {
189 | final CardboardDevice.DeviceParams params = new CardboardDevice.DeviceParams();
190 | params.setVendor(this.mVendor);
191 | params.setModel(this.mModel);
192 | params.setInterLensDistance(this.mInterLensDistance);
193 | params.setTrayBottomToLensHeight(this.mVerticalDistanceToLensCenter);
194 | params.setScreenToLensDistance(this.mScreenToLensDistance);
195 | params.leftEyeFieldOfViewAngles = this.mLeftEyeMaxFov.toProtobuf();
196 | params.distortionCoefficients = this.mDistortion.toProtobuf();
197 | if (this.mHasMagnet) {
198 | params.setHasMagnet(this.mHasMagnet);
199 | }
200 | return MessageNano.toByteArray((MessageNano)params);
201 | }
202 |
203 | public Uri toUri() {
204 | final byte[] paramsData = this.toByteArray();
205 | final int paramsSize = paramsData.length;
206 | return new Uri.Builder().scheme("http").authority("google.com").appendEncodedPath("cardboard/cfg").appendQueryParameter("p", Base64.encodeToString(paramsData, 0, paramsSize, 11)).build();
207 | }
208 |
209 | public void setVendor(final String vendor) {
210 | this.mVendor = ((vendor != null) ? vendor : "");
211 | }
212 |
213 | public String getVendor() {
214 | return this.mVendor;
215 | }
216 |
217 | public void setModel(final String model) {
218 | this.mModel = ((model != null) ? model : "");
219 | }
220 |
221 | public String getModel() {
222 | return this.mModel;
223 | }
224 |
225 | public void setInterLensDistance(final float interLensDistance) {
226 | this.mInterLensDistance = interLensDistance;
227 | }
228 |
229 | public float getInterLensDistance() {
230 | return this.mInterLensDistance;
231 | }
232 |
233 | public void setVerticalDistanceToLensCenter(final float verticalDistanceToLensCenter) {
234 | this.mVerticalDistanceToLensCenter = verticalDistanceToLensCenter;
235 | }
236 |
237 | public float getVerticalDistanceToLensCenter() {
238 | return this.mVerticalDistanceToLensCenter;
239 | }
240 |
241 | public void setScreenToLensDistance(final float screenToLensDistance) {
242 | this.mScreenToLensDistance = screenToLensDistance;
243 | }
244 |
245 | public float getScreenToLensDistance() {
246 | return this.mScreenToLensDistance;
247 | }
248 |
249 | public Distortion getDistortion() {
250 | return this.mDistortion;
251 | }
252 |
253 | public FieldOfView getLeftEyeMaxFov() {
254 | return this.mLeftEyeMaxFov;
255 | }
256 |
257 | public boolean getHasMagnet() {
258 | return this.mHasMagnet;
259 | }
260 |
261 | public void setHasMagnet(final boolean magnet) {
262 | this.mHasMagnet = magnet;
263 | }
264 |
265 | @Override
266 | public boolean equals(final Object other) {
267 | if (other == null) {
268 | return false;
269 | }
270 | if (other == this) {
271 | return true;
272 | }
273 | if (!(other instanceof CardboardDeviceParams)) {
274 | return false;
275 | }
276 | final CardboardDeviceParams o = (CardboardDeviceParams)other;
277 | return this.mVendor.equals(o.mVendor) && this.mModel.equals(o.mModel) && this.mInterLensDistance == o.mInterLensDistance && this.mVerticalDistanceToLensCenter == o.mVerticalDistanceToLensCenter && this.mScreenToLensDistance == o.mScreenToLensDistance && this.mLeftEyeMaxFov.equals(o.mLeftEyeMaxFov) && this.mDistortion.equals(o.mDistortion) && this.mHasMagnet == o.mHasMagnet;
278 | }
279 |
280 | @Override
281 | public String toString() {
282 | final StringBuilder append = new StringBuilder().append("{\n");
283 | final String value = String.valueOf(String.valueOf(this.mVendor));
284 | final StringBuilder append2 = append.append(new StringBuilder(12 + value.length()).append(" vendor: ").append(value).append(",\n").toString());
285 | final String value2 = String.valueOf(String.valueOf(this.mModel));
286 | final StringBuilder append3 = append2.append(new StringBuilder(11 + value2.length()).append(" model: ").append(value2).append(",\n").toString()).append(new StringBuilder(40).append(" inter_lens_distance: ").append(this.mInterLensDistance).append(",\n").toString()).append(new StringBuilder(53).append(" vertical_distance_to_lens_center: ").append(this.mVerticalDistanceToLensCenter).append(",\n").toString()).append(new StringBuilder(44).append(" screen_to_lens_distance: ").append(this.mScreenToLensDistance).append(",\n").toString());
287 | final String value3 = String.valueOf(String.valueOf(this.mLeftEyeMaxFov.toString().replace("\n", "\n ")));
288 | final StringBuilder append4 = append3.append(new StringBuilder(22 + value3.length()).append(" left_eye_max_fov: ").append(value3).append(",\n").toString());
289 | final String value4 = String.valueOf(String.valueOf(this.mDistortion.toString().replace("\n", "\n ")));
290 | return append4.append(new StringBuilder(16 + value4.length()).append(" distortion: ").append(value4).append(",\n").toString()).append(new StringBuilder(17).append(" magnet: ").append(this.mHasMagnet).append(",\n").toString()).append("}\n").toString();
291 | }
292 |
293 | private void setDefaultValues() {
294 | this.mVendor = DEFAULT_VENDOR;
295 | this.mModel = DEFAULT_MODEL;
296 | this.mInterLensDistance = DEFAULT_INTER_LENS_DISTANCE;
297 | this.mVerticalDistanceToLensCenter = DEFAULT_VERTICAL_DISTANCE_TO_LENS_CENTER;
298 | this.mScreenToLensDistance = DEFAULT_SCREEN_TO_LENS_DISTANCE;
299 | this.mLeftEyeMaxFov = new FieldOfView();
300 | this.mHasMagnet = true;
301 | this.mDistortion = new Distortion();
302 | }
303 |
304 | private void copyFrom(final CardboardDeviceParams params) {
305 | this.mVendor = params.mVendor;
306 | this.mModel = params.mModel;
307 | this.mInterLensDistance = params.mInterLensDistance;
308 | this.mVerticalDistanceToLensCenter = params.mVerticalDistanceToLensCenter;
309 | this.mScreenToLensDistance = params.mScreenToLensDistance;
310 | this.mLeftEyeMaxFov = new FieldOfView(params.mLeftEyeMaxFov);
311 | this.mHasMagnet = params.mHasMagnet;
312 | this.mDistortion = new Distortion(params.mDistortion);
313 | }
314 |
315 | static {
316 | URI_ORIGINAL_CARDBOARD_NFC = new Uri.Builder().scheme(URI_SCHEME_LEGACY_CARDBOARD).authority(URI_HOST_LEGACY_CARDBOARD).build();
317 | URI_ORIGINAL_CARDBOARD_QR_CODE = new Uri.Builder().scheme(HTTP_SCHEME).authority(URI_HOST_GOOGLE_SHORT).appendEncodedPath(URI_PATH_CARDBOARD_HOME).build();
318 | }
319 | }
320 |
--------------------------------------------------------------------------------
/library/src/main/java/com/google/vrtoolkit/cardboard/ConfigUtils.java:
--------------------------------------------------------------------------------
1 | package com.google.vrtoolkit.cardboard;
2 |
3 |
4 | import android.content.res.AssetManager;
5 | import android.os.Environment;
6 |
7 | import java.io.File;
8 | import java.io.IOException;
9 | import java.io.InputStream;
10 |
11 | public abstract class ConfigUtils {
12 | public static final String CARDBOARD_CONFIG_FOLDER = "Cardboard";
13 | public static final String CARDBOARD_DEVICE_PARAMS_FILE = "current_device_params";
14 | public static final String CARDBOARD_PHONE_PARAMS_FILE = "phone_params";
15 |
16 | public static File getConfigFile(final String filename) {
17 | final File configFolder = new File(
18 | Environment.getExternalStorageDirectory(), CARDBOARD_CONFIG_FOLDER);
19 | if (!configFolder.exists()) {
20 | configFolder.mkdirs();
21 | }
22 | else if (!configFolder.isDirectory()) {
23 | final String value = String.valueOf(String.valueOf(configFolder));
24 | throw new IllegalStateException(new StringBuilder()
25 | .append("Folder ").append(value).append(" already exists").toString());
26 | }
27 | return new File(configFolder, filename);
28 | }
29 |
30 | public static InputStream openAssetConfigFile(final AssetManager assetManager,
31 | final String filename) throws IOException {
32 | final String assetPath = new File(CARDBOARD_CONFIG_FOLDER, filename).getPath();
33 | return assetManager.open(assetPath);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/library/src/main/java/com/google/vrtoolkit/cardboard/Constants.java:
--------------------------------------------------------------------------------
1 | package com.google.vrtoolkit.cardboard;
2 |
3 | public class Constants {
4 | public static final String CARDBOARD_CATEGORY = "com.google.intent.category.CARDBOARD";
5 | public static final String VERSION = "0.5.1";
6 | }
7 |
--------------------------------------------------------------------------------
/library/src/main/java/com/google/vrtoolkit/cardboard/Distortion.java:
--------------------------------------------------------------------------------
1 | package com.google.vrtoolkit.cardboard;
2 |
3 | import java.util.*;
4 |
5 | public class Distortion {
6 | private static final float[] DEFAULT_COEFFICIENTS;
7 | private float[] mCoefficients;
8 |
9 | public Distortion() {
10 | super();
11 | this.mCoefficients = Distortion.DEFAULT_COEFFICIENTS.clone();
12 | }
13 |
14 | public Distortion(final Distortion other) {
15 | super();
16 | this.setCoefficients(other.mCoefficients);
17 | }
18 |
19 | public static Distortion parseFromProtobuf(final float[] coefficients) {
20 | final Distortion distortion = new Distortion();
21 | distortion.setCoefficients(coefficients);
22 | return distortion;
23 | }
24 |
25 | public float[] toProtobuf() {
26 | return this.mCoefficients.clone();
27 | }
28 |
29 | public void setCoefficients(final float[] coefficients) {
30 | this.mCoefficients = ((coefficients != null) ? coefficients.clone() : new float[0]);
31 | }
32 |
33 | public float[] getCoefficients() {
34 | return this.mCoefficients;
35 | }
36 |
37 | public float distortionFactor(final float radius) {
38 | float result = 1.0f;
39 | float rFactor = 1.0f;
40 | final float rSquared = radius * radius;
41 | for (final float ki : this.mCoefficients) {
42 | rFactor *= rSquared;
43 | result += ki * rFactor;
44 | }
45 | return result;
46 | }
47 |
48 | public float distort(final float radius) {
49 | return radius * this.distortionFactor(radius);
50 | }
51 |
52 | public float distortInverse(final float radius) {
53 | float r0 = radius / 0.9f;
54 | float r = radius * 0.9f;
55 | float dr0 = radius - this.distort(r0);
56 | while (Math.abs(r - r0) > 1.0E-4) {
57 | final float dr = radius - this.distort(r);
58 | final float r2 = r - dr * ((r - r0) / (dr - dr0));
59 | r0 = r;
60 | r = r2;
61 | dr0 = dr;
62 | }
63 | return r;
64 | }
65 |
66 | private static double[] solveLeastSquares(final double[][] matA, final double[] vecY) {
67 | final int numSamples = matA.length;
68 | final int numCoefficients = matA[0].length;
69 | final double[][] matATA = new double[numCoefficients][numCoefficients];
70 | for (int k = 0; k < numCoefficients; ++k) {
71 | for (int j = 0; j < numCoefficients; ++j) {
72 | double sum = 0.0;
73 | for (int i = 0; i < numSamples; ++i) {
74 | sum += matA[i][j] * matA[i][k];
75 | }
76 | matATA[j][k] = sum;
77 | }
78 | }
79 | final double[][] matInvATA = new double[numCoefficients][numCoefficients];
80 | if (numCoefficients != 2) {
81 | throw new RuntimeException(new StringBuilder()
82 | .append("solveLeastSquares: only 2 coefficients currently supported, ")
83 | .append(numCoefficients).append(" given.").toString());
84 | }
85 | final double det = matATA[0][0] * matATA[1][1] - matATA[0][1] * matATA[1][0];
86 | matInvATA[0][0] = matATA[1][1] / det;
87 | matInvATA[1][1] = matATA[0][0] / det;
88 | matInvATA[0][1] = -matATA[1][0] / det;
89 | matInvATA[1][0] = -matATA[0][1] / det;
90 | final double[] vecATY = new double[numCoefficients];
91 | for (int l = 0; l < numCoefficients; ++l) {
92 | double sum2 = 0.0;
93 | for (int m = 0; m < numSamples; ++m) {
94 | sum2 += matA[m][l] * vecY[m];
95 | }
96 | vecATY[l] = sum2;
97 | }
98 | final double[] vecX = new double[numCoefficients];
99 | for (int j2 = 0; j2 < numCoefficients; ++j2) {
100 | double sum3 = 0.0;
101 | for (int i2 = 0; i2 < numCoefficients; ++i2) {
102 | sum3 += matInvATA[i2][j2] * vecATY[i2];
103 | }
104 | vecX[j2] = sum3;
105 | }
106 | return vecX;
107 | }
108 |
109 | public Distortion getApproximateInverseDistortion(final float maxRadius) {
110 | final int numSamples = 10;
111 | final int numCoefficients = 2;
112 | final double[][] matA = new double[10][2];
113 | final double[] vecY = new double[10];
114 | for (int i = 0; i < 10; ++i) {
115 | final float r = maxRadius * (i + 1) / 10.0f;
116 | double v;
117 | final double rp = v = this.distort(r);
118 | for (int j = 0; j < 2; ++j) {
119 | v *= rp * rp;
120 | matA[i][j] = v;
121 | }
122 | vecY[i] = r - rp;
123 | }
124 | final double[] vecK = solveLeastSquares(matA, vecY);
125 | final float[] coefficients = new float[vecK.length];
126 | for (int k = 0; k < vecK.length; ++k) {
127 | coefficients[k] = (float)vecK[k];
128 | }
129 | final Distortion inverse = new Distortion();
130 | inverse.setCoefficients(coefficients);
131 | return inverse;
132 | }
133 |
134 | @Override
135 | public boolean equals(final Object other) {
136 | if (other == null) {
137 | return false;
138 | }
139 | if (other == this) {
140 | return true;
141 | }
142 | if (!(other instanceof Distortion)) {
143 | return false;
144 | }
145 | final Distortion o = (Distortion)other;
146 | return Arrays.equals(this.mCoefficients, o.mCoefficients);
147 | }
148 |
149 | @Override
150 | public String toString() {
151 | final StringBuilder builder = new StringBuilder().append("{\n").append(" coefficients: [");
152 | for (int i = 0; i < this.mCoefficients.length; ++i) {
153 | builder.append(Float.toString(this.mCoefficients[i]));
154 | if (i < this.mCoefficients.length - 1) {
155 | builder.append(", ");
156 | }
157 | }
158 | builder.append("],\n}");
159 | return builder.toString();
160 | }
161 |
162 | static {
163 | DEFAULT_COEFFICIENTS = new float[] { 0.441f, 0.156f };
164 | }
165 | }
166 |
--------------------------------------------------------------------------------
/library/src/main/java/com/google/vrtoolkit/cardboard/Eye.java:
--------------------------------------------------------------------------------
1 | package com.google.vrtoolkit.cardboard;
2 |
3 | public class Eye {
4 | private final int mType;
5 | private final float[] mEyeView;
6 | private final Viewport mViewport;
7 | private final FieldOfView mFov;
8 | private volatile boolean mProjectionChanged;
9 | private float[] mPerspective;
10 | private float mLastZNear;
11 | private float mLastZFar;
12 |
13 | public Eye(final int type) {
14 | super();
15 | this.mType = type;
16 | this.mEyeView = new float[16];
17 | this.mViewport = new Viewport();
18 | this.mFov = new FieldOfView();
19 | this.mProjectionChanged = true;
20 | }
21 |
22 | public int getType() {
23 | return this.mType;
24 | }
25 |
26 | public float[] getEyeView() {
27 | return this.mEyeView;
28 | }
29 |
30 | public float[] getPerspective(final float zNear, final float zFar) {
31 | if (!this.mProjectionChanged && this.mLastZNear == zNear && this.mLastZFar == zFar) {
32 | return this.mPerspective;
33 | }
34 | if (this.mPerspective == null) {
35 | this.mPerspective = new float[16];
36 | }
37 | this.getFov().toPerspectiveMatrix(zNear, zFar, this.mPerspective, 0);
38 | this.mLastZNear = zNear;
39 | this.mLastZFar = zFar;
40 | this.mProjectionChanged = false;
41 | return this.mPerspective;
42 | }
43 |
44 | public Viewport getViewport() {
45 | return this.mViewport;
46 | }
47 |
48 | public FieldOfView getFov() {
49 | return this.mFov;
50 | }
51 |
52 | public void setProjectionChanged() {
53 | this.mProjectionChanged = true;
54 | }
55 |
56 | public abstract static class Type {
57 | public static final int MONOCULAR = 0;
58 | public static final int LEFT = 1;
59 | public static final int RIGHT = 2;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/library/src/main/java/com/google/vrtoolkit/cardboard/FieldOfView.java:
--------------------------------------------------------------------------------
1 | package com.google.vrtoolkit.cardboard;
2 |
3 | import android.opengl.*;
4 |
5 | public class FieldOfView {
6 | private static final float DEFAULT_MAX_FOV_LEFT_RIGHT = 40.0f;
7 | private static final float DEFAULT_MAX_FOV_BOTTOM = 40.0f;
8 | private static final float DEFAULT_MAX_FOV_TOP = 40.0f;
9 | private float mLeft;
10 | private float mRight;
11 | private float mBottom;
12 | private float mTop;
13 |
14 | public FieldOfView() {
15 | super();
16 | this.mLeft = DEFAULT_MAX_FOV_LEFT_RIGHT;
17 | this.mRight = DEFAULT_MAX_FOV_LEFT_RIGHT;
18 | this.mBottom = DEFAULT_MAX_FOV_BOTTOM;
19 | this.mTop = DEFAULT_MAX_FOV_TOP;
20 | }
21 |
22 | public FieldOfView(final float left, final float right, final float bottom, final float top) {
23 | super();
24 | this.mLeft = left;
25 | this.mRight = right;
26 | this.mBottom = bottom;
27 | this.mTop = top;
28 | }
29 |
30 | public FieldOfView(final FieldOfView other) {
31 | super();
32 | this.copy(other);
33 | }
34 |
35 | public static FieldOfView parseFromProtobuf(final float[] angles) {
36 | if (angles.length != 4) {
37 | return null;
38 | }
39 | return new FieldOfView(angles[0], angles[1], angles[2], angles[3]);
40 | }
41 |
42 | public float[] toProtobuf() {
43 | return new float[] { this.mLeft, this.mRight, this.mBottom, this.mTop };
44 | }
45 |
46 | public void copy(final FieldOfView other) {
47 | this.mLeft = other.mLeft;
48 | this.mRight = other.mRight;
49 | this.mBottom = other.mBottom;
50 | this.mTop = other.mTop;
51 | }
52 |
53 | public void setLeft(final float left) {
54 | this.mLeft = left;
55 | }
56 |
57 | public float getLeft() {
58 | return this.mLeft;
59 | }
60 |
61 | public void setRight(final float right) {
62 | this.mRight = right;
63 | }
64 |
65 | public float getRight() {
66 | return this.mRight;
67 | }
68 |
69 | public void setBottom(final float bottom) {
70 | this.mBottom = bottom;
71 | }
72 |
73 | public float getBottom() {
74 | return this.mBottom;
75 | }
76 |
77 | public void setTop(final float top) {
78 | this.mTop = top;
79 | }
80 |
81 | public float getTop() {
82 | return this.mTop;
83 | }
84 |
85 | public void toPerspectiveMatrix(final float near, final float far, final float[] perspective, final int offset) {
86 | if (offset + 16 > perspective.length) {
87 | throw new IllegalArgumentException("Not enough space to write the result");
88 | }
89 | final float l = (float)(-Math.tan(Math.toRadians(this.mLeft))) * near;
90 | final float r = (float)Math.tan(Math.toRadians(this.mRight)) * near;
91 | final float b = (float)(-Math.tan(Math.toRadians(this.mBottom))) * near;
92 | final float t = (float)Math.tan(Math.toRadians(this.mTop)) * near;
93 | Matrix.frustumM(perspective, offset, l, r, b, t, near, far);
94 | }
95 |
96 | @Override
97 | public boolean equals(final Object other) {
98 | if (other == null) {
99 | return false;
100 | }
101 | if (other == this) {
102 | return true;
103 | }
104 | if (!(other instanceof FieldOfView)) {
105 | return false;
106 | }
107 | final FieldOfView o = (FieldOfView)other;
108 | return this.mLeft == o.mLeft && this.mRight == o.mRight && this.mBottom == o.mBottom && this.mTop == o.mTop;
109 | }
110 |
111 | @Override
112 | public String toString() {
113 | return "{\n" + new StringBuilder(25).append(" left: ").append(this.mLeft).append(",\n").toString() + new StringBuilder(26).append(" right: ").append(this.mRight).append(",\n").toString() + new StringBuilder(27).append(" bottom: ").append(this.mBottom).append(",\n").toString() + new StringBuilder(24).append(" top: ").append(this.mTop).append(",\n").toString() + "}";
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/library/src/main/java/com/google/vrtoolkit/cardboard/GLStateBackup.java:
--------------------------------------------------------------------------------
1 | package com.google.vrtoolkit.cardboard;
2 |
3 | import java.nio.*;
4 | import android.opengl.*;
5 | import java.util.*;
6 |
7 | class GLStateBackup {
8 | private boolean mCullFaceEnabled;
9 | private boolean mScissorTestEnabled;
10 | private boolean mDepthTestEnabled;
11 | private IntBuffer mViewport;
12 | private IntBuffer mTexture2dId;
13 | private IntBuffer mTextureUnit;
14 | private IntBuffer mScissorBox;
15 | private IntBuffer mShaderProgram;
16 | private IntBuffer mArrayBufferBinding;
17 | private IntBuffer mElementArrayBufferBinding;
18 | private FloatBuffer mClearColor;
19 | private ArrayList mVertexAttributes;
20 |
21 | GLStateBackup() {
22 | super();
23 | this.mViewport = IntBuffer.allocate(4);
24 | this.mTexture2dId = IntBuffer.allocate(1);
25 | this.mTextureUnit = IntBuffer.allocate(1);
26 | this.mScissorBox = IntBuffer.allocate(4);
27 | this.mShaderProgram = IntBuffer.allocate(1);
28 | this.mArrayBufferBinding = IntBuffer.allocate(1);
29 | this.mElementArrayBufferBinding = IntBuffer.allocate(1);
30 | this.mClearColor = FloatBuffer.allocate(4);
31 | this.mVertexAttributes = new ArrayList();
32 | }
33 |
34 | void addTrackedVertexAttribute(final int attributeId) {
35 | this.mVertexAttributes.add(new VertexAttributeState(attributeId));
36 | }
37 |
38 | void clearTrackedVertexAttributes() {
39 | this.mVertexAttributes.clear();
40 | }
41 |
42 | void readFromGL() {
43 | GLES20.glGetIntegerv(GLES20.GL_VIEWPORT, this.mViewport);
44 | this.mCullFaceEnabled = GLES20.glIsEnabled(GLES20.GL_CULL_FACE);
45 | this.mScissorTestEnabled = GLES20.glIsEnabled(GLES20.GL_SCISSOR_TEST);
46 | this.mDepthTestEnabled = GLES20.glIsEnabled(GLES20.GL_DEPTH_TEST);
47 | GLES20.glGetFloatv(GLES20.GL_COLOR_CLEAR_VALUE, this.mClearColor);
48 | GLES20.glGetIntegerv(GLES20.GL_CURRENT_PROGRAM, this.mShaderProgram);
49 | GLES20.glGetIntegerv(GLES20.GL_SCISSOR_BOX, this.mScissorBox);
50 | GLES20.glGetIntegerv(GLES20.GL_ACTIVE_TEXTURE, this.mTextureUnit);
51 | GLES20.glGetIntegerv(GLES20.GL_TEXTURE_BINDING_2D, this.mTexture2dId);
52 | GLES20.glGetIntegerv(GLES20.GL_ARRAY_BUFFER_BINDING, this.mArrayBufferBinding);
53 | GLES20.glGetIntegerv(GLES20.GL_ELEMENT_ARRAY_BUFFER_BINDING, this.mElementArrayBufferBinding);
54 | for (final VertexAttributeState vas : this.mVertexAttributes) {
55 | vas.readFromGL();
56 | }
57 | }
58 |
59 | void writeToGL() {
60 | for (final VertexAttributeState vas : this.mVertexAttributes) {
61 | vas.writeToGL();
62 | }
63 | GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, this.mArrayBufferBinding.array()[0]);
64 | GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, this.mElementArrayBufferBinding.array()[0]);
65 | GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, this.mTexture2dId.array()[0]);
66 | GLES20.glActiveTexture(this.mTextureUnit.array()[0]);
67 | GLES20.glScissor(this.mScissorBox.array()[0], this.mScissorBox.array()[1], this.mScissorBox.array()[2], this.mScissorBox.array()[3]);
68 | GLES20.glUseProgram(this.mShaderProgram.array()[0]);
69 | GLES20.glClearColor(this.mClearColor.array()[0], this.mClearColor.array()[1], this.mClearColor.array()[2], this.mClearColor.array()[3]);
70 | if (this.mCullFaceEnabled) {
71 | GLES20.glEnable(GLES20.GL_CULL_FACE);
72 | }
73 | else {
74 | GLES20.glDisable(GLES20.GL_CULL_FACE);
75 | }
76 | if (this.mScissorTestEnabled) {
77 | GLES20.glEnable(GLES20.GL_SCISSOR_TEST);
78 | }
79 | else {
80 | GLES20.glDisable(GLES20.GL_SCISSOR_TEST);
81 | }
82 | if (this.mDepthTestEnabled) {
83 | GLES20.glEnable(GLES20.GL_DEPTH_TEST);
84 | }
85 | else {
86 | GLES20.glDisable(GLES20.GL_DEPTH_TEST);
87 | }
88 | GLES20.glViewport(this.mViewport.array()[0], this.mViewport.array()[1], this.mViewport.array()[2], this.mViewport.array()[3]);
89 | }
90 |
91 | private class VertexAttributeState
92 | {
93 | private int mAttributeId;
94 | private IntBuffer mEnabled;
95 |
96 | VertexAttributeState(final int attributeId) {
97 | super();
98 | this.mEnabled = IntBuffer.allocate(1);
99 | this.mAttributeId = attributeId;
100 | }
101 |
102 | void readFromGL() {
103 | GLES20.glGetVertexAttribiv(this.mAttributeId, GLES20.GL_VERTEX_ATTRIB_ARRAY_ENABLED, this.mEnabled);
104 | }
105 |
106 | void writeToGL() {
107 | if (this.mEnabled.array()[0] == 0) {
108 | GLES20.glDisableVertexAttribArray(this.mAttributeId);
109 | }
110 | else {
111 | GLES20.glEnableVertexAttribArray(this.mAttributeId);
112 | }
113 | }
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/library/src/main/java/com/google/vrtoolkit/cardboard/HeadMountedDisplay.java:
--------------------------------------------------------------------------------
1 | package com.google.vrtoolkit.cardboard;
2 |
3 | public class HeadMountedDisplay {
4 | private ScreenParams mScreen;
5 | private CardboardDeviceParams mCardboardDevice;
6 |
7 | public HeadMountedDisplay(final ScreenParams screenParams, final CardboardDeviceParams cardboardDevice) {
8 | super();
9 | this.mScreen = screenParams;
10 | this.mCardboardDevice = cardboardDevice;
11 | }
12 |
13 | public HeadMountedDisplay(final HeadMountedDisplay hmd) {
14 | super();
15 | this.mScreen = new ScreenParams(hmd.mScreen);
16 | this.mCardboardDevice = new CardboardDeviceParams(hmd.mCardboardDevice);
17 | }
18 |
19 | public void setScreenParams(final ScreenParams screen) {
20 | this.mScreen = new ScreenParams(screen);
21 | }
22 |
23 | public ScreenParams getScreenParams() {
24 | return this.mScreen;
25 | }
26 |
27 | public void setCardboardDeviceParams(final CardboardDeviceParams cardboardDeviceParams) {
28 | this.mCardboardDevice = new CardboardDeviceParams(cardboardDeviceParams);
29 | }
30 |
31 | public CardboardDeviceParams getCardboardDeviceParams() {
32 | return this.mCardboardDevice;
33 | }
34 |
35 | @Override
36 | public boolean equals(final Object other) {
37 | if (other == null) {
38 | return false;
39 | }
40 | if (other == this) {
41 | return true;
42 | }
43 | if (!(other instanceof HeadMountedDisplay)) {
44 | return false;
45 | }
46 | final HeadMountedDisplay o = (HeadMountedDisplay)other;
47 | return this.mScreen.equals(o.mScreen) && this.mCardboardDevice.equals(o.mCardboardDevice);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/library/src/main/java/com/google/vrtoolkit/cardboard/HeadMountedDisplayManager.java:
--------------------------------------------------------------------------------
1 | package com.google.vrtoolkit.cardboard;
2 |
3 | import android.content.*;
4 | import android.util.*;
5 | import android.view.*;
6 | import java.io.*;
7 |
8 | public class HeadMountedDisplayManager {
9 | private static final String TAG = "HeadMountedDisplayManager";
10 | private final HeadMountedDisplay mHmd;
11 | private final Context mContext;
12 |
13 | public HeadMountedDisplayManager(final Context context) {
14 | super();
15 | this.mContext = context;
16 | this.mHmd = new HeadMountedDisplay(this.createScreenParams(), this.createCardboardDeviceParams());
17 | }
18 |
19 | public HeadMountedDisplay getHeadMountedDisplay() {
20 | return this.mHmd;
21 | }
22 |
23 | public void onResume() {
24 | final CardboardDeviceParams deviceParams = this.createCardboardDeviceParamsFromExternalStorage();
25 | if (deviceParams != null && !deviceParams.equals(this.mHmd.getCardboardDeviceParams())) {
26 | this.mHmd.setCardboardDeviceParams(deviceParams);
27 | Log.i("HeadMountedDisplayManager", "Successfully read updated device params from external storage");
28 | }
29 | final ScreenParams screenParams = this.createScreenParamsFromExternalStorage(this.getDisplay());
30 | if (screenParams != null && !screenParams.equals(this.mHmd.getScreenParams())) {
31 | this.mHmd.setScreenParams(screenParams);
32 | Log.i("HeadMountedDisplayManager", "Successfully read updated screen params from external storage");
33 | }
34 | }
35 |
36 | public void onPause() {
37 | }
38 |
39 | public boolean updateCardboardDeviceParams(final CardboardDeviceParams cardboardDeviceParams) {
40 | if (cardboardDeviceParams == null || cardboardDeviceParams.equals(this.mHmd.getCardboardDeviceParams())) {
41 | return false;
42 | }
43 | this.mHmd.setCardboardDeviceParams(cardboardDeviceParams);
44 | this.writeCardboardParamsToExternalStorage();
45 | return true;
46 | }
47 |
48 | public boolean updateScreenParams(final ScreenParams screenParams) {
49 | if (screenParams == null || screenParams.equals(this.mHmd.getScreenParams())) {
50 | return false;
51 | }
52 | this.mHmd.setScreenParams(screenParams);
53 | return true;
54 | }
55 |
56 | private void writeCardboardParamsToExternalStorage() {
57 | boolean success = false;
58 | OutputStream stream = null;
59 | try {
60 | stream = new BufferedOutputStream(new FileOutputStream(ConfigUtils.getConfigFile("current_device_params")));
61 | success = this.mHmd.getCardboardDeviceParams().writeToOutputStream(stream);
62 | }
63 | catch (FileNotFoundException e) {}
64 | finally {
65 | if (stream != null) {
66 | try {
67 | stream.close();
68 | }
69 | catch (IOException ex) {}
70 | }
71 | }
72 | if (!success) {
73 | Log.e("HeadMountedDisplayManager", "Could not write Cardboard parameters to external storage.");
74 | }
75 | else {
76 | Log.i("HeadMountedDisplayManager", "Successfully wrote Cardboard parameters to external storage.");
77 | }
78 | }
79 |
80 | private Display getDisplay() {
81 | final WindowManager windowManager = (WindowManager)this.mContext.getSystemService("window");
82 | return windowManager.getDefaultDisplay();
83 | }
84 |
85 | private ScreenParams createScreenParams() {
86 | final Display display = this.getDisplay();
87 | final ScreenParams params = this.createScreenParamsFromExternalStorage(display);
88 | if (params != null) {
89 | Log.i("HeadMountedDisplayManager", "Successfully read screen params from external storage");
90 | return params;
91 | }
92 | return new ScreenParams(display);
93 | }
94 |
95 | private CardboardDeviceParams createCardboardDeviceParams() {
96 | CardboardDeviceParams params = this.createCardboardDeviceParamsFromExternalStorage();
97 | if (params != null) {
98 | Log.i("HeadMountedDisplayManager", "Successfully read device params from external storage");
99 | return params;
100 | }
101 | params = this.createCardboardDeviceParamsFromAssetFolder();
102 | if (params != null) {
103 | Log.i("HeadMountedDisplayManager", "Successfully read device params from asset folder");
104 | this.writeCardboardParamsToExternalStorage();
105 | return params;
106 | }
107 | return new CardboardDeviceParams();
108 | }
109 |
110 | private CardboardDeviceParams createCardboardDeviceParamsFromAssetFolder() {
111 | try {
112 | InputStream stream = null;
113 | try {
114 | stream = new BufferedInputStream(ConfigUtils.openAssetConfigFile(this.mContext.getAssets(), "current_device_params"));
115 | return CardboardDeviceParams.createFromInputStream(stream);
116 | }
117 | finally {
118 | if (stream != null) {
119 | stream.close();
120 | }
121 | }
122 | }
123 | catch (FileNotFoundException e) {
124 | final String s = "HeadMountedDisplayManager";
125 | final String value = String.valueOf(String.valueOf(e));
126 | Log.d(s, new StringBuilder(47 + value.length()).append("Bundled Cardboard device parameters not found: ").append(value).toString());
127 | }
128 | catch (IOException e2) {
129 | final String s2 = "HeadMountedDisplayManager";
130 | final String value2 = String.valueOf(String.valueOf(e2));
131 | Log.e(s2, new StringBuilder(43 + value2.length()).append("Error reading config file in asset folder: ").append(value2).toString());
132 | }
133 | return null;
134 | }
135 |
136 | private CardboardDeviceParams createCardboardDeviceParamsFromExternalStorage() {
137 | try {
138 | InputStream stream = null;
139 | try {
140 | stream = new BufferedInputStream(new FileInputStream(ConfigUtils.getConfigFile("current_device_params")));
141 | return CardboardDeviceParams.createFromInputStream(stream);
142 | }
143 | finally {
144 | if (stream != null) {
145 | try {
146 | stream.close();
147 | }
148 | catch (IOException ex) {}
149 | }
150 | }
151 | }
152 | catch (FileNotFoundException e) {
153 | final String s = "HeadMountedDisplayManager";
154 | final String value = String.valueOf(String.valueOf(e));
155 | Log.d(s, new StringBuilder(44 + value.length()).append("Cardboard device parameters file not found: ").append(value).toString());
156 | return null;
157 | }
158 | }
159 |
160 | private ScreenParams createScreenParamsFromExternalStorage(final Display display) {
161 | try {
162 | InputStream stream = null;
163 | try {
164 | stream = new BufferedInputStream(new FileInputStream(ConfigUtils.getConfigFile("phone_params")));
165 | return ScreenParams.createFromInputStream(display, stream);
166 | }
167 | finally {
168 | if (stream != null) {
169 | try {
170 | stream.close();
171 | }
172 | catch (IOException ex) {}
173 | }
174 | }
175 | }
176 | catch (FileNotFoundException e) {
177 | final String s = "HeadMountedDisplayManager";
178 | final String value = String.valueOf(String.valueOf(e));
179 | Log.d(s, new StringBuilder(44 + value.length()).append("Cardboard screen parameters file not found: ").append(value).toString());
180 | return null;
181 | }
182 | }
183 | }
184 |
--------------------------------------------------------------------------------
/library/src/main/java/com/google/vrtoolkit/cardboard/HeadTransform.java:
--------------------------------------------------------------------------------
1 | package com.google.vrtoolkit.cardboard;
2 |
3 | import android.opengl.*;
4 | import android.util.*;
5 |
6 | public class HeadTransform {
7 | private static final float GIMBAL_LOCK_EPSILON = 0.01f;
8 | private final float[] mHeadView;
9 |
10 | public HeadTransform() {
11 | super();
12 | Matrix.setIdentityM(this.mHeadView = new float[16], 0);
13 | }
14 |
15 | float[] getHeadView() {
16 | return this.mHeadView;
17 | }
18 |
19 | public void getHeadView(final float[] headView, final int offset) {
20 | if (offset + 16 > headView.length) {
21 | throw new IllegalArgumentException("Not enough space to write the result");
22 | }
23 | System.arraycopy(this.mHeadView, 0, headView, offset, 16);
24 | }
25 |
26 | public void getForwardVector(final float[] forward, final int offset) {
27 | if (offset + 3 > forward.length) {
28 | throw new IllegalArgumentException("Not enough space to write the result");
29 | }
30 | for (int i = 0; i < 3; ++i) {
31 | forward[i + offset] = -this.mHeadView[8 + i];
32 | }
33 | }
34 |
35 | public void getUpVector(final float[] up, final int offset) {
36 | if (offset + 3 > up.length) {
37 | throw new IllegalArgumentException("Not enough space to write the result");
38 | }
39 | for (int i = 0; i < 3; ++i) {
40 | up[i + offset] = this.mHeadView[4 + i];
41 | }
42 | }
43 |
44 | public void getRightVector(final float[] right, final int offset) {
45 | if (offset + 3 > right.length) {
46 | throw new IllegalArgumentException("Not enough space to write the result");
47 | }
48 | for (int i = 0; i < 3; ++i) {
49 | right[i + offset] = this.mHeadView[i];
50 | }
51 | }
52 |
53 | public void getQuaternion(final float[] quaternion, final int offset) {
54 | if (offset + 4 > quaternion.length) {
55 | throw new IllegalArgumentException("Not enough space to write the result");
56 | }
57 | final float[] m = this.mHeadView;
58 | final float t = m[0] + m[5] + m[10];
59 | float w;
60 | float x;
61 | float y;
62 | float z;
63 | if (t >= 0.0f) {
64 | float s = FloatMath.sqrt(t + 1.0f);
65 | w = 0.5f * s;
66 | s = 0.5f / s;
67 | x = (m[9] - m[6]) * s;
68 | y = (m[2] - m[8]) * s;
69 | z = (m[4] - m[1]) * s;
70 | }
71 | else if (m[0] > m[5] && m[0] > m[10]) {
72 | float s = FloatMath.sqrt(1.0f + m[0] - m[5] - m[10]);
73 | x = s * 0.5f;
74 | s = 0.5f / s;
75 | y = (m[4] + m[1]) * s;
76 | z = (m[2] + m[8]) * s;
77 | w = (m[9] - m[6]) * s;
78 | }
79 | else if (m[5] > m[10]) {
80 | float s = FloatMath.sqrt(1.0f + m[5] - m[0] - m[10]);
81 | y = s * 0.5f;
82 | s = 0.5f / s;
83 | x = (m[4] + m[1]) * s;
84 | z = (m[9] + m[6]) * s;
85 | w = (m[2] - m[8]) * s;
86 | }
87 | else {
88 | float s = FloatMath.sqrt(1.0f + m[10] - m[0] - m[5]);
89 | z = s * 0.5f;
90 | s = 0.5f / s;
91 | x = (m[2] + m[8]) * s;
92 | y = (m[9] + m[6]) * s;
93 | w = (m[4] - m[1]) * s;
94 | }
95 | quaternion[offset + 0] = x;
96 | quaternion[offset + 1] = y;
97 | quaternion[offset + 2] = z;
98 | quaternion[offset + 3] = w;
99 | }
100 |
101 | public void getEulerAngles(final float[] eulerAngles, final int offset) {
102 | if (offset + 3 > eulerAngles.length) {
103 | throw new IllegalArgumentException("Not enough space to write the result");
104 | }
105 | final float pitch = (float)Math.asin(this.mHeadView[6]);
106 | float yaw;
107 | float roll;
108 | if (FloatMath.sqrt(1.0f - this.mHeadView[6] * this.mHeadView[6]) >= GIMBAL_LOCK_EPSILON) {
109 | yaw = (float)Math.atan2(-this.mHeadView[2], this.mHeadView[10]);
110 | roll = (float)Math.atan2(-this.mHeadView[4], this.mHeadView[5]);
111 | }
112 | else {
113 | yaw = 0.0f;
114 | roll = (float)Math.atan2(this.mHeadView[1], this.mHeadView[0]);
115 | }
116 | eulerAngles[offset + 0] = -pitch;
117 | eulerAngles[offset + 1] = -yaw;
118 | eulerAngles[offset + 2] = -roll;
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/library/src/main/java/com/google/vrtoolkit/cardboard/PhoneParams.java:
--------------------------------------------------------------------------------
1 | package com.google.vrtoolkit.cardboard;
2 |
3 | import com.google.vrtoolkit.cardboard.proto.*;
4 | import java.nio.*;
5 | import android.util.*;
6 | import com.google.protobuf.nano.*;
7 | import java.io.*;
8 |
9 | public class PhoneParams {
10 | private static final String TAG;
11 | private static final int STREAM_SENTINEL = 779508118;
12 |
13 | static Phone.PhoneParams readFromInputStream(final InputStream inputStream) {
14 | if (inputStream == null) {
15 | return null;
16 | }
17 | try {
18 | final ByteBuffer header = ByteBuffer.allocate(8);
19 | if (inputStream.read(header.array(), 0, header.array().length) == -1) {
20 | Log.e(PhoneParams.TAG, "Error parsing param record: end of stream.");
21 | return null;
22 | }
23 | final int sentinel = header.getInt();
24 | final int length = header.getInt();
25 | if (sentinel != STREAM_SENTINEL) {
26 | Log.e(PhoneParams.TAG, "Error parsing param record: incorrect sentinel.");
27 | return null;
28 | }
29 | final byte[] protoBytes = new byte[length];
30 | if (inputStream.read(protoBytes, 0, protoBytes.length) == -1) {
31 | Log.e(PhoneParams.TAG, "Error parsing param record: end of stream.");
32 | return null;
33 | }
34 | return (Phone.PhoneParams)MessageNano.mergeFrom((MessageNano)new Phone.PhoneParams(), protoBytes);
35 | }
36 | catch (InvalidProtocolBufferNanoException e) {
37 | final String tag = PhoneParams.TAG;
38 | final String s = "Error parsing protocol buffer: ";
39 | final String value = String.valueOf(e.toString());
40 | Log.w(tag, (value.length() != 0) ? s.concat(value) : new String(s));
41 | }
42 | catch (IOException e2) {
43 | final String tag2 = PhoneParams.TAG;
44 | final String s2 = "Error reading Cardboard parameters: ";
45 | final String value2 = String.valueOf(e2.toString());
46 | Log.w(tag2, (value2.length() != 0) ? s2.concat(value2) : new String(s2));
47 | }
48 | return null;
49 | }
50 |
51 | static Phone.PhoneParams readFromExternalStorage() {
52 | try {
53 | InputStream stream = null;
54 | try {
55 | stream = new BufferedInputStream(new FileInputStream(ConfigUtils.getConfigFile("phone_params")));
56 | return readFromInputStream(stream);
57 | }
58 | finally {
59 | if (stream != null) {
60 | try {
61 | stream.close();
62 | }
63 | catch (IOException ex) {}
64 | }
65 | }
66 | }
67 | catch (FileNotFoundException e) {
68 | final String tag = PhoneParams.TAG;
69 | final String value = String.valueOf(String.valueOf(e));
70 | Log.d(tag, new StringBuilder(43 + value.length()).append("Cardboard phone parameters file not found: ").append(value).toString());
71 | return null;
72 | }
73 | }
74 |
75 | static {
76 | TAG = PhoneParams.class.getSimpleName();
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/library/src/main/java/com/google/vrtoolkit/cardboard/ScreenParams.java:
--------------------------------------------------------------------------------
1 | package com.google.vrtoolkit.cardboard;
2 |
3 | import android.view.*;
4 | import android.util.*;
5 | import com.google.vrtoolkit.cardboard.proto.*;
6 | import java.io.*;
7 |
8 | public class ScreenParams {
9 | private static final float METERS_PER_INCH = 0.0254f;
10 | private static final float DEFAULT_BORDER_SIZE_METERS = 0.003f;
11 | private int mWidth;
12 | private int mHeight;
13 | private float mXMetersPerPixel;
14 | private float mYMetersPerPixel;
15 | private float mBorderSizeMeters;
16 |
17 | public ScreenParams(final Display display) {
18 | super();
19 | final DisplayMetrics metrics = new DisplayMetrics();
20 | try {
21 | display.getRealMetrics(metrics);
22 | }
23 | catch (NoSuchMethodError e) {
24 | display.getMetrics(metrics);
25 | }
26 | this.mXMetersPerPixel = METERS_PER_INCH / metrics.xdpi;
27 | this.mYMetersPerPixel = METERS_PER_INCH / metrics.ydpi;
28 | this.mWidth = metrics.widthPixels;
29 | this.mHeight = metrics.heightPixels;
30 | this.mBorderSizeMeters = DEFAULT_BORDER_SIZE_METERS;
31 | if (this.mHeight > this.mWidth) {
32 | final int tempPx = this.mWidth;
33 | this.mWidth = this.mHeight;
34 | this.mHeight = tempPx;
35 | final float tempMetersPerPixel = this.mXMetersPerPixel;
36 | this.mXMetersPerPixel = this.mYMetersPerPixel;
37 | this.mYMetersPerPixel = tempMetersPerPixel;
38 | }
39 | }
40 |
41 | public static ScreenParams fromProto(final Display display, final Phone.PhoneParams params) {
42 | if (params == null) {
43 | return null;
44 | }
45 | final ScreenParams screenParams = new ScreenParams(display);
46 | if (params.hasXPpi()) {
47 | screenParams.mXMetersPerPixel = METERS_PER_INCH / params.getXPpi();
48 | }
49 | if (params.hasYPpi()) {
50 | screenParams.mYMetersPerPixel = METERS_PER_INCH / params.getYPpi();
51 | }
52 | if (params.hasBottomBezelHeight()) {
53 | screenParams.mBorderSizeMeters = params.getBottomBezelHeight();
54 | }
55 | return screenParams;
56 | }
57 |
58 | public ScreenParams(final ScreenParams params) {
59 | super();
60 | this.mWidth = params.mWidth;
61 | this.mHeight = params.mHeight;
62 | this.mXMetersPerPixel = params.mXMetersPerPixel;
63 | this.mYMetersPerPixel = params.mYMetersPerPixel;
64 | this.mBorderSizeMeters = params.mBorderSizeMeters;
65 | }
66 |
67 | public void setWidth(final int width) {
68 | this.mWidth = width;
69 | }
70 |
71 | public int getWidth() {
72 | return this.mWidth;
73 | }
74 |
75 | public void setHeight(final int height) {
76 | this.mHeight = height;
77 | }
78 |
79 | public int getHeight() {
80 | return this.mHeight;
81 | }
82 |
83 | public float getWidthMeters() {
84 | return this.mWidth * this.mXMetersPerPixel;
85 | }
86 |
87 | public float getHeightMeters() {
88 | return this.mHeight * this.mYMetersPerPixel;
89 | }
90 |
91 | public void setBorderSizeMeters(final float screenBorderSize) {
92 | this.mBorderSizeMeters = screenBorderSize;
93 | }
94 |
95 | public float getBorderSizeMeters() {
96 | return this.mBorderSizeMeters;
97 | }
98 |
99 | @Override
100 | public boolean equals(final Object other) {
101 | if (other == null) {
102 | return false;
103 | }
104 | if (other == this) {
105 | return true;
106 | }
107 | if (!(other instanceof ScreenParams)) {
108 | return false;
109 | }
110 | final ScreenParams o = (ScreenParams)other;
111 | return this.mWidth == o.mWidth && this.mHeight == o.mHeight && this.mXMetersPerPixel == o.mXMetersPerPixel && this.mYMetersPerPixel == o.mYMetersPerPixel && this.mBorderSizeMeters == o.mBorderSizeMeters;
112 | }
113 |
114 | @Override
115 | public String toString() {
116 | return "{\n" + new StringBuilder(22).append(" width: ").append(this.mWidth).append(",\n").toString() + new StringBuilder(23).append(" height: ").append(this.mHeight).append(",\n").toString() + new StringBuilder(39).append(" x_meters_per_pixel: ").append(this.mXMetersPerPixel).append(",\n").toString() + new StringBuilder(39).append(" y_meters_per_pixel: ").append(this.mYMetersPerPixel).append(",\n").toString() + new StringBuilder(39).append(" border_size_meters: ").append(this.mBorderSizeMeters).append(",\n").toString() + "}";
117 | }
118 |
119 | public static ScreenParams createFromInputStream(final Display display, final InputStream inputStream) {
120 | final Phone.PhoneParams phoneParams = PhoneParams.readFromInputStream(inputStream);
121 | if (phoneParams == null) {
122 | return null;
123 | }
124 | return fromProto(display, phoneParams);
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/library/src/main/java/com/google/vrtoolkit/cardboard/UiUtils.java:
--------------------------------------------------------------------------------
1 | package com.google.vrtoolkit.cardboard;
2 |
3 | import android.content.pm.*;
4 | import java.util.*;
5 | import android.net.*;
6 | import android.widget.*;
7 | import android.content.*;
8 | import android.os.*;
9 | import android.app.*;
10 |
11 | class UiUtils {
12 | private static final String CARDBOARD_WEBSITE = "http://google.com/cardboard/cfg?vrtoolkit_version=0.5.1";
13 | private static final String CARDBOARD_CONFIGURE_ACTION = "com.google.vrtoolkit.cardboard.CONFIGURE";
14 | private static final String INTENT_EXTRAS_VERSION_KEY = "VERSION";
15 | private static final String NO_BROWSER_TEXT = "No browser to open website.";
16 |
17 | static void launchOrInstallCardboard(final Context context) {
18 | final PackageManager pm = context.getPackageManager();
19 | final Intent settingsIntent = new Intent();
20 | settingsIntent.setAction("com.google.vrtoolkit.cardboard.CONFIGURE");
21 | settingsIntent.putExtra("VERSION", "0.5.1");
22 | final List resolveInfos = (List)pm.queryIntentActivities(settingsIntent, 0);
23 | final List intentsToGoogleCardboard = new ArrayList();
24 | for (final ResolveInfo info : resolveInfos) {
25 | final String pkgName = info.activityInfo.packageName;
26 | if (pkgName.startsWith("com.google.")) {
27 | final Intent intent = new Intent(settingsIntent);
28 | intent.setClassName(pkgName, info.activityInfo.name);
29 | intentsToGoogleCardboard.add(intent);
30 | }
31 | }
32 | if (intentsToGoogleCardboard.isEmpty()) {
33 | showInstallDialog(context);
34 | }
35 | else if (intentsToGoogleCardboard.size() == 1) {
36 | showConfigureDialog(context, intentsToGoogleCardboard.get(0));
37 | }
38 | else {
39 | showConfigureDialog(context, settingsIntent);
40 | }
41 | }
42 |
43 | private static void showInstallDialog(final Context context) {
44 | final DialogInterface.OnClickListener listener = (DialogInterface.OnClickListener)new DialogInterface.OnClickListener() {
45 | public void onClick(final DialogInterface dialog, final int id) {
46 | try {
47 | context.startActivity(new Intent("android.intent.action.VIEW", Uri.parse("http://google.com/cardboard/cfg?vrtoolkit_version=0.5.1")));
48 | }
49 | catch (ActivityNotFoundException e) {
50 | Toast.makeText(context.getApplicationContext(), (CharSequence)"No browser to open website.", 1).show();
51 | }
52 | }
53 | };
54 | final FragmentManager fragmentManager = ((Activity)context).getFragmentManager();
55 | final DialogFragment dialog = new SettingsDialogFragment((DialogStrings)new InstallDialogStrings(), listener);
56 | dialog.show(fragmentManager, "InstallCardboardDialog");
57 | }
58 |
59 | private static void showConfigureDialog(final Context context, final Intent intent) {
60 | final DialogInterface.OnClickListener listener = (DialogInterface.OnClickListener)new DialogInterface.OnClickListener() {
61 | public void onClick(final DialogInterface dialog, final int id) {
62 | try {
63 | context.startActivity(intent);
64 | }
65 | catch (ActivityNotFoundException e) {
66 | showInstallDialog(context);
67 | }
68 | }
69 | };
70 | final FragmentManager fragmentManager = ((Activity)context).getFragmentManager();
71 | final DialogFragment dialog = new SettingsDialogFragment((DialogStrings)new ConfigureDialogStrings(), listener);
72 | dialog.show(fragmentManager, "ConfigureCardboardDialog");
73 | }
74 |
75 | private static class DialogStrings {
76 | String mTitle;
77 | String mMessage;
78 | String mPositiveButtonText;
79 | String mNegativeButtonText;
80 | }
81 |
82 | private static class InstallDialogStrings extends DialogStrings {
83 | InstallDialogStrings() {
84 | super();
85 | this.mTitle = "Configure";
86 | this.mMessage = "Get the Cardboard app in order to configure your viewer.";
87 | this.mPositiveButtonText = "Go to Play Store";
88 | this.mNegativeButtonText = "Cancel";
89 | }
90 | }
91 |
92 | private static class ConfigureDialogStrings extends DialogStrings {
93 | ConfigureDialogStrings() {
94 | super();
95 | this.mTitle = "Configure";
96 | this.mMessage = "Set up your viewer for the best experience.";
97 | this.mPositiveButtonText = "Setup";
98 | this.mNegativeButtonText = "Cancel";
99 | }
100 | }
101 |
102 | private static class SettingsDialogFragment extends DialogFragment {
103 | private DialogStrings mDialogStrings;
104 | private DialogInterface.OnClickListener mPositiveButtonListener;
105 |
106 | private SettingsDialogFragment(final DialogStrings dialogStrings, final DialogInterface.OnClickListener positiveButtonListener) {
107 | super();
108 | this.mDialogStrings = dialogStrings;
109 | this.mPositiveButtonListener = positiveButtonListener;
110 | }
111 |
112 | public Dialog onCreateDialog(final Bundle savedInstanceState) {
113 | final AlertDialog.Builder builder = new AlertDialog.Builder((Context)this.getActivity());
114 | builder.setTitle((CharSequence)this.mDialogStrings.mTitle).setMessage((CharSequence)this.mDialogStrings.mMessage).setPositiveButton((CharSequence)this.mDialogStrings.mPositiveButtonText, this.mPositiveButtonListener).setNegativeButton((CharSequence)this.mDialogStrings.mNegativeButtonText, (DialogInterface.OnClickListener)null);
115 | return (Dialog)builder.create();
116 | }
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/library/src/main/java/com/google/vrtoolkit/cardboard/Viewport.java:
--------------------------------------------------------------------------------
1 | package com.google.vrtoolkit.cardboard;
2 |
3 | import android.opengl.*;
4 |
5 | public class Viewport {
6 | public int x;
7 | public int y;
8 | public int width;
9 | public int height;
10 |
11 | public void setViewport(final int x, final int y, final int width, final int height) {
12 | this.x = x;
13 | this.y = y;
14 | this.width = width;
15 | this.height = height;
16 | }
17 |
18 | public void setGLViewport() {
19 | GLES20.glViewport(this.x, this.y, this.width, this.height);
20 | }
21 |
22 | public void setGLScissor() {
23 | GLES20.glScissor(this.x, this.y, this.width, this.height);
24 | }
25 |
26 | public void getAsArray(final int[] array, final int offset) {
27 | if (offset + 4 > array.length) {
28 | throw new IllegalArgumentException("Not enough space to write the result");
29 | }
30 | array[offset] = this.x;
31 | array[offset + 1] = this.y;
32 | array[offset + 2] = this.width;
33 | array[offset + 3] = this.height;
34 | }
35 |
36 | @Override
37 | public String toString() {
38 | return "{\n" + new StringBuilder(18).append(" x: ").append(this.x).append(",\n").toString() + new StringBuilder(18).append(" y: ").append(this.y).append(",\n").toString() + new StringBuilder(22).append(" width: ").append(this.width).append(",\n").toString() + new StringBuilder(23).append(" height: ").append(this.height).append(",\n").toString() + "}";
39 | }
40 |
41 | @Override
42 | public boolean equals(final Object obj) {
43 | if (obj == this) {
44 | return true;
45 | }
46 | if (!(obj instanceof Viewport)) {
47 | return false;
48 | }
49 | final Viewport other = (Viewport)obj;
50 | return this.x == other.x && this.y == other.y && this.width == other.width && this.height == other.height;
51 | }
52 |
53 | @Override
54 | public int hashCode() {
55 | return Integer.valueOf(this.x).hashCode() ^ Integer.valueOf(this.y).hashCode() ^ Integer.valueOf(this.width).hashCode() ^ Integer.valueOf(this.height).hashCode();
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/library/src/main/java/com/google/vrtoolkit/cardboard/proto/CardboardDevice.java:
--------------------------------------------------------------------------------
1 | package com.google.vrtoolkit.cardboard.proto;
2 |
3 | import java.io.*;
4 | import com.google.protobuf.nano.*;
5 |
6 | public interface CardboardDevice {
7 | public static final class DeviceParams extends MessageNano {
8 | private static volatile DeviceParams[] _emptyArray;
9 | private int bitField0_;
10 | private String vendor_;
11 | private String model_;
12 | private float screenToLensDistance_;
13 | private float interLensDistance_;
14 | public float[] leftEyeFieldOfViewAngles;
15 | private float trayBottomToLensHeight_;
16 | public float[] distortionCoefficients;
17 | private boolean hasMagnet_;
18 |
19 | public static DeviceParams[] emptyArray() {
20 | if (DeviceParams._emptyArray == null) {
21 | synchronized (InternalNano.LAZY_INIT_LOCK) {
22 | if (DeviceParams._emptyArray == null) {
23 | DeviceParams._emptyArray = new DeviceParams[0];
24 | }
25 | }
26 | }
27 | return DeviceParams._emptyArray;
28 | }
29 |
30 | public String getVendor() {
31 | return this.vendor_;
32 | }
33 |
34 | public DeviceParams setVendor(String value) {
35 | if (value == null) {
36 | throw new NullPointerException();
37 | }
38 | this.vendor_ = value;
39 | this.bitField0_ |= 0x1;
40 | return this;
41 | }
42 |
43 | public boolean hasVendor() {
44 | return (this.bitField0_ & 0x1) != 0x0;
45 | }
46 |
47 | public DeviceParams clearVendor() {
48 | this.vendor_ = "";
49 | this.bitField0_ &= 0xFFFFFFFE;
50 | return this;
51 | }
52 |
53 | public String getModel() {
54 | return this.model_;
55 | }
56 |
57 | public DeviceParams setModel(String value) {
58 | if (value == null) {
59 | throw new NullPointerException();
60 | }
61 | this.model_ = value;
62 | this.bitField0_ |= 0x2;
63 | return this;
64 | }
65 |
66 | public boolean hasModel() {
67 | return (this.bitField0_ & 0x2) != 0x0;
68 | }
69 |
70 | public DeviceParams clearModel() {
71 | this.model_ = "";
72 | this.bitField0_ &= 0xFFFFFFFD;
73 | return this;
74 | }
75 |
76 | public float getScreenToLensDistance() {
77 | return this.screenToLensDistance_;
78 | }
79 |
80 | public DeviceParams setScreenToLensDistance(float value) {
81 | this.screenToLensDistance_ = value;
82 | this.bitField0_ |= 0x4;
83 | return this;
84 | }
85 |
86 | public boolean hasScreenToLensDistance() {
87 | return (this.bitField0_ & 0x4) != 0x0;
88 | }
89 |
90 | public DeviceParams clearScreenToLensDistance() {
91 | this.screenToLensDistance_ = 0.0f;
92 | this.bitField0_ &= 0xFFFFFFFB;
93 | return this;
94 | }
95 |
96 | public float getInterLensDistance() {
97 | return this.interLensDistance_;
98 | }
99 |
100 | public DeviceParams setInterLensDistance(float value) {
101 | this.interLensDistance_ = value;
102 | this.bitField0_ |= 0x8;
103 | return this;
104 | }
105 |
106 | public boolean hasInterLensDistance() {
107 | return (this.bitField0_ & 0x8) != 0x0;
108 | }
109 |
110 | public DeviceParams clearInterLensDistance() {
111 | this.interLensDistance_ = 0.0f;
112 | this.bitField0_ &= 0xFFFFFFF7;
113 | return this;
114 | }
115 |
116 | public float getTrayBottomToLensHeight() {
117 | return this.trayBottomToLensHeight_;
118 | }
119 |
120 | public DeviceParams setTrayBottomToLensHeight(float value) {
121 | this.trayBottomToLensHeight_ = value;
122 | this.bitField0_ |= 0x10;
123 | return this;
124 | }
125 |
126 | public boolean hasTrayBottomToLensHeight() {
127 | return (this.bitField0_ & 0x10) != 0x0;
128 | }
129 |
130 | public DeviceParams clearTrayBottomToLensHeight() {
131 | this.trayBottomToLensHeight_ = 0.0f;
132 | this.bitField0_ &= 0xFFFFFFEF;
133 | return this;
134 | }
135 |
136 | public boolean getHasMagnet() {
137 | return this.hasMagnet_;
138 | }
139 |
140 | public DeviceParams setHasMagnet(boolean value) {
141 | this.hasMagnet_ = value;
142 | this.bitField0_ |= 0x20;
143 | return this;
144 | }
145 |
146 | public boolean hasHasMagnet() {
147 | return (this.bitField0_ & 0x20) != 0x0;
148 | }
149 |
150 | public DeviceParams clearHasMagnet() {
151 | this.hasMagnet_ = false;
152 | this.bitField0_ &= 0xFFFFFFDF;
153 | return this;
154 | }
155 |
156 | public DeviceParams() {
157 | super();
158 | this.clear();
159 | }
160 |
161 | public DeviceParams clear() {
162 | this.bitField0_ = 0;
163 | this.vendor_ = "";
164 | this.model_ = "";
165 | this.screenToLensDistance_ = 0.0f;
166 | this.interLensDistance_ = 0.0f;
167 | this.leftEyeFieldOfViewAngles = WireFormatNano.EMPTY_FLOAT_ARRAY;
168 | this.trayBottomToLensHeight_ = 0.0f;
169 | this.distortionCoefficients = WireFormatNano.EMPTY_FLOAT_ARRAY;
170 | this.hasMagnet_ = false;
171 | this.cachedSize = -1;
172 | return this;
173 | }
174 |
175 | public void writeTo(CodedOutputByteBufferNano output) throws IOException {
176 | int dataSize;
177 | if ((this.bitField0_ & 0x1) != 0x0) {
178 | output.writeString(1, this.vendor_);
179 | }
180 | if ((this.bitField0_ & 0x2) != 0x0) {
181 | output.writeString(2, this.model_);
182 | }
183 | if ((this.bitField0_ & 0x4) != 0x0) {
184 | output.writeFloat(3, this.screenToLensDistance_);
185 | }
186 | if ((this.bitField0_ & 0x8) != 0x0) {
187 | output.writeFloat(4, this.interLensDistance_);
188 | }
189 | if (this.leftEyeFieldOfViewAngles != null && this.leftEyeFieldOfViewAngles.length > 0) {
190 | dataSize = 4 * this.leftEyeFieldOfViewAngles.length;
191 | output.writeRawVarint32(42);
192 | output.writeRawVarint32(dataSize);
193 | for (int i = 0; i < this.leftEyeFieldOfViewAngles.length; ++i) {
194 | output.writeFloatNoTag(this.leftEyeFieldOfViewAngles[i]);
195 | }
196 | }
197 | if ((this.bitField0_ & 0x10) != 0x0) {
198 | output.writeFloat(6, this.trayBottomToLensHeight_);
199 | }
200 | if (this.distortionCoefficients != null && this.distortionCoefficients.length > 0) {
201 | dataSize = 4 * this.distortionCoefficients.length;
202 | output.writeRawVarint32(58);
203 | output.writeRawVarint32(dataSize);
204 | for (int i = 0; i < this.distortionCoefficients.length; ++i) {
205 | output.writeFloatNoTag(this.distortionCoefficients[i]);
206 | }
207 | }
208 | if ((this.bitField0_ & 0x20) != 0x0) {
209 | output.writeBool(10, this.hasMagnet_);
210 | }
211 | super.writeTo(output);
212 | }
213 |
214 | protected int computeSerializedSize() {
215 | int size;
216 | int dataSize;
217 | size = super.computeSerializedSize();
218 | if ((this.bitField0_ & 0x1) != 0x0) {
219 | size += CodedOutputByteBufferNano.computeStringSize(1, this.vendor_);
220 | }
221 | if ((this.bitField0_ & 0x2) != 0x0) {
222 | size += CodedOutputByteBufferNano.computeStringSize(2, this.model_);
223 | }
224 | if ((this.bitField0_ & 0x4) != 0x0) {
225 | size += CodedOutputByteBufferNano.computeFloatSize(3, this.screenToLensDistance_);
226 | }
227 | if ((this.bitField0_ & 0x8) != 0x0) {
228 | size += CodedOutputByteBufferNano.computeFloatSize(4, this.interLensDistance_);
229 | }
230 | if (this.leftEyeFieldOfViewAngles != null && this.leftEyeFieldOfViewAngles.length > 0) {
231 | dataSize = 4 * this.leftEyeFieldOfViewAngles.length;
232 | size += dataSize;
233 | size = ++size + CodedOutputByteBufferNano.computeRawVarint32Size(dataSize);
234 | }
235 | if ((this.bitField0_ & 0x10) != 0x0) {
236 | size += CodedOutputByteBufferNano.computeFloatSize(6, this.trayBottomToLensHeight_);
237 | }
238 | if (this.distortionCoefficients != null && this.distortionCoefficients.length > 0) {
239 | dataSize = 4 * this.distortionCoefficients.length;
240 | size += dataSize;
241 | size = ++size + CodedOutputByteBufferNano.computeRawVarint32Size(dataSize);
242 | }
243 | if ((this.bitField0_ & 0x20) != 0x0) {
244 | size += CodedOutputByteBufferNano.computeBoolSize(10, this.hasMagnet_);
245 | }
246 | return size;
247 | }
248 |
249 | public DeviceParams mergeFrom(CodedInputByteBufferNano input) throws IOException {
250 | int tag;
251 | int arrayLength;
252 | int i;
253 | float[] newArray;
254 | int length;
255 | int limit;
256 | int arrayLength2;
257 | int j;
258 | float[] newArray2;
259 | while (true) {
260 | tag = input.readTag();
261 | switch (tag) {
262 | case 0: {
263 | return this;
264 | }
265 | default: {
266 | if (!WireFormatNano.parseUnknownField(input, tag)) {
267 | return this;
268 | }
269 | continue;
270 | }
271 | case 10: {
272 | this.vendor_ = input.readString();
273 | this.bitField0_ |= 0x1;
274 | continue;
275 | }
276 | case 18: {
277 | this.model_ = input.readString();
278 | this.bitField0_ |= 0x2;
279 | continue;
280 | }
281 | case 29: {
282 | this.screenToLensDistance_ = input.readFloat();
283 | this.bitField0_ |= 0x4;
284 | continue;
285 | }
286 | case 37: {
287 | this.interLensDistance_ = input.readFloat();
288 | this.bitField0_ |= 0x8;
289 | continue;
290 | }
291 | case 45: {
292 | arrayLength = WireFormatNano.getRepeatedFieldArrayLength(input, 45);
293 | i = ((this.leftEyeFieldOfViewAngles == null) ? 0 : this.leftEyeFieldOfViewAngles.length);
294 | newArray = new float[i + arrayLength];
295 | if (i != 0) {
296 | System.arraycopy(this.leftEyeFieldOfViewAngles, 0, newArray, 0, i);
297 | }
298 | while (i < newArray.length - 1) {
299 | newArray[i] = input.readFloat();
300 | input.readTag();
301 | ++i;
302 | }
303 | newArray[i] = input.readFloat();
304 | this.leftEyeFieldOfViewAngles = newArray;
305 | continue;
306 | }
307 | case 42: {
308 | length = input.readRawVarint32();
309 | limit = input.pushLimit(length);
310 | arrayLength2 = length / 4;
311 | j = ((this.leftEyeFieldOfViewAngles == null) ? 0 : this.leftEyeFieldOfViewAngles.length);
312 | newArray2 = new float[j + arrayLength2];
313 | if (j != 0) {
314 | System.arraycopy(this.leftEyeFieldOfViewAngles, 0, newArray2, 0, j);
315 | }
316 | while (j < newArray2.length) {
317 | newArray2[j] = input.readFloat();
318 | ++j;
319 | }
320 | this.leftEyeFieldOfViewAngles = newArray2;
321 | input.popLimit(limit);
322 | continue;
323 | }
324 | case 53: {
325 | this.trayBottomToLensHeight_ = input.readFloat();
326 | this.bitField0_ |= 0x10;
327 | continue;
328 | }
329 | case 61: {
330 | arrayLength = WireFormatNano.getRepeatedFieldArrayLength(input, 61);
331 | i = ((this.distortionCoefficients == null) ? 0 : this.distortionCoefficients.length);
332 | newArray = new float[i + arrayLength];
333 | if (i != 0) {
334 | System.arraycopy(this.distortionCoefficients, 0, newArray, 0, i);
335 | }
336 | while (i < newArray.length - 1) {
337 | newArray[i] = input.readFloat();
338 | input.readTag();
339 | ++i;
340 | }
341 | newArray[i] = input.readFloat();
342 | this.distortionCoefficients = newArray;
343 | continue;
344 | }
345 | case 58: {
346 | length = input.readRawVarint32();
347 | limit = input.pushLimit(length);
348 | arrayLength2 = length / 4;
349 | j = ((this.distortionCoefficients == null) ? 0 : this.distortionCoefficients.length);
350 | newArray2 = new float[j + arrayLength2];
351 | if (j != 0) {
352 | System.arraycopy(this.distortionCoefficients, 0, newArray2, 0, j);
353 | }
354 | while (j < newArray2.length) {
355 | newArray2[j] = input.readFloat();
356 | ++j;
357 | }
358 | this.distortionCoefficients = newArray2;
359 | input.popLimit(limit);
360 | continue;
361 | }
362 | case 80: {
363 | this.hasMagnet_ = input.readBool();
364 | this.bitField0_ |= 0x20;
365 | continue;
366 | }
367 | }
368 | }
369 | }
370 |
371 | public static DeviceParams parseFrom(byte[] data) throws InvalidProtocolBufferNanoException {
372 | return (DeviceParams)MessageNano.mergeFrom((MessageNano)new DeviceParams(), data);
373 | }
374 |
375 | public static DeviceParams parseFrom(CodedInputByteBufferNano input) throws IOException {
376 | return new DeviceParams().mergeFrom(input);
377 | }
378 | }
379 | }
380 |
--------------------------------------------------------------------------------
/library/src/main/java/com/google/vrtoolkit/cardboard/proto/Phone.java:
--------------------------------------------------------------------------------
1 | package com.google.vrtoolkit.cardboard.proto;
2 |
3 | import java.io.*;
4 | import com.google.protobuf.nano.*;
5 |
6 | public interface Phone {
7 | public static final class PhoneParams extends MessageNano {
8 | private static volatile PhoneParams[] _emptyArray;
9 | private int bitField0_;
10 | private float xPpi_;
11 | private float yPpi_;
12 | private float bottomBezelHeight_;
13 | public float[] gyroBias;
14 |
15 | public static PhoneParams[] emptyArray() {
16 | if (PhoneParams._emptyArray == null) {
17 | synchronized (InternalNano.LAZY_INIT_LOCK) {
18 | if (PhoneParams._emptyArray == null) {
19 | PhoneParams._emptyArray = new PhoneParams[0];
20 | }
21 | }
22 | }
23 | return PhoneParams._emptyArray;
24 | }
25 |
26 | public float getXPpi() {
27 | return this.xPpi_;
28 | }
29 |
30 | public PhoneParams setXPpi(float value) {
31 | this.xPpi_ = value;
32 | this.bitField0_ |= 0x1;
33 | return this;
34 | }
35 |
36 | public boolean hasXPpi() {
37 | return (this.bitField0_ & 0x1) != 0x0;
38 | }
39 |
40 | public PhoneParams clearXPpi() {
41 | this.xPpi_ = 0.0f;
42 | this.bitField0_ &= 0xFFFFFFFE;
43 | return this;
44 | }
45 |
46 | public float getYPpi() {
47 | return this.yPpi_;
48 | }
49 |
50 | public PhoneParams setYPpi(float value) {
51 | this.yPpi_ = value;
52 | this.bitField0_ |= 0x2;
53 | return this;
54 | }
55 |
56 | public boolean hasYPpi() {
57 | return (this.bitField0_ & 0x2) != 0x0;
58 | }
59 |
60 | public PhoneParams clearYPpi() {
61 | this.yPpi_ = 0.0f;
62 | this.bitField0_ &= 0xFFFFFFFD;
63 | return this;
64 | }
65 |
66 | public float getBottomBezelHeight() {
67 | return this.bottomBezelHeight_;
68 | }
69 |
70 | public PhoneParams setBottomBezelHeight(float value) {
71 | this.bottomBezelHeight_ = value;
72 | this.bitField0_ |= 0x4;
73 | return this;
74 | }
75 |
76 | public boolean hasBottomBezelHeight() {
77 | return (this.bitField0_ & 0x4) != 0x0;
78 | }
79 |
80 | public PhoneParams clearBottomBezelHeight() {
81 | this.bottomBezelHeight_ = 0.0f;
82 | this.bitField0_ &= 0xFFFFFFFB;
83 | return this;
84 | }
85 |
86 | public PhoneParams() {
87 | super();
88 | this.clear();
89 | }
90 |
91 | public PhoneParams clear() {
92 | this.bitField0_ = 0;
93 | this.xPpi_ = 0.0f;
94 | this.yPpi_ = 0.0f;
95 | this.bottomBezelHeight_ = 0.0f;
96 | this.gyroBias = WireFormatNano.EMPTY_FLOAT_ARRAY;
97 | this.cachedSize = -1;
98 | return this;
99 | }
100 |
101 | public void writeTo(CodedOutputByteBufferNano output) throws IOException {
102 | int dataSize;
103 | if ((this.bitField0_ & 0x1) != 0x0) {
104 | output.writeFloat(1, this.xPpi_);
105 | }
106 | if ((this.bitField0_ & 0x2) != 0x0) {
107 | output.writeFloat(2, this.yPpi_);
108 | }
109 | if ((this.bitField0_ & 0x4) != 0x0) {
110 | output.writeFloat(3, this.bottomBezelHeight_);
111 | }
112 | if (this.gyroBias != null && this.gyroBias.length > 0) {
113 | dataSize = 4 * this.gyroBias.length;
114 | output.writeRawVarint32(34);
115 | output.writeRawVarint32(dataSize);
116 | for (int i = 0; i < this.gyroBias.length; ++i) {
117 | output.writeFloatNoTag(this.gyroBias[i]);
118 | }
119 | }
120 | super.writeTo(output);
121 | }
122 |
123 | protected int computeSerializedSize() {
124 | int size;
125 | int dataSize;
126 | size = super.computeSerializedSize();
127 | if ((this.bitField0_ & 0x1) != 0x0) {
128 | size += CodedOutputByteBufferNano.computeFloatSize(1, this.xPpi_);
129 | }
130 | if ((this.bitField0_ & 0x2) != 0x0) {
131 | size += CodedOutputByteBufferNano.computeFloatSize(2, this.yPpi_);
132 | }
133 | if ((this.bitField0_ & 0x4) != 0x0) {
134 | size += CodedOutputByteBufferNano.computeFloatSize(3, this.bottomBezelHeight_);
135 | }
136 | if (this.gyroBias != null && this.gyroBias.length > 0) {
137 | dataSize = 4 * this.gyroBias.length;
138 | size += dataSize;
139 | size = ++size + CodedOutputByteBufferNano.computeRawVarint32Size(dataSize);
140 | }
141 | return size;
142 | }
143 |
144 | public PhoneParams mergeFrom(CodedInputByteBufferNano input) throws IOException {
145 | int tag;
146 | int arrayLength;
147 | int i;
148 | float[] newArray;
149 | int length;
150 | int limit;
151 | int arrayLength2;
152 | int j;
153 | float[] newArray2;
154 | while (true) {
155 | tag = input.readTag();
156 | switch (tag) {
157 | case 0: {
158 | return this;
159 | }
160 | default: {
161 | if (!WireFormatNano.parseUnknownField(input, tag)) {
162 | return this;
163 | }
164 | continue;
165 | }
166 | case 13: {
167 | this.xPpi_ = input.readFloat();
168 | this.bitField0_ |= 0x1;
169 | continue;
170 | }
171 | case 21: {
172 | this.yPpi_ = input.readFloat();
173 | this.bitField0_ |= 0x2;
174 | continue;
175 | }
176 | case 29: {
177 | this.bottomBezelHeight_ = input.readFloat();
178 | this.bitField0_ |= 0x4;
179 | continue;
180 | }
181 | case 37: {
182 | arrayLength = WireFormatNano.getRepeatedFieldArrayLength(input, 37);
183 | i = ((this.gyroBias == null) ? 0 : this.gyroBias.length);
184 | newArray = new float[i + arrayLength];
185 | if (i != 0) {
186 | System.arraycopy(this.gyroBias, 0, newArray, 0, i);
187 | }
188 | while (i < newArray.length - 1) {
189 | newArray[i] = input.readFloat();
190 | input.readTag();
191 | ++i;
192 | }
193 | newArray[i] = input.readFloat();
194 | this.gyroBias = newArray;
195 | continue;
196 | }
197 | case 34: {
198 | length = input.readRawVarint32();
199 | limit = input.pushLimit(length);
200 | arrayLength2 = length / 4;
201 | j = ((this.gyroBias == null) ? 0 : this.gyroBias.length);
202 | newArray2 = new float[j + arrayLength2];
203 | if (j != 0) {
204 | System.arraycopy(this.gyroBias, 0, newArray2, 0, j);
205 | }
206 | while (j < newArray2.length) {
207 | newArray2[j] = input.readFloat();
208 | ++j;
209 | }
210 | this.gyroBias = newArray2;
211 | input.popLimit(limit);
212 | continue;
213 | }
214 | }
215 | }
216 | }
217 |
218 | public static PhoneParams parseFrom(byte[] data) throws InvalidProtocolBufferNanoException {
219 | return (PhoneParams)MessageNano.mergeFrom((MessageNano)new PhoneParams(), data);
220 | }
221 |
222 | public static PhoneParams parseFrom(CodedInputByteBufferNano input) throws IOException {
223 | return new PhoneParams().mergeFrom(input);
224 | }
225 | }
226 | }
227 |
--------------------------------------------------------------------------------
/library/src/main/java/com/google/vrtoolkit/cardboard/sensors/Clock.java:
--------------------------------------------------------------------------------
1 | package com.google.vrtoolkit.cardboard.sensors;
2 |
3 | public interface Clock {
4 | long nanoTime();
5 | }
6 |
--------------------------------------------------------------------------------
/library/src/main/java/com/google/vrtoolkit/cardboard/sensors/DeviceSensorLooper.java:
--------------------------------------------------------------------------------
1 | package com.google.vrtoolkit.cardboard.sensors;
2 |
3 | import java.util.*;
4 | import android.hardware.*;
5 | import android.os.*;
6 |
7 | public class DeviceSensorLooper implements SensorEventProvider {
8 | private boolean mIsRunning;
9 | private SensorManager mSensorManager;
10 | private Looper mSensorLooper;
11 | private SensorEventListener mSensorEventListener;
12 | private final ArrayList mRegisteredListeners;
13 | private static final int[] INPUT_SENSORS;
14 |
15 | public DeviceSensorLooper(final SensorManager sensorManager) {
16 | super();
17 | this.mRegisteredListeners = new ArrayList();
18 | this.mSensorManager = sensorManager;
19 | }
20 |
21 | @Override
22 | public void start() {
23 | if (this.mIsRunning) {
24 | return;
25 | }
26 | this.mSensorEventListener = (SensorEventListener)new SensorEventListener() {
27 | public void onSensorChanged(final SensorEvent event) {
28 | for (final SensorEventListener listener : DeviceSensorLooper.this.mRegisteredListeners) {
29 | synchronized (listener) {
30 | listener.onSensorChanged(event);
31 | }
32 | }
33 | }
34 |
35 | public void onAccuracyChanged(final Sensor sensor, final int accuracy) {
36 | for (final SensorEventListener listener : DeviceSensorLooper.this.mRegisteredListeners) {
37 | synchronized (listener) {
38 | listener.onAccuracyChanged(sensor, accuracy);
39 | }
40 | }
41 | }
42 | };
43 | final HandlerThread sensorThread = new HandlerThread("sensor") {
44 | protected void onLooperPrepared() {
45 | final Handler handler = new Handler(Looper.myLooper());
46 | for (final int sensorType : DeviceSensorLooper.INPUT_SENSORS) {
47 | final Sensor sensor = DeviceSensorLooper.this.mSensorManager.getDefaultSensor(sensorType);
48 | DeviceSensorLooper.this.mSensorManager.registerListener(DeviceSensorLooper.this.mSensorEventListener, sensor, 0, handler);
49 | }
50 | }
51 | };
52 | sensorThread.start();
53 | this.mSensorLooper = sensorThread.getLooper();
54 | this.mIsRunning = true;
55 | }
56 |
57 | @Override
58 | public void stop() {
59 | if (!this.mIsRunning) {
60 | return;
61 | }
62 | this.mSensorManager.unregisterListener(this.mSensorEventListener);
63 | this.mSensorEventListener = null;
64 | this.mSensorLooper.quit();
65 | this.mSensorLooper = null;
66 | this.mIsRunning = false;
67 | }
68 |
69 | @Override
70 | public void registerListener(final SensorEventListener listener) {
71 | synchronized (this.mRegisteredListeners) {
72 | this.mRegisteredListeners.add(listener);
73 | }
74 | }
75 |
76 | @Override
77 | public void unregisterListener(final SensorEventListener listener) {
78 | synchronized (this.mRegisteredListeners) {
79 | this.mRegisteredListeners.remove(listener);
80 | }
81 | }
82 |
83 | static {
84 | INPUT_SENSORS = new int[] { 1, 4 };
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/library/src/main/java/com/google/vrtoolkit/cardboard/sensors/HeadTracker.java:
--------------------------------------------------------------------------------
1 | package com.google.vrtoolkit.cardboard.sensors;
2 |
3 | import com.google.vrtoolkit.cardboard.sensors.internal.*;
4 | import android.content.*;
5 | import android.view.*;
6 | import android.opengl.*;
7 | import android.hardware.*;
8 | import java.util.concurrent.*;
9 |
10 | public class HeadTracker implements SensorEventListener {
11 | private static final float DEFAULT_NECK_HORIZONTAL_OFFSET = 0.08f;
12 | private static final float DEFAULT_NECK_VERTICAL_OFFSET = 0.075f;
13 | private static final boolean DEFAULT_NECK_MODEL_ENABLED = false;
14 | private final Display mDisplay;
15 | private final float[] mEkfToHeadTracker;
16 | private final float[] mSensorToDisplay;
17 | private float mDisplayRotation;
18 | private final float[] mNeckModelTranslation;
19 | private final float[] mTmpHeadView;
20 | private final float[] mTmpHeadView2;
21 | private boolean mNeckModelEnabled;
22 | private volatile boolean mTracking;
23 | private OrientationEKF mTracker;
24 | private SensorEventProvider mSensorEventProvider;
25 | private Clock mClock;
26 | private long mLatestGyroEventClockTimeNs;
27 | private final Vector3d mGyroBias;
28 | private final Vector3d mLatestGyro;
29 | private final Vector3d mLatestAcc;
30 |
31 | public static HeadTracker createFromContext(final Context context) {
32 | final SensorManager sensorManager = (SensorManager)context.getSystemService("sensor");
33 | final Display display = ((WindowManager)context.getSystemService("window")).getDefaultDisplay();
34 | return new HeadTracker(new DeviceSensorLooper(sensorManager), new SystemClock(), display);
35 | }
36 |
37 | public HeadTracker(final SensorEventProvider sensorEventProvider, final Clock clock, final Display display) {
38 | super();
39 | this.mEkfToHeadTracker = new float[16];
40 | this.mSensorToDisplay = new float[16];
41 | this.mDisplayRotation = Float.NaN;
42 | this.mNeckModelTranslation = new float[16];
43 | this.mTmpHeadView = new float[16];
44 | this.mTmpHeadView2 = new float[16];
45 | this.mNeckModelEnabled = DEFAULT_NECK_MODEL_ENABLED;
46 | this.mGyroBias = new Vector3d();
47 | this.mLatestGyro = new Vector3d();
48 | this.mLatestAcc = new Vector3d();
49 | this.mClock = clock;
50 | this.mSensorEventProvider = sensorEventProvider;
51 | this.mTracker = new OrientationEKF();
52 | this.mDisplay = display;
53 | Matrix.setIdentityM(this.mNeckModelTranslation, 0);
54 | Matrix.translateM(this.mNeckModelTranslation, 0,
55 | 0.0f, -DEFAULT_NECK_VERTICAL_OFFSET, DEFAULT_NECK_HORIZONTAL_OFFSET);
56 | }
57 |
58 | public void onSensorChanged(final SensorEvent event) {
59 | if (event.sensor.getType() == 1) {
60 | this.mLatestAcc.set(event.values[0], event.values[1], event.values[2]);
61 | this.mTracker.processAcc(this.mLatestAcc, event.timestamp);
62 | }
63 | else if (event.sensor.getType() == 4) {
64 | this.mLatestGyroEventClockTimeNs = this.mClock.nanoTime();
65 | this.mLatestGyro.set(event.values[0], event.values[1], event.values[2]);
66 | Vector3d.sub(this.mLatestGyro, this.mGyroBias, this.mLatestGyro);
67 | this.mTracker.processGyro(this.mLatestGyro, event.timestamp);
68 | }
69 | }
70 |
71 | public void onAccuracyChanged(final Sensor sensor, final int accuracy) {
72 | }
73 |
74 | public void startTracking() {
75 | if (this.mTracking) {
76 | return;
77 | }
78 | this.mTracker.reset();
79 | this.mSensorEventProvider.registerListener((SensorEventListener)this);
80 | this.mSensorEventProvider.start();
81 | this.mTracking = true;
82 | }
83 |
84 | public void stopTracking() {
85 | if (!this.mTracking) {
86 | return;
87 | }
88 | this.mSensorEventProvider.unregisterListener((SensorEventListener)this);
89 | this.mSensorEventProvider.stop();
90 | this.mTracking = false;
91 | }
92 |
93 | public void setGyroBias(final float[] gyroBias) {
94 | if (gyroBias == null) {
95 | this.mGyroBias.setZero();
96 | return;
97 | }
98 | if (gyroBias.length != 3) {
99 | throw new IllegalArgumentException("Gyro bias should be an array of 3 values");
100 | }
101 | this.mGyroBias.set(gyroBias[0], gyroBias[1], gyroBias[2]);
102 | }
103 |
104 | public void setNeckModelEnabled(final boolean enabled) {
105 | this.mNeckModelEnabled = enabled;
106 | }
107 |
108 | public void getLastHeadView(final float[] headView, final int offset) {
109 | if (offset + 16 > headView.length) {
110 | throw new IllegalArgumentException("Not enough space to write the result");
111 | }
112 | float rotation = 0.0f;
113 | switch (this.mDisplay.getRotation()) {
114 | case 0: {
115 | rotation = 0.0f;
116 | break;
117 | }
118 | case 1: {
119 | rotation = 90.0f;
120 | break;
121 | }
122 | case 2: {
123 | rotation = 180.0f;
124 | break;
125 | }
126 | case 3: {
127 | rotation = 270.0f;
128 | break;
129 | }
130 | }
131 | if (rotation != this.mDisplayRotation) {
132 | this.mDisplayRotation = rotation;
133 | Matrix.setRotateEulerM(this.mSensorToDisplay, 0, 0.0f, 0.0f, -rotation);
134 | Matrix.setRotateEulerM(this.mEkfToHeadTracker, 0, -90.0f, 0.0f, rotation);
135 | }
136 | synchronized (this.mTracker) {
137 | final double secondsSinceLastGyroEvent = TimeUnit.NANOSECONDS.toSeconds(this.mClock.nanoTime() - this.mLatestGyroEventClockTimeNs);
138 | final double secondsToPredictForward = secondsSinceLastGyroEvent + 1.0/30;
139 | final double[] mat = this.mTracker.getPredictedGLMatrix(secondsToPredictForward);
140 | for (int i = 0; i < headView.length; ++i) {
141 | this.mTmpHeadView[i] = (float)mat[i];
142 | }
143 | }
144 | Matrix.multiplyMM(this.mTmpHeadView2, 0, this.mSensorToDisplay, 0, this.mTmpHeadView, 0);
145 | Matrix.multiplyMM(headView, offset, this.mTmpHeadView2, 0, this.mEkfToHeadTracker, 0);
146 | if (this.mNeckModelEnabled) {
147 | Matrix.multiplyMM(this.mTmpHeadView, 0, this.mNeckModelTranslation, 0, headView, offset);
148 | Matrix.translateM(headView, offset, this.mTmpHeadView, 0, 0.0f, DEFAULT_NECK_VERTICAL_OFFSET, 0.0f);
149 | }
150 | }
151 | }
152 |
--------------------------------------------------------------------------------
/library/src/main/java/com/google/vrtoolkit/cardboard/sensors/MagnetSensor.java:
--------------------------------------------------------------------------------
1 | package com.google.vrtoolkit.cardboard.sensors;
2 |
3 | import android.content.Context;
4 | import android.hardware.Sensor;
5 | import android.hardware.SensorEvent;
6 | import android.hardware.SensorEventListener;
7 | import android.hardware.SensorManager;
8 | import android.os.Build;
9 | import android.os.Handler;
10 | import android.os.Looper;
11 |
12 | import java.lang.ref.WeakReference;
13 | import java.util.ArrayList;
14 | import java.util.Arrays;
15 |
16 | public class MagnetSensor {
17 | private static final String HTC_ONE_MODEL = "HTC One";
18 | private TriggerDetector mDetector;
19 | private Thread mDetectorThread;
20 |
21 | public MagnetSensor(final Context context) {
22 | super();
23 | if (HTC_ONE_MODEL.equals(Build.MODEL)) {
24 | mDetector = new VectorTriggerDetector(context);
25 | } else {
26 | mDetector = new ThresholdTriggerDetector(context);
27 | }
28 | }
29 |
30 | public void start() {
31 | mDetectorThread = new Thread(mDetector);
32 | mDetectorThread.start();
33 | }
34 |
35 | public void stop() {
36 | if (mDetectorThread != null) {
37 | mDetectorThread.interrupt();
38 | mDetector.stop();
39 | }
40 | }
41 |
42 | public void setOnCardboardTriggerListener(final OnCardboardTriggerListener listener) {
43 | mDetector.setOnCardboardTriggerListener(listener, new Handler());
44 | }
45 |
46 | private abstract static class TriggerDetector implements Runnable, SensorEventListener {
47 | protected static final String TAG = "TriggerDetector";
48 | protected SensorManager mSensorManager;
49 | protected Sensor mMagnetometer;
50 | protected WeakReference mListenerRef;
51 | protected Handler mHandler;
52 |
53 | public TriggerDetector(final Context context) {
54 | super();
55 | mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
56 | mMagnetometer = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
57 | }
58 |
59 | public synchronized void setOnCardboardTriggerListener(
60 | final OnCardboardTriggerListener listener, final Handler handler) {
61 | mListenerRef = new WeakReference<>(listener);
62 | mHandler = handler;
63 | }
64 |
65 | protected void handleButtonPressed() {
66 | synchronized (this) {
67 | final OnCardboardTriggerListener listener = mListenerRef != null ?
68 | mListenerRef.get() : null;
69 | if (listener != null) {
70 | mHandler.post(new Runnable() {
71 | @Override
72 | public void run() {
73 | listener.onCardboardTrigger();
74 | }
75 | });
76 | }
77 | }
78 | }
79 |
80 | @Override
81 | public void run() {
82 | Looper.prepare();
83 | mSensorManager.registerListener(this, this.mMagnetometer, 0);
84 | Looper.loop();
85 | }
86 |
87 | public void stop() {
88 | mSensorManager.unregisterListener(this);
89 | }
90 |
91 | public void onSensorChanged(final SensorEvent event) {
92 | }
93 |
94 | public void onAccuracyChanged(final Sensor sensor, final int accuracy) {
95 | }
96 | }
97 |
98 | private static class ThresholdTriggerDetector extends TriggerDetector {
99 | private static final String TAG = "ThresholdTriggerDetector";
100 | private static final long NS_SEGMENT_SIZE = 200000000L;
101 | private static final long NS_WINDOW_SIZE = 400000000L;
102 | private static final long NS_WAIT_TIME = 350000000L;
103 | private long mLastFiring;
104 | private static int mT1;
105 | private static int mT2;
106 | private ArrayList mSensorData;
107 | private ArrayList mSensorTimes;
108 |
109 | public ThresholdTriggerDetector(final Context context) {
110 | super(context);
111 | mLastFiring = 0L;
112 | mSensorData = new ArrayList<>();
113 | mSensorTimes = new ArrayList<>();
114 | }
115 |
116 | public ThresholdTriggerDetector(final Context context, final int t1, final int t2) {
117 | super(context);
118 | mLastFiring = 0L;
119 | mSensorData = new ArrayList<>();
120 | mSensorTimes = new ArrayList<>();
121 | ThresholdTriggerDetector.mT1 = t1;
122 | ThresholdTriggerDetector.mT2 = t2;
123 | }
124 |
125 | private void addData(final float[] values, final long time) {
126 | mSensorData.add(values);
127 | mSensorTimes.add(time);
128 | while (mSensorTimes.get(0) < time - NS_WINDOW_SIZE) {
129 | mSensorData.remove(0);
130 | mSensorTimes.remove(0);
131 | }
132 | evaluateModel(time);
133 | }
134 |
135 | private void evaluateModel(final long time) {
136 | if (time - mLastFiring < NS_WAIT_TIME || mSensorData.size() < 2) {
137 | return;
138 | }
139 | final float[] baseline = mSensorData.get(mSensorData.size() - 1);
140 | int startSecondSegment = 0;
141 | for (int i = 0; i < this.mSensorTimes.size(); ++i) {
142 | if (time - mSensorTimes.get(i) < NS_SEGMENT_SIZE) {
143 | startSecondSegment = i;
144 | break;
145 | }
146 | }
147 | final float[] offsets = new float[mSensorData.size()];
148 | computeOffsets(offsets, baseline);
149 | final float min1 = computeMinimum(Arrays.copyOfRange(offsets, 0, startSecondSegment));
150 | final float max2 = computeMaximum(Arrays.copyOfRange(
151 | offsets, startSecondSegment, mSensorData.size()));
152 | if (min1 < ThresholdTriggerDetector.mT1 && max2 > ThresholdTriggerDetector.mT2) {
153 | mLastFiring = time;
154 | handleButtonPressed();
155 | }
156 | }
157 |
158 | private void computeOffsets(final float[] offsets, final float[] baseline) {
159 | for (int i = 0; i < mSensorData.size(); ++i) {
160 | final float[] point = mSensorData.get(i);
161 | final float[] o = {
162 | point[0] - baseline[0],
163 | point[1] - baseline[1],
164 | point[2] - baseline[2]
165 | };
166 | final float magnitude = (float) Math.sqrt(o[0] * o[0] + o[1] * o[1] + o[2] * o[2]);
167 | offsets[i] = magnitude;
168 | }
169 | }
170 |
171 | private float computeMaximum(final float[] offsets) {
172 | float max = Float.NEGATIVE_INFINITY;
173 | for (final float o : offsets) {
174 | max = Math.max(o, max);
175 | }
176 | return max;
177 | }
178 |
179 | private float computeMinimum(final float[] offsets) {
180 | float min = Float.POSITIVE_INFINITY;
181 | for (final float o : offsets) {
182 | min = Math.min(o, min);
183 | }
184 | return min;
185 | }
186 |
187 | @Override
188 | public void onSensorChanged(final SensorEvent event) {
189 | if (event.sensor.equals(this.mMagnetometer)) {
190 | final float[] values = event.values;
191 | if (values[0] == 0.0f && values[1] == 0.0f && values[2] == 0.0f) {
192 | return;
193 | }
194 | addData(event.values.clone(), event.timestamp);
195 | }
196 | }
197 |
198 | @Override
199 | public void onAccuracyChanged(final Sensor sensor, final int accuracy) {
200 | }
201 |
202 | static {
203 | ThresholdTriggerDetector.mT1 = 30;
204 | ThresholdTriggerDetector.mT2 = 130;
205 | }
206 | }
207 |
208 | private static class VectorTriggerDetector extends TriggerDetector {
209 | private static final String TAG = "ThresholdTriggerDetector";
210 | private static final long NS_REFRESH_TIME = 350000000L;
211 | private static final long NS_THROWAWAY_SIZE = 500000000L;
212 | private static final long NS_WAIT_SIZE = 100000000L;
213 | private long mLastFiring;
214 | private static int mXThreshold;
215 | private static int mYThreshold;
216 | private static int mZThreshold;
217 | private ArrayList mSensorData;
218 | private ArrayList mSensorTimes;
219 |
220 | public VectorTriggerDetector(final Context context) {
221 | super(context);
222 | mLastFiring = 0L;
223 | mSensorData = new ArrayList<>();
224 | mSensorTimes = new ArrayList<>();
225 | VectorTriggerDetector.mXThreshold = -3;
226 | VectorTriggerDetector.mYThreshold = 15;
227 | VectorTriggerDetector.mZThreshold = 6;
228 | }
229 |
230 | public VectorTriggerDetector(final Context context, final int xThreshold,
231 | final int yThreshold, final int zThreshold) {
232 | super(context);
233 | mLastFiring = 0L;
234 | mSensorData = new ArrayList<>();
235 | mSensorTimes = new ArrayList<>();
236 | VectorTriggerDetector.mXThreshold = xThreshold;
237 | VectorTriggerDetector.mYThreshold = yThreshold;
238 | VectorTriggerDetector.mZThreshold = zThreshold;
239 | }
240 |
241 | private void addData(final float[] values, final long time) {
242 | mSensorData.add(values);
243 | mSensorTimes.add(time);
244 | while (mSensorTimes.get(0) < time - NS_THROWAWAY_SIZE) {
245 | mSensorData.remove(0);
246 | mSensorTimes.remove(0);
247 | }
248 | evaluateModel(time);
249 | }
250 |
251 | private void evaluateModel(final long time) {
252 | if (time - mLastFiring < NS_REFRESH_TIME || mSensorData.size() < 2) {
253 | return;
254 | }
255 | int baseIndex = 0;
256 | for (int i = 1; i < mSensorTimes.size(); ++i) {
257 | if (time - mSensorTimes.get(i) < NS_WAIT_SIZE) {
258 | baseIndex = i;
259 | break;
260 | }
261 | }
262 | final float[] oldValues = mSensorData.get(baseIndex);
263 | final float[] currentValues = mSensorData.get(mSensorData.size() - 1);
264 | if (currentValues[0] - oldValues[0] < VectorTriggerDetector.mXThreshold
265 | && currentValues[1] - oldValues[1] > VectorTriggerDetector.mYThreshold
266 | && currentValues[2] - oldValues[2] > VectorTriggerDetector.mZThreshold) {
267 | mLastFiring = time;
268 | handleButtonPressed();
269 | }
270 | }
271 |
272 | @Override
273 | public void onSensorChanged(final SensorEvent event) {
274 | if (event.sensor.equals(mMagnetometer)) {
275 | final float[] values = event.values;
276 | if (values[0] == 0.0f && values[1] == 0.0f && values[2] == 0.0f) {
277 | return;
278 | }
279 | addData(event.values.clone(), event.timestamp);
280 | }
281 | }
282 |
283 | @Override
284 | public void onAccuracyChanged(final Sensor sensor, final int accuracy) {
285 | }
286 | }
287 |
288 | public interface OnCardboardTriggerListener {
289 | void onCardboardTrigger();
290 | }
291 | }
292 |
--------------------------------------------------------------------------------
/library/src/main/java/com/google/vrtoolkit/cardboard/sensors/NfcSensor.java:
--------------------------------------------------------------------------------
1 | package com.google.vrtoolkit.cardboard.sensors;
2 |
3 | import android.content.*;
4 | import android.os.*;
5 | import java.io.*;
6 | import android.net.*;
7 | import android.nfc.*;
8 | import android.nfc.tech.*;
9 | import android.util.*;
10 | import android.app.*;
11 | import com.google.vrtoolkit.cardboard.*;
12 | import java.util.*;
13 |
14 | public class NfcSensor {
15 | private static final String TAG = "NfcSensor";
16 | private static final int MAX_CONNECTION_FAILURES = 1;
17 | private static final long NFC_POLLING_INTERVAL_MS = 250L;
18 | private static NfcSensor sInstance;
19 | private final Context mContext;
20 | private final NfcAdapter mNfcAdapter;
21 | private final Object mTagLock;
22 | private final List mListeners;
23 | private IntentFilter[] mNfcIntentFilters;
24 | private Ndef mCurrentNdef;
25 | private Tag mCurrentTag;
26 | private boolean mCurrentTagIsCardboard;
27 | private Timer mNfcDisconnectTimer;
28 | private int mTagConnectionFailures;
29 |
30 | public static NfcSensor getInstance(final Context context) {
31 | if (NfcSensor.sInstance == null) {
32 | NfcSensor.sInstance = new NfcSensor(context);
33 | }
34 | return NfcSensor.sInstance;
35 | }
36 |
37 | private NfcSensor(final Context context) {
38 | super();
39 | this.mContext = context.getApplicationContext();
40 | this.mNfcAdapter = NfcAdapter.getDefaultAdapter(this.mContext);
41 | this.mListeners = new ArrayList();
42 | this.mTagLock = new Object();
43 | if (this.mNfcAdapter == null) {
44 | return;
45 | }
46 | final IntentFilter ndefIntentFilter = new IntentFilter("android.nfc.action.NDEF_DISCOVERED");
47 | ndefIntentFilter.addAction("android.nfc.action.TECH_DISCOVERED");
48 | ndefIntentFilter.addAction("android.nfc.action.TAG_DISCOVERED");
49 | this.mNfcIntentFilters = new IntentFilter[] { ndefIntentFilter };
50 | this.mContext.registerReceiver((BroadcastReceiver)new BroadcastReceiver() {
51 | public void onReceive(final Context context, final Intent intent) {
52 | NfcSensor.this.onNfcIntent(intent);
53 | }
54 | }, ndefIntentFilter);
55 | }
56 |
57 | public void addOnCardboardNfcListener(final OnCardboardNfcListener listener) {
58 | if (listener == null) {
59 | return;
60 | }
61 | synchronized (this.mListeners) {
62 | for (final ListenerHelper helper : this.mListeners) {
63 | if (helper.getListener() == listener) {
64 | return;
65 | }
66 | }
67 | this.mListeners.add(new ListenerHelper(listener, new Handler()));
68 | }
69 | }
70 |
71 | public void removeOnCardboardNfcListener(final OnCardboardNfcListener listener) {
72 | if (listener == null) {
73 | return;
74 | }
75 | synchronized (this.mListeners) {
76 | for (final ListenerHelper helper : this.mListeners) {
77 | if (helper.getListener() == listener) {
78 | this.mListeners.remove(helper);
79 | }
80 | }
81 | }
82 | }
83 |
84 | public boolean isNfcSupported() {
85 | return this.mNfcAdapter != null;
86 | }
87 |
88 | public boolean isNfcEnabled() {
89 | return this.isNfcSupported() && this.mNfcAdapter.isEnabled();
90 | }
91 |
92 | public boolean isDeviceInCardboard() {
93 | synchronized (this.mTagLock) {
94 | return this.mCurrentTagIsCardboard;
95 | }
96 | }
97 |
98 | public NdefMessage getTagContents() {
99 | synchronized (this.mTagLock) {
100 | return (this.mCurrentNdef != null) ? this.mCurrentNdef.getCachedNdefMessage() : null;
101 | }
102 | }
103 |
104 | public NdefMessage getCurrentTagContents() throws TagLostException, IOException, FormatException {
105 | synchronized (this.mTagLock) {
106 | return (this.mCurrentNdef != null) ? this.mCurrentNdef.getNdefMessage() : null;
107 | }
108 | }
109 |
110 | public int getTagCapacity() {
111 | synchronized (this.mTagLock) {
112 | if (this.mCurrentNdef == null) {
113 | throw new IllegalStateException("No NFC tag");
114 | }
115 | return this.mCurrentNdef.getMaxSize();
116 | }
117 | }
118 |
119 | public void writeUri(final Uri uri) throws TagLostException, IOException, IllegalArgumentException {
120 | synchronized (this.mTagLock) {
121 | if (this.mCurrentTag == null) {
122 | throw new IllegalStateException("No NFC tag found");
123 | }
124 | NdefMessage currentMessage = null;
125 | NdefMessage newMessage = null;
126 | final NdefRecord newRecord = NdefRecord.createUri(uri);
127 | try {
128 | currentMessage = this.getCurrentTagContents();
129 | }
130 | catch (Exception e3) {
131 | currentMessage = this.getTagContents();
132 | }
133 | if (currentMessage != null) {
134 | final ArrayList newRecords = new ArrayList();
135 | boolean recordFound = false;
136 | for (final NdefRecord record : currentMessage.getRecords()) {
137 | if (this.isCardboardNdefRecord(record)) {
138 | if (!recordFound) {
139 | newRecords.add(newRecord);
140 | recordFound = true;
141 | }
142 | }
143 | else {
144 | newRecords.add(record);
145 | }
146 | }
147 | newMessage = new NdefMessage((NdefRecord[])newRecords.toArray(new NdefRecord[newRecords.size()]));
148 | }
149 | if (newMessage == null) {
150 | newMessage = new NdefMessage(new NdefRecord[] { newRecord });
151 | }
152 | Label_0432: {
153 | if (this.mCurrentNdef != null) {
154 | if (!this.mCurrentNdef.isConnected()) {
155 | this.mCurrentNdef.connect();
156 | }
157 | if (this.mCurrentNdef.getMaxSize() < newMessage.getByteArrayLength()) {
158 | throw new IllegalArgumentException(new StringBuilder(82).append("Not enough capacity in NFC tag. Capacity: ").append(this.mCurrentNdef.getMaxSize()).append(" bytes, ").append(newMessage.getByteArrayLength()).append(" required.").toString());
159 | }
160 | try {
161 | this.mCurrentNdef.writeNdefMessage(newMessage);
162 | break Label_0432;
163 | }
164 | catch (FormatException e) {
165 | final String s = "Internal error when writing to NFC tag: ";
166 | final String value = String.valueOf(e.toString());
167 | throw new RuntimeException((value.length() != 0) ? s.concat(value) : new String(s));
168 | }
169 | }
170 | final NdefFormatable ndef = NdefFormatable.get(this.mCurrentTag);
171 | if (ndef == null) {
172 | throw new IOException("Could not find a writable technology for the NFC tag");
173 | }
174 | Log.w("NfcSensor", "Ndef technology not available. Falling back to NdefFormattable.");
175 | try {
176 | ndef.connect();
177 | ndef.format(newMessage);
178 | ndef.close();
179 | }
180 | catch (FormatException e2) {
181 | final String s2 = "Internal error when writing to NFC tag: ";
182 | final String value2 = String.valueOf(e2.toString());
183 | throw new RuntimeException((value2.length() != 0) ? s2.concat(value2) : new String(s2));
184 | }
185 | }
186 | this.onNewNfcTag(this.mCurrentTag);
187 | }
188 | }
189 |
190 | public void onResume(final Activity activity) {
191 | if (!this.isNfcEnabled()) {
192 | return;
193 | }
194 | final Intent intent = new Intent("android.nfc.action.NDEF_DISCOVERED");
195 | intent.setPackage(activity.getPackageName());
196 | final PendingIntent pendingIntent = PendingIntent.getBroadcast(this.mContext, 0, intent, 0);
197 | this.mNfcAdapter.enableForegroundDispatch(activity, pendingIntent, this.mNfcIntentFilters, (String[][])null);
198 | }
199 |
200 | public void onPause(final Activity activity) {
201 | if (!this.isNfcEnabled()) {
202 | return;
203 | }
204 | this.mNfcAdapter.disableForegroundDispatch(activity);
205 | }
206 |
207 | public void onNfcIntent(final Intent intent) {
208 | if (!this.isNfcEnabled() || intent == null || !this.mNfcIntentFilters[0].matchAction(intent.getAction())) {
209 | return;
210 | }
211 | this.onNewNfcTag((Tag)intent.getParcelableExtra("android.nfc.extra.TAG"));
212 | }
213 |
214 | private void onNewNfcTag(final Tag nfcTag) {
215 | if (nfcTag == null) {
216 | return;
217 | }
218 | synchronized (this.mTagLock) {
219 | final Tag previousTag = this.mCurrentTag;
220 | final Ndef previousNdef = this.mCurrentNdef;
221 | final boolean previousTagWasCardboard = this.mCurrentTagIsCardboard;
222 | this.closeCurrentNfcTag();
223 | this.mCurrentTag = nfcTag;
224 | this.mCurrentNdef = Ndef.get(nfcTag);
225 | if (this.mCurrentNdef == null) {
226 | if (previousTagWasCardboard) {
227 | this.sendDisconnectionEvent();
228 | }
229 | return;
230 | }
231 | boolean isSameTag = false;
232 | if (previousNdef != null) {
233 | final byte[] tagId1 = this.mCurrentTag.getId();
234 | final byte[] tagId2 = previousTag.getId();
235 | isSameTag = (tagId1 != null && tagId2 != null && Arrays.equals(tagId1, tagId2));
236 | if (!isSameTag && previousTagWasCardboard) {
237 | this.sendDisconnectionEvent();
238 | }
239 | }
240 | NdefMessage nfcTagContents;
241 | try {
242 | this.mCurrentNdef.connect();
243 | nfcTagContents = this.mCurrentNdef.getCachedNdefMessage();
244 | }
245 | catch (Exception e) {
246 | final String s = "NfcSensor";
247 | final String s2 = "Error reading NFC tag: ";
248 | final String value = String.valueOf(e.toString());
249 | Log.e(s, (value.length() != 0) ? s2.concat(value) : new String(s2));
250 | if (isSameTag && previousTagWasCardboard) {
251 | this.sendDisconnectionEvent();
252 | }
253 | return;
254 | }
255 | this.mCurrentTagIsCardboard = this.isCardboardNdefMessage(nfcTagContents);
256 | if (!isSameTag && this.mCurrentTagIsCardboard) {
257 | synchronized (this.mListeners) {
258 | for (final ListenerHelper listener : this.mListeners) {
259 | listener.onInsertedIntoCardboard(CardboardDeviceParams.createFromNfcContents(nfcTagContents));
260 | }
261 | }
262 | }
263 | if (this.mCurrentTagIsCardboard) {
264 | this.mTagConnectionFailures = 0;
265 | (this.mNfcDisconnectTimer = new Timer("NFC disconnect timer")).schedule(new TimerTask() {
266 | @Override
267 | public void run() {
268 | synchronized (NfcSensor.this.mTagLock) {
269 | if (!NfcSensor.this.mCurrentNdef.isConnected()) {
270 | ++NfcSensor.this.mTagConnectionFailures;
271 | if (NfcSensor.this.mTagConnectionFailures > 1) {
272 | NfcSensor.this.closeCurrentNfcTag();
273 | NfcSensor.this.sendDisconnectionEvent();
274 | }
275 | }
276 | }
277 | }
278 | }, 250L, 250L);
279 | }
280 | }
281 | }
282 |
283 | private void closeCurrentNfcTag() {
284 | if (this.mNfcDisconnectTimer != null) {
285 | this.mNfcDisconnectTimer.cancel();
286 | }
287 | if (this.mCurrentNdef == null) {
288 | return;
289 | }
290 | try {
291 | this.mCurrentNdef.close();
292 | }
293 | catch (IOException e) {
294 | Log.w("NfcSensor", e.toString());
295 | }
296 | this.mCurrentTag = null;
297 | this.mCurrentNdef = null;
298 | this.mCurrentTagIsCardboard = false;
299 | }
300 |
301 | private void sendDisconnectionEvent() {
302 | synchronized (this.mListeners) {
303 | for (final ListenerHelper listener : this.mListeners) {
304 | listener.onRemovedFromCardboard();
305 | }
306 | }
307 | }
308 |
309 | private boolean isCardboardNdefMessage(final NdefMessage message) {
310 | if (message == null) {
311 | return false;
312 | }
313 | for (final NdefRecord record : message.getRecords()) {
314 | if (this.isCardboardNdefRecord(record)) {
315 | return true;
316 | }
317 | }
318 | return false;
319 | }
320 |
321 | private boolean isCardboardNdefRecord(final NdefRecord record) {
322 | if (record == null) {
323 | return false;
324 | }
325 | final Uri uri = record.toUri();
326 | return uri != null && CardboardDeviceParams.isCardboardUri(uri);
327 | }
328 |
329 | private static class ListenerHelper implements OnCardboardNfcListener
330 | {
331 | private OnCardboardNfcListener mListener;
332 | private Handler mHandler;
333 |
334 | public ListenerHelper(final OnCardboardNfcListener listener, final Handler handler) {
335 | super();
336 | this.mListener = listener;
337 | this.mHandler = handler;
338 | }
339 |
340 | public OnCardboardNfcListener getListener() {
341 | return this.mListener;
342 | }
343 |
344 | @Override
345 | public void onInsertedIntoCardboard(final CardboardDeviceParams deviceParams) {
346 | this.mHandler.post((Runnable)new Runnable() {
347 | @Override
348 | public void run() {
349 | ListenerHelper.this.mListener.onInsertedIntoCardboard(deviceParams);
350 | }
351 | });
352 | }
353 |
354 | @Override
355 | public void onRemovedFromCardboard() {
356 | this.mHandler.post((Runnable)new Runnable() {
357 | @Override
358 | public void run() {
359 | ListenerHelper.this.mListener.onRemovedFromCardboard();
360 | }
361 | });
362 | }
363 | }
364 |
365 | public interface OnCardboardNfcListener
366 | {
367 | void onInsertedIntoCardboard(CardboardDeviceParams p0);
368 |
369 | void onRemovedFromCardboard();
370 | }
371 | }
372 |
--------------------------------------------------------------------------------
/library/src/main/java/com/google/vrtoolkit/cardboard/sensors/SensorEventProvider.java:
--------------------------------------------------------------------------------
1 | package com.google.vrtoolkit.cardboard.sensors;
2 |
3 | import android.hardware.*;
4 |
5 | public interface SensorEventProvider {
6 | void start();
7 |
8 | void stop();
9 |
10 | void registerListener(SensorEventListener p0);
11 |
12 | void unregisterListener(SensorEventListener p0);
13 | }
14 |
--------------------------------------------------------------------------------
/library/src/main/java/com/google/vrtoolkit/cardboard/sensors/SystemClock.java:
--------------------------------------------------------------------------------
1 | package com.google.vrtoolkit.cardboard.sensors;
2 |
3 | public class SystemClock implements Clock {
4 | @Override
5 | public long nanoTime() {
6 | return System.nanoTime();
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/library/src/main/java/com/google/vrtoolkit/cardboard/sensors/internal/GyroBiasEstimator.java:
--------------------------------------------------------------------------------
1 | package com.google.vrtoolkit.cardboard.sensors.internal;
2 |
3 | public class GyroBiasEstimator {
4 | private static final float GYRO_SMOOTHING_FACTOR = 0.01f;
5 | private static final float ACC_SMOOTHING_FACTOR = 0.1f;
6 | private static final Vector3d UP_VECTOR;
7 | private static final float MIN_ACCEL_DOT_WITH_UP;
8 | private static final float MIN_ACCEL_LENGTH = 1.0E-4f;
9 | private static final float MAX_GYRO_DIFF = 0.01f;
10 | private static final long CALIBRATION_DURATION_NS = 5000000000L;
11 | private static final long MAX_DELAY_BETWEEN_EVENTS_NS = 100000000L;
12 | private final Vector3d mLastGyro;
13 | private final Vector3d mCurrGyro;
14 | private final Vector3d mGyroDiff;
15 | private final Vector3d mCurrAcc;
16 | private final Vector3d mAccSmoothed;
17 | private final Vector3d mAccNormalizedTmp;
18 | private float mGyroMagnitudeDiffSmoothed;
19 | private final Estimate mBiasEstimate;
20 | private long mCalibrationStartTimeNs;
21 | private long mLastGyroTimeNs;
22 | private long mLastAccTimeNs;
23 |
24 | public GyroBiasEstimator() {
25 | super();
26 | this.mLastGyro = new Vector3d();
27 | this.mCurrGyro = new Vector3d();
28 | this.mGyroDiff = new Vector3d();
29 | this.mCurrAcc = new Vector3d();
30 | this.mAccSmoothed = new Vector3d();
31 | this.mAccNormalizedTmp = new Vector3d();
32 | this.mBiasEstimate = new Estimate();
33 | this.mCalibrationStartTimeNs = -1L;
34 | this.mLastGyroTimeNs = -1L;
35 | this.mLastAccTimeNs = -1L;
36 | }
37 |
38 | public void processGyroscope(final Vector3d gyro, final long sensorTimeStamp) {
39 | if (this.mBiasEstimate.mState == Estimate.State.CALIBRATED) {
40 | return;
41 | }
42 | this.mCurrGyro.set(gyro);
43 | Vector3d.sub(this.mCurrGyro, this.mLastGyro, this.mGyroDiff);
44 | final float mCurrDiff = (float)this.mGyroDiff.length();
45 | this.mGyroMagnitudeDiffSmoothed = MAX_GYRO_DIFF * mCurrDiff + (1-MAX_GYRO_DIFF) * this.mGyroMagnitudeDiffSmoothed;
46 | this.mLastGyro.set(this.mCurrGyro);
47 | final boolean eventIsDelayed = sensorTimeStamp > this.mLastGyroTimeNs + MAX_DELAY_BETWEEN_EVENTS_NS;
48 | this.mLastGyroTimeNs = sensorTimeStamp;
49 | if (eventIsDelayed) {
50 | this.resetCalibration();
51 | return;
52 | }
53 | if (this.mBiasEstimate.mState == Estimate.State.CALIBRATING && sensorTimeStamp > this.mCalibrationStartTimeNs + CALIBRATION_DURATION_NS) {
54 | this.mBiasEstimate.mState = Estimate.State.CALIBRATED;
55 | return;
56 | }
57 | if (!this.canCalibrateGyro()) {
58 | this.resetCalibration();
59 | return;
60 | }
61 | this.startCalibration(sensorTimeStamp);
62 | }
63 |
64 | private void resetCalibration() {
65 | this.mBiasEstimate.mState = Estimate.State.UNCALIBRATED;
66 | this.mBiasEstimate.mBias.set(0.0, 0.0, 0.0);
67 | this.mCalibrationStartTimeNs = -1L;
68 | }
69 |
70 | private void startCalibration(final long gyroTimeStamp) {
71 | if (this.mBiasEstimate.mState != Estimate.State.CALIBRATING) {
72 | this.mBiasEstimate.mBias.set(this.mCurrGyro);
73 | this.mBiasEstimate.mState = Estimate.State.CALIBRATING;
74 | this.mCalibrationStartTimeNs = gyroTimeStamp;
75 | }
76 | else {
77 | smooth(this.mBiasEstimate.mBias, this.mCurrGyro, GYRO_SMOOTHING_FACTOR);
78 | }
79 | }
80 |
81 | public void processAccelerometer(final Vector3d acc, final long sensorTimeStamp) {
82 | if (this.mBiasEstimate.mState == Estimate.State.CALIBRATED) {
83 | return;
84 | }
85 | this.mCurrAcc.set(acc);
86 | final boolean eventIsDelayed = sensorTimeStamp > this.mLastAccTimeNs + MAX_DELAY_BETWEEN_EVENTS_NS;
87 | this.mLastAccTimeNs = sensorTimeStamp;
88 | if (eventIsDelayed) {
89 | this.resetCalibration();
90 | return;
91 | }
92 | smooth(this.mAccSmoothed, this.mCurrAcc, ACC_SMOOTHING_FACTOR);
93 | }
94 |
95 | public void getEstimate(final Estimate output) {
96 | output.set(this.mBiasEstimate);
97 | }
98 |
99 | private boolean canCalibrateGyro() {
100 | if (this.mAccSmoothed.length() < MIN_ACCEL_LENGTH) {
101 | return false;
102 | }
103 | this.mAccNormalizedTmp.set(this.mAccSmoothed);
104 | this.mAccNormalizedTmp.normalize();
105 | return Vector3d.dot(this.mAccNormalizedTmp, GyroBiasEstimator.UP_VECTOR) >= GyroBiasEstimator.MIN_ACCEL_DOT_WITH_UP && this.mGyroMagnitudeDiffSmoothed <= 0.01f;
106 | }
107 |
108 | private static void smooth(final Vector3d smoothed, final Vector3d newValue, final float smoothingFactor) {
109 | smoothed.x = smoothingFactor * newValue.x + (1.0f - smoothingFactor) * smoothed.x;
110 | smoothed.y = smoothingFactor * newValue.y + (1.0f - smoothingFactor) * smoothed.y;
111 | smoothed.z = smoothingFactor * newValue.z + (1.0f - smoothingFactor) * smoothed.z;
112 | }
113 |
114 | static {
115 | UP_VECTOR = new Vector3d(0.0, 0.0, 1.0);
116 | MIN_ACCEL_DOT_WITH_UP = (float)Math.cos(Math.toRadians(10.0));
117 | }
118 |
119 | public static class Estimate
120 | {
121 | public State mState;
122 | public final Vector3d mBias;
123 |
124 | public Estimate() {
125 | super();
126 | this.mState = State.UNCALIBRATED;
127 | this.mBias = new Vector3d();
128 | }
129 |
130 | public void set(final Estimate from) {
131 | this.mState = from.mState;
132 | this.mBias.set(from.mBias);
133 | }
134 |
135 | public enum State
136 | {
137 | UNCALIBRATED,
138 | CALIBRATING,
139 | CALIBRATED;
140 | }
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/library/src/main/java/com/google/vrtoolkit/cardboard/sensors/internal/Matrix3x3d.java:
--------------------------------------------------------------------------------
1 | package com.google.vrtoolkit.cardboard.sensors.internal;
2 |
3 | public class Matrix3x3d {
4 | public double[] m;
5 |
6 | public Matrix3x3d() {
7 | super();
8 | this.m = new double[9];
9 | }
10 |
11 | public Matrix3x3d(final double m00, final double m01, final double m02, final double m10, final double m11, final double m12, final double m20, final double m21, final double m22) {
12 | super();
13 | (this.m = new double[9])[0] = m00;
14 | this.m[1] = m01;
15 | this.m[2] = m02;
16 | this.m[3] = m10;
17 | this.m[4] = m11;
18 | this.m[5] = m12;
19 | this.m[6] = m20;
20 | this.m[7] = m21;
21 | this.m[8] = m22;
22 | }
23 |
24 | public Matrix3x3d(final Matrix3x3d o) {
25 | super();
26 | (this.m = new double[9])[0] = o.m[0];
27 | this.m[1] = o.m[1];
28 | this.m[2] = o.m[2];
29 | this.m[3] = o.m[3];
30 | this.m[4] = o.m[4];
31 | this.m[5] = o.m[5];
32 | this.m[6] = o.m[6];
33 | this.m[7] = o.m[7];
34 | this.m[8] = o.m[8];
35 | }
36 |
37 | public void set(final double m00, final double m01, final double m02, final double m10, final double m11, final double m12, final double m20, final double m21, final double m22) {
38 | this.m[0] = m00;
39 | this.m[1] = m01;
40 | this.m[2] = m02;
41 | this.m[3] = m10;
42 | this.m[4] = m11;
43 | this.m[5] = m12;
44 | this.m[6] = m20;
45 | this.m[7] = m21;
46 | this.m[8] = m22;
47 | }
48 |
49 | public void set(final Matrix3x3d o) {
50 | this.m[0] = o.m[0];
51 | this.m[1] = o.m[1];
52 | this.m[2] = o.m[2];
53 | this.m[3] = o.m[3];
54 | this.m[4] = o.m[4];
55 | this.m[5] = o.m[5];
56 | this.m[6] = o.m[6];
57 | this.m[7] = o.m[7];
58 | this.m[8] = o.m[8];
59 | }
60 |
61 | public void setZero() {
62 | this.m[0] = 0;
63 | this.m[1] = 0;
64 | this.m[2] = 0;
65 | this.m[3] = 0;
66 | this.m[4] = 0;
67 | this.m[5] = 0;
68 | this.m[6] = 0;
69 | this.m[7] = 0;
70 | this.m[8] = 0;
71 | }
72 |
73 | public void setIdentity() {
74 | this.m[0] = 1;
75 | this.m[1] = 0;
76 | this.m[2] = 0;
77 | this.m[3] = 0;
78 | this.m[4] = 1;
79 | this.m[5] = 0;
80 | this.m[6] = 0;
81 | this.m[7] = 0;
82 | this.m[8] = 1;
83 | }
84 |
85 | public void setSameDiagonal(final double d) {
86 | this.m[0] = d;
87 | this.m[4] = d;
88 | this.m[8] = d;
89 | }
90 |
91 | public double get(final int row, final int col) {
92 | return this.m[3 * row + col];
93 | }
94 |
95 | public void set(final int row, final int col, final double value) {
96 | this.m[3 * row + col] = value;
97 | }
98 |
99 | public void getColumn(final int col, final Vector3d v) {
100 | v.x = this.m[col];
101 | v.y = this.m[col + 3];
102 | v.z = this.m[col + 6];
103 | }
104 |
105 | public void setColumn(final int col, final Vector3d v) {
106 | this.m[col] = v.x;
107 | this.m[col + 3] = v.y;
108 | this.m[col + 6] = v.z;
109 | }
110 |
111 | public void scale(final double s) {
112 | for (int i = 0; i < 9; i++) {
113 | this.m[i] *= s;
114 | }
115 | }
116 |
117 | public void plusEquals(final Matrix3x3d b) {
118 | for (int i = 0; i < 9; i++) {
119 | this.m[i] += b.m[i];
120 | }
121 | }
122 |
123 | public void minusEquals(final Matrix3x3d b) {
124 | for (int i = 0; i < 9; i++) {
125 | this.m[i] -= b.m[i];
126 | }
127 | }
128 |
129 | public void transpose() {
130 | double tmp = this.m[1];
131 | this.m[1] = this.m[3];
132 | this.m[3] = tmp;
133 | tmp = this.m[2];
134 | this.m[2] = this.m[6];
135 | this.m[6] = tmp;
136 | tmp = this.m[5];
137 | this.m[5] = this.m[7];
138 | this.m[7] = tmp;
139 | }
140 |
141 | public void transpose(final Matrix3x3d result) {
142 | final double m1 = this.m[1];
143 | final double m2 = this.m[2];
144 | final double m3 = this.m[5];
145 | result.m[0] = this.m[0];
146 | result.m[1] = this.m[3];
147 | result.m[2] = this.m[6];
148 | result.m[3] = m1;
149 | result.m[4] = this.m[4];
150 | result.m[5] = this.m[7];
151 | result.m[6] = m2;
152 | result.m[7] = m3;
153 | result.m[8] = this.m[8];
154 | }
155 |
156 | public static void add(final Matrix3x3d a, final Matrix3x3d b, final Matrix3x3d result) {
157 | result.m[0] = a.m[0] + b.m[0];
158 | result.m[1] = a.m[1] + b.m[1];
159 | result.m[2] = a.m[2] + b.m[2];
160 | result.m[3] = a.m[3] + b.m[3];
161 | result.m[4] = a.m[4] + b.m[4];
162 | result.m[5] = a.m[5] + b.m[5];
163 | result.m[6] = a.m[6] + b.m[6];
164 | result.m[7] = a.m[7] + b.m[7];
165 | result.m[8] = a.m[8] + b.m[8];
166 | }
167 |
168 | public static void mult(final Matrix3x3d a, final Matrix3x3d b, final Matrix3x3d result) {
169 | result.set(a.m[0] * b.m[0] + a.m[1] * b.m[3] + a.m[2] * b.m[6],
170 | a.m[0] * b.m[1] + a.m[1] * b.m[4] + a.m[2] * b.m[7],
171 | a.m[0] * b.m[2] + a.m[1] * b.m[5] + a.m[2] * b.m[8],
172 | a.m[3] * b.m[0] + a.m[4] * b.m[3] + a.m[5] * b.m[6],
173 | a.m[3] * b.m[1] + a.m[4] * b.m[4] + a.m[5] * b.m[7],
174 | a.m[3] * b.m[2] + a.m[4] * b.m[5] + a.m[5] * b.m[8],
175 | a.m[6] * b.m[0] + a.m[7] * b.m[3] + a.m[8] * b.m[6],
176 | a.m[6] * b.m[1] + a.m[7] * b.m[4] + a.m[8] * b.m[7],
177 | a.m[6] * b.m[2] + a.m[7] * b.m[5] + a.m[8] * b.m[8]);
178 | }
179 |
180 | public static void mult(final Matrix3x3d a, final Vector3d v, final Vector3d result) {
181 | final double x = a.m[0] * v.x + a.m[1] * v.y + a.m[2] * v.z;
182 | final double y = a.m[3] * v.x + a.m[4] * v.y + a.m[5] * v.z;
183 | final double z = a.m[6] * v.x + a.m[7] * v.y + a.m[8] * v.z;
184 | result.x = x;
185 | result.y = y;
186 | result.z = z;
187 | }
188 |
189 | public double determinant() {
190 | return this.get(0, 0) * (this.get(1, 1) * this.get(2, 2) - this.get(2, 1) * this.get(1, 2))
191 | - this.get(0, 1) * (this.get(1, 0) * this.get(2, 2) - this.get(1, 2) * this.get(2, 0))
192 | + this.get(0, 2) * (this.get(1, 0) * this.get(2, 1) - this.get(1, 1) * this.get(2, 0));
193 | }
194 |
195 | public boolean invert(final Matrix3x3d result) {
196 | final double d = this.determinant();
197 | if (d == 0.0) {
198 | return false;
199 | }
200 | final double invdet = 1.0 / d;
201 | result.set((this.m[4] * this.m[8] - this.m[7] * this.m[5]) * invdet,
202 | -(this.m[1] * this.m[8] - this.m[2] * this.m[7]) * invdet,
203 | (this.m[1] * this.m[5] - this.m[2] * this.m[4]) * invdet,
204 | -(this.m[3] * this.m[8] - this.m[5] * this.m[6]) * invdet,
205 | (this.m[0] * this.m[8] - this.m[2] * this.m[6]) * invdet,
206 | -(this.m[0] * this.m[5] - this.m[3] * this.m[2]) * invdet,
207 | (this.m[3] * this.m[7] - this.m[6] * this.m[4]) * invdet,
208 | -(this.m[0] * this.m[7] - this.m[6] * this.m[1]) * invdet,
209 | (this.m[0] * this.m[4] - this.m[3] * this.m[1]) * invdet);
210 | return true;
211 | }
212 |
213 | @Override
214 | public String toString() {
215 | final StringBuilder builder = new StringBuilder().append("{ ");
216 | for (int i = 0; i < 9; ++i)
217 | {
218 | builder.append(Double.toString(this.m[i]));
219 | if (i < 9 - 1)
220 | {
221 | builder.append(", ");
222 | }
223 | }
224 | builder.append(" }");
225 | return builder.toString();
226 | }
227 | }
228 |
--------------------------------------------------------------------------------
/library/src/main/java/com/google/vrtoolkit/cardboard/sensors/internal/So3Util.java:
--------------------------------------------------------------------------------
1 | package com.google.vrtoolkit.cardboard.sensors.internal;
2 |
3 | public class So3Util {
4 | private static final double M_SQRT1_2 = 0.7071067811865476;
5 | private static final double ONE_6TH = 0.1666666716337204;
6 | private static final double ONE_20TH = 0.1666666716337204;
7 | private static Vector3d temp31;
8 | private static Vector3d sO3FromTwoVecN;
9 | private static Vector3d sO3FromTwoVecA;
10 | private static Vector3d sO3FromTwoVecB;
11 | private static Vector3d sO3FromTwoVecRotationAxis;
12 | private static Matrix3x3d sO3FromTwoVec33R1;
13 | private static Matrix3x3d sO3FromTwoVec33R2;
14 | private static Vector3d muFromSO3R2;
15 | private static Vector3d rotationPiAboutAxisTemp;
16 |
17 | public static void sO3FromTwoVec(final Vector3d a, final Vector3d b, final Matrix3x3d result) {
18 | Vector3d.cross(a, b, So3Util.sO3FromTwoVecN);
19 | if (So3Util.sO3FromTwoVecN.length() == 0.0) {
20 | final double dot = Vector3d.dot(a, b);
21 | if (dot >= 0.0) {
22 | result.setIdentity();
23 | }
24 | else {
25 | Vector3d.ortho(a, So3Util.sO3FromTwoVecRotationAxis);
26 | rotationPiAboutAxis(So3Util.sO3FromTwoVecRotationAxis, result);
27 | }
28 | return;
29 | }
30 | So3Util.sO3FromTwoVecA.set(a);
31 | So3Util.sO3FromTwoVecB.set(b);
32 | So3Util.sO3FromTwoVecN.normalize();
33 | So3Util.sO3FromTwoVecA.normalize();
34 | So3Util.sO3FromTwoVecB.normalize();
35 | final Matrix3x3d r1 = So3Util.sO3FromTwoVec33R1;
36 | r1.setColumn(0, So3Util.sO3FromTwoVecA);
37 | r1.setColumn(1, So3Util.sO3FromTwoVecN);
38 | Vector3d.cross(So3Util.sO3FromTwoVecN, So3Util.sO3FromTwoVecA, So3Util.temp31);
39 | r1.setColumn(2, So3Util.temp31);
40 | final Matrix3x3d r2 = So3Util.sO3FromTwoVec33R2;
41 | r2.setColumn(0, So3Util.sO3FromTwoVecB);
42 | r2.setColumn(1, So3Util.sO3FromTwoVecN);
43 | Vector3d.cross(So3Util.sO3FromTwoVecN, So3Util.sO3FromTwoVecB, So3Util.temp31);
44 | r2.setColumn(2, So3Util.temp31);
45 | r1.transpose();
46 | Matrix3x3d.mult(r2, r1, result);
47 | }
48 |
49 | private static void rotationPiAboutAxis(final Vector3d v, final Matrix3x3d result) {
50 | So3Util.rotationPiAboutAxisTemp.set(v);
51 | So3Util.rotationPiAboutAxisTemp.scale(3.141592653589793 / So3Util.rotationPiAboutAxisTemp.length());
52 | final double invTheta = 0.3183098861837907;
53 | final double kA = 0.0;
54 | final double kB = 0.20264236728467558;
55 | rodriguesSo3Exp(So3Util.rotationPiAboutAxisTemp, kA, kB, result);
56 | }
57 |
58 | public static void sO3FromMu(final Vector3d w, final Matrix3x3d result) {
59 | final double thetaSq = Vector3d.dot(w, w);
60 | final double theta = Math.sqrt(thetaSq);
61 | double kA;
62 | double kB;
63 | if (thetaSq < 1.0E-8) {
64 | kA = 1.0 - 0.1666666716337204 * thetaSq;
65 | kB = 0.5;
66 | }
67 | else if (thetaSq < 1.0E-6) {
68 | kB = 0.5 - 0.0416666679084301 * thetaSq;
69 | kA = 1.0 - thetaSq * 0.1666666716337204 * (1.0 - 0.1666666716337204 * thetaSq);
70 | }
71 | else {
72 | final double invTheta = 1.0 / theta;
73 | kA = Math.sin(theta) * invTheta;
74 | kB = (1.0 - Math.cos(theta)) * (invTheta * invTheta);
75 | }
76 | rodriguesSo3Exp(w, kA, kB, result);
77 | }
78 |
79 | public static void muFromSO3(final Matrix3x3d so3, final Vector3d result) {
80 | final double cosAngle = (so3.get(0, 0) + so3.get(1, 1) + so3.get(2, 2) - 1.0) * 0.5;
81 | result.set((so3.get(2, 1) - so3.get(1, 2)) / 2.0, (so3.get(0, 2) - so3.get(2, 0)) / 2.0, (so3.get(1, 0) - so3.get(0, 1)) / 2.0);
82 | final double sinAngleAbs = result.length();
83 | if (cosAngle > 0.7071067811865476) {
84 | if (sinAngleAbs > 0.0) {
85 | result.scale(Math.asin(sinAngleAbs) / sinAngleAbs);
86 | }
87 | }
88 | else if (cosAngle > -0.7071067811865476) {
89 | final double angle = Math.acos(cosAngle);
90 | result.scale(angle / sinAngleAbs);
91 | }
92 | else {
93 | final double angle = 3.141592653589793 - Math.asin(sinAngleAbs);
94 | final double d0 = so3.get(0, 0) - cosAngle;
95 | final double d = so3.get(1, 1) - cosAngle;
96 | final double d2 = so3.get(2, 2) - cosAngle;
97 | final Vector3d r2 = So3Util.muFromSO3R2;
98 | if (d0 * d0 > d * d && d0 * d0 > d2 * d2) {
99 | r2.set(d0, (so3.get(1, 0) + so3.get(0, 1)) / 2.0, (so3.get(0, 2) + so3.get(2, 0)) / 2.0);
100 | }
101 | else if (d * d > d2 * d2) {
102 | r2.set((so3.get(1, 0) + so3.get(0, 1)) / 2.0, d, (so3.get(2, 1) + so3.get(1, 2)) / 2.0);
103 | }
104 | else {
105 | r2.set((so3.get(0, 2) + so3.get(2, 0)) / 2.0, (so3.get(2, 1) + so3.get(1, 2)) / 2.0, d2);
106 | }
107 | if (Vector3d.dot(r2, result) < 0.0) {
108 | r2.scale(-1.0);
109 | }
110 | r2.normalize();
111 | r2.scale(angle);
112 | result.set(r2);
113 | }
114 | }
115 |
116 | private static void rodriguesSo3Exp(final Vector3d w, final double kA, final double kB, final Matrix3x3d result) {
117 | final double wx2 = w.x * w.x;
118 | final double wy2 = w.y * w.y;
119 | final double wz2 = w.z * w.z;
120 | result.set(0, 0, 1.0 - kB * (wy2 + wz2));
121 | result.set(1, 1, 1.0 - kB * (wx2 + wz2));
122 | result.set(2, 2, 1.0 - kB * (wx2 + wy2));
123 | double a = kA * w.z;
124 | double b = kB * (w.x * w.y);
125 | result.set(0, 1, b - a);
126 | result.set(1, 0, b + a);
127 | a = kA * w.y;
128 | b = kB * (w.x * w.z);
129 | result.set(0, 2, b + a);
130 | result.set(2, 0, b - a);
131 | a = kA * w.x;
132 | b = kB * (w.y * w.z);
133 | result.set(1, 2, b - a);
134 | result.set(2, 1, b + a);
135 | }
136 |
137 | public static void generatorField(final int i, final Matrix3x3d pos, final Matrix3x3d result) {
138 | result.set(i, 0, 0.0);
139 | result.set((i + 1) % 3,
140 | 0,
141 | -pos.get((i + 2) % 3, 0));
142 | result.set((i + 2) % 3,
143 | 0, pos.get((i + 1) % 3,0));
144 | }
145 |
146 | static {
147 | So3Util.temp31 = new Vector3d();
148 | So3Util.sO3FromTwoVecN = new Vector3d();
149 | So3Util.sO3FromTwoVecA = new Vector3d();
150 | So3Util.sO3FromTwoVecB = new Vector3d();
151 | So3Util.sO3FromTwoVecRotationAxis = new Vector3d();
152 | So3Util.sO3FromTwoVec33R1 = new Matrix3x3d();
153 | So3Util.sO3FromTwoVec33R2 = new Matrix3x3d();
154 | So3Util.muFromSO3R2 = new Vector3d();
155 | So3Util.rotationPiAboutAxisTemp = new Vector3d();
156 | }
157 | }
158 |
--------------------------------------------------------------------------------
/library/src/main/java/com/google/vrtoolkit/cardboard/sensors/internal/Vector3d.java:
--------------------------------------------------------------------------------
1 | package com.google.vrtoolkit.cardboard.sensors.internal;
2 |
3 | public class Vector3d {
4 | public double x;
5 | public double y;
6 | public double z;
7 |
8 | public Vector3d() {
9 | super();
10 | }
11 |
12 | public Vector3d(final double xx, final double yy, final double zz) {
13 | super();
14 | this.set(xx, yy, zz);
15 | }
16 |
17 | public void set(final double xx, final double yy, final double zz) {
18 | this.x = xx;
19 | this.y = yy;
20 | this.z = zz;
21 | }
22 |
23 | public void setComponent(final int i, final double val) {
24 | if (i == 0) {
25 | this.x = val;
26 | }
27 | else if (i == 1) {
28 | this.y = val;
29 | }
30 | else {
31 | this.z = val;
32 | }
33 | }
34 |
35 | public void setZero() {
36 | final double x = 0.0;
37 | this.z = x;
38 | this.y = x;
39 | this.x = x;
40 | }
41 |
42 | public void set(final Vector3d other) {
43 | this.x = other.x;
44 | this.y = other.y;
45 | this.z = other.z;
46 | }
47 |
48 | public void scale(final double s) {
49 | this.x *= s;
50 | this.y *= s;
51 | this.z *= s;
52 | }
53 |
54 | public void normalize() {
55 | final double d = this.length();
56 | if (d != 0.0) {
57 | this.scale(1.0 / d);
58 | }
59 | }
60 |
61 | public static double dot(final Vector3d a, final Vector3d b) {
62 | return a.x * b.x + a.y * b.y + a.z * b.z;
63 | }
64 |
65 | public double length() {
66 | return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
67 | }
68 |
69 | public boolean sameValues(final Vector3d other) {
70 | return this.x == other.x && this.y == other.y && this.z == other.z;
71 | }
72 |
73 | public static void add(final Vector3d a, final Vector3d b, final Vector3d result) {
74 | result.set(a.x + b.x, a.y + b.y, a.z + b.z);
75 | }
76 |
77 | public static void sub(final Vector3d a, final Vector3d b, final Vector3d result) {
78 | result.set(a.x - b.x, a.y - b.y, a.z - b.z);
79 | }
80 |
81 | public static void cross(final Vector3d a, final Vector3d b, final Vector3d result) {
82 | result.set(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x);
83 | }
84 |
85 | public static void ortho(final Vector3d v, final Vector3d result) {
86 | int k = largestAbsComponent(v) - 1;
87 | if (k < 0) {
88 | k = 2;
89 | }
90 | result.setZero();
91 | result.setComponent(k, 1.0);
92 | cross(v, result, result);
93 | result.normalize();
94 | }
95 |
96 | public static int largestAbsComponent(final Vector3d v) {
97 | final double xAbs = Math.abs(v.x);
98 | final double yAbs = Math.abs(v.y);
99 | final double zAbs = Math.abs(v.z);
100 | if (xAbs > yAbs) {
101 | if (xAbs > zAbs) {
102 | return 0;
103 | }
104 | return 2;
105 | }
106 | else {
107 | if (yAbs > zAbs) {
108 | return 1;
109 | }
110 | return 2;
111 | }
112 | }
113 |
114 | @Override
115 | public String toString() {
116 | final StringBuilder builder = new StringBuilder().append("{ ");
117 | builder.append(Double.toString(this.x));
118 | builder.append(", ");
119 | builder.append(Double.toString(this.y));
120 | builder.append(", ");
121 | builder.append(Double.toString(this.z));
122 | builder.append(" }");
123 | return builder.toString();
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/sample/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/sample/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 21
5 | buildToolsVersion "21.1.2"
6 |
7 | defaultConfig {
8 | applicationId "com.google.vrtoolkit.cardboard.samples.treasurehunt"
9 | minSdkVersion 16
10 | targetSdkVersion 21
11 | versionCode 1
12 | versionName "1.0"
13 | }
14 |
15 | compileOptions {
16 | sourceCompatibility JavaVersion.VERSION_1_7
17 | targetCompatibility JavaVersion.VERSION_1_7
18 | }
19 |
20 | lintOptions {
21 | abortOnError false
22 | }
23 |
24 | buildTypes {
25 | release {
26 | minifyEnabled false
27 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
28 | }
29 | }
30 | }
31 |
32 | dependencies {
33 | compile project(':library')
34 | }
35 |
--------------------------------------------------------------------------------
/sample/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add any project specific keep options here:
2 |
3 | # If your project uses WebView with JS, uncomment the following
4 | # and specify the fully qualified class name to the JavaScript interface
5 | # class:
6 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
7 | # public *;
8 | #}
9 |
--------------------------------------------------------------------------------
/sample/src/androidTest/java/com/google/vrtoolkit/cardboard/samples/treasurehunt/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.google.vrtoolkit.cardboard.samples.treasurehunt;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/sample/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
16 |
17 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/google/vrtoolkit/cardboard/samples/treasurehunt/CardboardOverlayView.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Google Inc. All Rights Reserved.
3 |
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.google.vrtoolkit.cardboard.samples.treasurehunt;
18 |
19 | import android.content.Context;
20 | import android.graphics.Color;
21 | import android.graphics.Typeface;
22 | import android.util.AttributeSet;
23 | import android.util.TypedValue;
24 | import android.view.Gravity;
25 | import android.view.View;
26 | import android.view.ViewGroup;
27 | import android.view.animation.AlphaAnimation;
28 | import android.view.animation.Animation;
29 | import android.widget.ImageView;
30 | import android.widget.LinearLayout;
31 | import android.widget.TextView;
32 |
33 | /**
34 | * Contains two sub-views to provide a simple stereo HUD.
35 | */
36 | public class CardboardOverlayView extends LinearLayout {
37 | private static final String TAG = CardboardOverlayView.class.getSimpleName();
38 | private final CardboardOverlayEyeView mLeftView;
39 | private final CardboardOverlayEyeView mRightView;
40 | private AlphaAnimation mTextFadeAnimation;
41 |
42 | public CardboardOverlayView(Context context, AttributeSet attrs) {
43 | super(context, attrs);
44 | setOrientation(HORIZONTAL);
45 |
46 | LayoutParams params = new LayoutParams(
47 | LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, 1.0f);
48 | params.setMargins(0, 0, 0, 0);
49 |
50 | mLeftView = new CardboardOverlayEyeView(context, attrs);
51 | mLeftView.setLayoutParams(params);
52 | addView(mLeftView);
53 |
54 | mRightView = new CardboardOverlayEyeView(context, attrs);
55 | mRightView.setLayoutParams(params);
56 | addView(mRightView);
57 |
58 | // Set some reasonable defaults.
59 | setDepthOffset(0.016f);
60 | setColor(Color.rgb(150, 255, 180));
61 | setVisibility(View.VISIBLE);
62 |
63 | mTextFadeAnimation = new AlphaAnimation(1.0f, 0.0f);
64 | mTextFadeAnimation.setDuration(5000);
65 | }
66 |
67 | public void show3DToast(String message) {
68 | setText(message);
69 | setTextAlpha(1f);
70 | mTextFadeAnimation.setAnimationListener(new EndAnimationListener() {
71 | @Override
72 | public void onAnimationEnd(Animation animation) {
73 | setTextAlpha(0f);
74 | }
75 | });
76 | startAnimation(mTextFadeAnimation);
77 | }
78 |
79 | private abstract class EndAnimationListener implements Animation.AnimationListener {
80 | @Override public void onAnimationRepeat(Animation animation) {}
81 | @Override public void onAnimationStart(Animation animation) {}
82 | }
83 |
84 | private void setDepthOffset(float offset) {
85 | mLeftView.setOffset(offset);
86 | mRightView.setOffset(-offset);
87 | }
88 |
89 | private void setText(String text) {
90 | mLeftView.setText(text);
91 | mRightView.setText(text);
92 | }
93 |
94 | private void setTextAlpha(float alpha) {
95 | mLeftView.setTextViewAlpha(alpha);
96 | mRightView.setTextViewAlpha(alpha);
97 | }
98 |
99 | private void setColor(int color) {
100 | mLeftView.setColor(color);
101 | mRightView.setColor(color);
102 | }
103 |
104 | /**
105 | * A simple view group containing some horizontally centered text underneath a horizontally
106 | * centered image.
107 | *
108 | * This is a helper class for CardboardOverlayView.
109 | */
110 | private class CardboardOverlayEyeView extends ViewGroup {
111 | private final ImageView imageView;
112 | private final TextView textView;
113 | private float offset;
114 |
115 | public CardboardOverlayEyeView(Context context, AttributeSet attrs) {
116 | super(context, attrs);
117 | imageView = new ImageView(context, attrs);
118 | imageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
119 | imageView.setAdjustViewBounds(true); // Preserve aspect ratio.
120 | addView(imageView);
121 |
122 | textView = new TextView(context, attrs);
123 | textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14.0f);
124 | textView.setTypeface(textView.getTypeface(), Typeface.BOLD);
125 | textView.setGravity(Gravity.CENTER);
126 | textView.setShadowLayer(3.0f, 0.0f, 0.0f, Color.DKGRAY);
127 | addView(textView);
128 | }
129 |
130 | public void setColor(int color) {
131 | imageView.setColorFilter(color);
132 | textView.setTextColor(color);
133 | }
134 |
135 | public void setText(String text) {
136 | textView.setText(text);
137 | }
138 |
139 | public void setTextViewAlpha(float alpha) {
140 | textView.setAlpha(alpha);
141 | }
142 |
143 | public void setOffset(float offset) {
144 | this.offset = offset;
145 | }
146 |
147 | @Override
148 | protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
149 | // Width and height of this ViewGroup.
150 | final int width = right - left;
151 | final int height = bottom - top;
152 |
153 | // The size of the image, given as a fraction of the dimension as a ViewGroup.
154 | // We multiply both width and heading with this number to compute the image's bounding
155 | // box. Inside the box, the image is the horizontally and vertically centered.
156 | final float imageSize = 0.12f;
157 |
158 | // The fraction of this ViewGroup's height by which we shift the image off the
159 | // ViewGroup's center. Positive values shift downwards, negative values shift upwards.
160 | final float verticalImageOffset = -0.07f;
161 |
162 | // Vertical position of the text, specified in fractions of this ViewGroup's height.
163 | final float verticalTextPos = 0.52f;
164 |
165 | // Layout ImageView
166 | float imageMargin = (1.0f - imageSize) / 2.0f;
167 | float leftMargin = (int) (width * (imageMargin + offset));
168 | float topMargin = (int) (height * (imageMargin + verticalImageOffset));
169 | imageView.layout(
170 | (int) leftMargin, (int) topMargin,
171 | (int) (leftMargin + width * imageSize), (int) (topMargin + height * imageSize));
172 |
173 | // Layout TextView
174 | leftMargin = offset * width;
175 | topMargin = height * verticalTextPos;
176 | textView.layout(
177 | (int) leftMargin, (int) topMargin,
178 | (int) (leftMargin + width), (int) (topMargin + height * (1.0f - verticalTextPos)));
179 | }
180 | }
181 | }
182 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/google/vrtoolkit/cardboard/samples/treasurehunt/WorldLayoutData.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Google Inc. All Rights Reserved.
3 |
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.google.vrtoolkit.cardboard.samples.treasurehunt;
18 |
19 | /**
20 | * Contains vertex, normal and color data.
21 | */
22 | public final class WorldLayoutData {
23 |
24 | public static final float[] CUBE_COORDS = new float[] {
25 | // Front face
26 | -1.0f, 1.0f, 1.0f,
27 | -1.0f, -1.0f, 1.0f,
28 | 1.0f, 1.0f, 1.0f,
29 | -1.0f, -1.0f, 1.0f,
30 | 1.0f, -1.0f, 1.0f,
31 | 1.0f, 1.0f, 1.0f,
32 |
33 | // Right face
34 | 1.0f, 1.0f, 1.0f,
35 | 1.0f, -1.0f, 1.0f,
36 | 1.0f, 1.0f, -1.0f,
37 | 1.0f, -1.0f, 1.0f,
38 | 1.0f, -1.0f, -1.0f,
39 | 1.0f, 1.0f, -1.0f,
40 |
41 | // Back face
42 | 1.0f, 1.0f, -1.0f,
43 | 1.0f, -1.0f, -1.0f,
44 | -1.0f, 1.0f, -1.0f,
45 | 1.0f, -1.0f, -1.0f,
46 | -1.0f, -1.0f, -1.0f,
47 | -1.0f, 1.0f, -1.0f,
48 |
49 | // Left face
50 | -1.0f, 1.0f, -1.0f,
51 | -1.0f, -1.0f, -1.0f,
52 | -1.0f, 1.0f, 1.0f,
53 | -1.0f, -1.0f, -1.0f,
54 | -1.0f, -1.0f, 1.0f,
55 | -1.0f, 1.0f, 1.0f,
56 |
57 | // Top face
58 | -1.0f, 1.0f, -1.0f,
59 | -1.0f, 1.0f, 1.0f,
60 | 1.0f, 1.0f, -1.0f,
61 | -1.0f, 1.0f, 1.0f,
62 | 1.0f, 1.0f, 1.0f,
63 | 1.0f, 1.0f, -1.0f,
64 |
65 | // Bottom face
66 | 1.0f, -1.0f, -1.0f,
67 | 1.0f, -1.0f, 1.0f,
68 | -1.0f, -1.0f, -1.0f,
69 | 1.0f, -1.0f, 1.0f,
70 | -1.0f, -1.0f, 1.0f,
71 | -1.0f, -1.0f, -1.0f,
72 | };
73 |
74 | public static final float[] CUBE_COLORS = new float[] {
75 | // front, green
76 | 0f, 0.5273f, 0.2656f, 1.0f,
77 | 0f, 0.5273f, 0.2656f, 1.0f,
78 | 0f, 0.5273f, 0.2656f, 1.0f,
79 | 0f, 0.5273f, 0.2656f, 1.0f,
80 | 0f, 0.5273f, 0.2656f, 1.0f,
81 | 0f, 0.5273f, 0.2656f, 1.0f,
82 |
83 | // right, blue
84 | 0.0f, 0.3398f, 0.9023f, 1.0f,
85 | 0.0f, 0.3398f, 0.9023f, 1.0f,
86 | 0.0f, 0.3398f, 0.9023f, 1.0f,
87 | 0.0f, 0.3398f, 0.9023f, 1.0f,
88 | 0.0f, 0.3398f, 0.9023f, 1.0f,
89 | 0.0f, 0.3398f, 0.9023f, 1.0f,
90 |
91 | // back, also green
92 | 0f, 0.5273f, 0.2656f, 1.0f,
93 | 0f, 0.5273f, 0.2656f, 1.0f,
94 | 0f, 0.5273f, 0.2656f, 1.0f,
95 | 0f, 0.5273f, 0.2656f, 1.0f,
96 | 0f, 0.5273f, 0.2656f, 1.0f,
97 | 0f, 0.5273f, 0.2656f, 1.0f,
98 |
99 | // left, also blue
100 | 0.0f, 0.3398f, 0.9023f, 1.0f,
101 | 0.0f, 0.3398f, 0.9023f, 1.0f,
102 | 0.0f, 0.3398f, 0.9023f, 1.0f,
103 | 0.0f, 0.3398f, 0.9023f, 1.0f,
104 | 0.0f, 0.3398f, 0.9023f, 1.0f,
105 | 0.0f, 0.3398f, 0.9023f, 1.0f,
106 |
107 | // top, red
108 | 0.8359375f, 0.17578125f, 0.125f, 1.0f,
109 | 0.8359375f, 0.17578125f, 0.125f, 1.0f,
110 | 0.8359375f, 0.17578125f, 0.125f, 1.0f,
111 | 0.8359375f, 0.17578125f, 0.125f, 1.0f,
112 | 0.8359375f, 0.17578125f, 0.125f, 1.0f,
113 | 0.8359375f, 0.17578125f, 0.125f, 1.0f,
114 |
115 | // bottom, also red
116 | 0.8359375f, 0.17578125f, 0.125f, 1.0f,
117 | 0.8359375f, 0.17578125f, 0.125f, 1.0f,
118 | 0.8359375f, 0.17578125f, 0.125f, 1.0f,
119 | 0.8359375f, 0.17578125f, 0.125f, 1.0f,
120 | 0.8359375f, 0.17578125f, 0.125f, 1.0f,
121 | 0.8359375f, 0.17578125f, 0.125f, 1.0f,
122 | };
123 |
124 | public static final float[] CUBE_FOUND_COLORS = new float[] {
125 | // front, yellow
126 | 1.0f, 0.6523f, 0.0f, 1.0f,
127 | 1.0f, 0.6523f, 0.0f, 1.0f,
128 | 1.0f, 0.6523f, 0.0f, 1.0f,
129 | 1.0f, 0.6523f, 0.0f, 1.0f,
130 | 1.0f, 0.6523f, 0.0f, 1.0f,
131 | 1.0f, 0.6523f, 0.0f, 1.0f,
132 |
133 | // right, yellow
134 | 1.0f, 0.6523f, 0.0f, 1.0f,
135 | 1.0f, 0.6523f, 0.0f, 1.0f,
136 | 1.0f, 0.6523f, 0.0f, 1.0f,
137 | 1.0f, 0.6523f, 0.0f, 1.0f,
138 | 1.0f, 0.6523f, 0.0f, 1.0f,
139 | 1.0f, 0.6523f, 0.0f, 1.0f,
140 |
141 | // back, yellow
142 | 1.0f, 0.6523f, 0.0f, 1.0f,
143 | 1.0f, 0.6523f, 0.0f, 1.0f,
144 | 1.0f, 0.6523f, 0.0f, 1.0f,
145 | 1.0f, 0.6523f, 0.0f, 1.0f,
146 | 1.0f, 0.6523f, 0.0f, 1.0f,
147 | 1.0f, 0.6523f, 0.0f, 1.0f,
148 |
149 | // left, yellow
150 | 1.0f, 0.6523f, 0.0f, 1.0f,
151 | 1.0f, 0.6523f, 0.0f, 1.0f,
152 | 1.0f, 0.6523f, 0.0f, 1.0f,
153 | 1.0f, 0.6523f, 0.0f, 1.0f,
154 | 1.0f, 0.6523f, 0.0f, 1.0f,
155 | 1.0f, 0.6523f, 0.0f, 1.0f,
156 |
157 | // top, yellow
158 | 1.0f, 0.6523f, 0.0f, 1.0f,
159 | 1.0f, 0.6523f, 0.0f, 1.0f,
160 | 1.0f, 0.6523f, 0.0f, 1.0f,
161 | 1.0f, 0.6523f, 0.0f, 1.0f,
162 | 1.0f, 0.6523f, 0.0f, 1.0f,
163 | 1.0f, 0.6523f, 0.0f, 1.0f,
164 |
165 | // bottom, yellow
166 | 1.0f, 0.6523f, 0.0f, 1.0f,
167 | 1.0f, 0.6523f, 0.0f, 1.0f,
168 | 1.0f, 0.6523f, 0.0f, 1.0f,
169 | 1.0f, 0.6523f, 0.0f, 1.0f,
170 | 1.0f, 0.6523f, 0.0f, 1.0f,
171 | 1.0f, 0.6523f, 0.0f, 1.0f,
172 | };
173 |
174 | public static final float[] CUBE_NORMALS = new float[] {
175 | // Front face
176 | 0.0f, 0.0f, 1.0f,
177 | 0.0f, 0.0f, 1.0f,
178 | 0.0f, 0.0f, 1.0f,
179 | 0.0f, 0.0f, 1.0f,
180 | 0.0f, 0.0f, 1.0f,
181 | 0.0f, 0.0f, 1.0f,
182 |
183 | // Right face
184 | 1.0f, 0.0f, 0.0f,
185 | 1.0f, 0.0f, 0.0f,
186 | 1.0f, 0.0f, 0.0f,
187 | 1.0f, 0.0f, 0.0f,
188 | 1.0f, 0.0f, 0.0f,
189 | 1.0f, 0.0f, 0.0f,
190 |
191 | // Back face
192 | 0.0f, 0.0f, -1.0f,
193 | 0.0f, 0.0f, -1.0f,
194 | 0.0f, 0.0f, -1.0f,
195 | 0.0f, 0.0f, -1.0f,
196 | 0.0f, 0.0f, -1.0f,
197 | 0.0f, 0.0f, -1.0f,
198 |
199 | // Left face
200 | -1.0f, 0.0f, 0.0f,
201 | -1.0f, 0.0f, 0.0f,
202 | -1.0f, 0.0f, 0.0f,
203 | -1.0f, 0.0f, 0.0f,
204 | -1.0f, 0.0f, 0.0f,
205 | -1.0f, 0.0f, 0.0f,
206 |
207 | // Top face
208 | 0.0f, 1.0f, 0.0f,
209 | 0.0f, 1.0f, 0.0f,
210 | 0.0f, 1.0f, 0.0f,
211 | 0.0f, 1.0f, 0.0f,
212 | 0.0f, 1.0f, 0.0f,
213 | 0.0f, 1.0f, 0.0f,
214 |
215 | // Bottom face
216 | 0.0f, -1.0f, 0.0f,
217 | 0.0f, -1.0f, 0.0f,
218 | 0.0f, -1.0f, 0.0f,
219 | 0.0f, -1.0f, 0.0f,
220 | 0.0f, -1.0f, 0.0f,
221 | 0.0f, -1.0f, 0.0f
222 | };
223 |
224 | public static final float[] FLOOR_COORDS = new float[] {
225 | 200f, 0, -200f,
226 | -200f, 0, -200f,
227 | -200f, 0, 200f,
228 | 200f, 0, -200f,
229 | -200f, 0, 200f,
230 | 200f, 0, 200f,
231 | };
232 |
233 | public static final float[] FLOOR_NORMALS = new float[] {
234 | 0.0f, 1.0f, 0.0f,
235 | 0.0f, 1.0f, 0.0f,
236 | 0.0f, 1.0f, 0.0f,
237 | 0.0f, 1.0f, 0.0f,
238 | 0.0f, 1.0f, 0.0f,
239 | 0.0f, 1.0f, 0.0f,
240 | };
241 |
242 | public static final float[] FLOOR_COLORS = new float[] {
243 | 0.0f, 0.3398f, 0.9023f, 1.0f,
244 | 0.0f, 0.3398f, 0.9023f, 1.0f,
245 | 0.0f, 0.3398f, 0.9023f, 1.0f,
246 | 0.0f, 0.3398f, 0.9023f, 1.0f,
247 | 0.0f, 0.3398f, 0.9023f, 1.0f,
248 | 0.0f, 0.3398f, 0.9023f, 1.0f,
249 | };
250 | }
251 |
--------------------------------------------------------------------------------
/sample/src/main/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsanchezsaez/cardboard-java/df049c9024d275189893330eeb6ad6cf5b32275d/sample/src/main/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsanchezsaez/cardboard-java/df049c9024d275189893330eeb6ad6cf5b32275d/sample/src/main/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsanchezsaez/cardboard-java/df049c9024d275189893330eeb6ad6cf5b32275d/sample/src/main/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsanchezsaez/cardboard-java/df049c9024d275189893330eeb6ad6cf5b32275d/sample/src/main/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/layout/common_ui.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
15 |
16 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsanchezsaez/cardboard-java/df049c9024d275189893330eeb6ad6cf5b32275d/sample/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsanchezsaez/cardboard-java/df049c9024d275189893330eeb6ad6cf5b32275d/sample/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsanchezsaez/cardboard-java/df049c9024d275189893330eeb6ad6cf5b32275d/sample/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsanchezsaez/cardboard-java/df049c9024d275189893330eeb6ad6cf5b32275d/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/raw/grid_fragment.shader:
--------------------------------------------------------------------------------
1 | precision mediump float;
2 | varying vec4 v_Color;
3 | varying vec3 v_Grid;
4 |
5 | void main() {
6 | float depth = gl_FragCoord.z / gl_FragCoord.w; // Calculate world-space distance.
7 |
8 | if ((mod(abs(v_Grid.x), 10.0) < 0.1) || (mod(abs(v_Grid.z), 10.0) < 0.1)) {
9 | gl_FragColor = max(0.0, (90.0-depth) / 90.0) * vec4(1.0, 1.0, 1.0, 1.0)
10 | + min(1.0, depth / 90.0) * v_Color;
11 | } else {
12 | gl_FragColor = v_Color;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/sample/src/main/res/raw/light_vertex.shader:
--------------------------------------------------------------------------------
1 | uniform mat4 u_Model;
2 | uniform mat4 u_MVP;
3 | uniform mat4 u_MVMatrix;
4 | uniform vec3 u_LightPos;
5 |
6 | attribute vec4 a_Position;
7 | attribute vec4 a_Color;
8 | attribute vec3 a_Normal;
9 |
10 | varying vec4 v_Color;
11 | varying vec3 v_Grid;
12 |
13 | void main() {
14 | v_Grid = vec3(u_Model * a_Position);
15 |
16 | vec3 modelViewVertex = vec3(u_MVMatrix * a_Position);
17 | vec3 modelViewNormal = vec3(u_MVMatrix * vec4(a_Normal, 0.0));
18 |
19 | float distance = length(u_LightPos - modelViewVertex);
20 | vec3 lightVector = normalize(u_LightPos - modelViewVertex);
21 | float diffuse = max(dot(modelViewNormal, lightVector), 0.5);
22 |
23 | diffuse = diffuse * (1.0 / (1.0 + (0.00001 * distance * distance)));
24 | v_Color = a_Color * diffuse;
25 | gl_Position = u_MVP * a_Position;
26 | }
27 |
--------------------------------------------------------------------------------
/sample/src/main/res/raw/passthrough_fragment.shader:
--------------------------------------------------------------------------------
1 | precision mediump float;
2 | varying vec4 v_Color;
3 |
4 | void main() {
5 | gl_FragColor = v_Color;
6 | }
7 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Cardboard Sample
4 |
5 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':library', ':sample'
2 |
--------------------------------------------------------------------------------