Add Google Cardboard (android) version.

Update the website with more information
parent af4a639d
apply plugin: 'com.android.model.application'
model {
android {
compileSdkVersion = 25
buildToolsVersion = "25.0.2"
defaultConfig.with {
applicationId = "com.google.vr.ndk.samples.treasurehunt"
minSdkVersion.apiLevel = 19
targetSdkVersion.apiLevel = 24
versionCode = 1
versionName = "1.0"
}
}
android.buildTypes {
release {
minifyEnabled = false
proguardFiles.add(file('proguard-android.txt'))
}
}
android.ndk {
moduleName = "treasurehunt_jni"
cppFlags.add("-std=c++11")
cppFlags.add("-I" + file("src/main/jni").absolutePath)
// Add the necessary GVR headers.
cppFlags.add("-I" + file("${project.rootDir}/libraries/headers").absolutePath)
cppFlags.add("-DINDICESGL32" )
cppFlags.add("-fexceptions")
stl = "gnustl_shared"
// Add the necessary GVR .so files for all architectures.
ldFlags.add("-L" + file("${project.rootDir}/libraries/jni/arm64-v8a").absolutePath)
ldFlags.add("-L" + file("${project.rootDir}/libraries/jni/armeabi-v7a").absolutePath)
ldFlags.add("-L" + file("${project.rootDir}/libraries/jni/x86").absolutePath)
ldLibs.addAll(["log", "android", "EGL", "GLESv3"])
// Specific the particular .so files this sample links against.
ldLibs.add("gvr")
ldLibs.add("gvr_audio")
}
android.productFlavors {
create ("fat") {
// This sample builds all architectures by default. Note that if you
// only want to build for a specific architecture, you need to
// remove the appropriate lines below. You also need to remove the
// .so files from the apk using
// "packagingOptions {exclude('lib/armeabi-v7a/*')}" in the android
// section.
ndk.abiFilters.add("arm64-v8a")
ndk.abiFilters.add("armeabi-v7a")
ndk.abiFilters.add("x86")
}
}
}
dependencies {
compile 'com.google.vr:sdk-audio:1.20.0'
compile 'com.google.vr:sdk-base:1.20.0'
compile "com.android.support:support-v4:23.1.1"
}
build.dependsOn(':extractNdk')
This source diff could not be displayed because it is too large. You can view the blob instead.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.google.vr.ndk.samples.treasurehunt"
android:versionCode="170117123"
android:versionName="1.20.0">
<!-- The GVR SDK requires API 19+ and OpenGL ES 2+. -->
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="24" />
<uses-feature android:glEsVersion="0x00030000" android:required="true" />
<!-- Required for vibration feedback when the trigger action is performed. -->
<uses-permission android:name="android.permission.VIBRATE"/>
<!-- Required to read the paired viewer's distortion parameters. -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET" />
<!-- Make accelerometer and gyroscope hard requirements for good head tracking. -->
<uses-feature android:name="android.hardware.sensor.accelerometer" android:required="true"/>
<uses-feature android:name="android.hardware.sensor.gyroscope" android:required="true"/>
<!-- Indicates use of Android's VR-mode, available only on Android N+. -->
<uses-feature android:name="android.software.vr.mode" android:required="false"/>
<!-- Indicates use of VR features that are available only on Daydream-ready devices. -->
<uses-feature android:name="android.hardware.vr.high_performance" android:required="false"/>
<application
android:allowBackup="true"
android:label="MainActivity"
android:theme="@style/VrActivityTheme">
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:screenOrientation="landscape"
android:configChanges="orientation|keyboardHidden|screenSize"
android:enableVrMode="@string/gvr_vr_mode_component"
android:resizeableActivity="false">
<!-- The VR icon to be used in Daydream Home comes in two parts:
a foreground icon and a background icon. -->
<meta-data android:name="com.google.android.vr.icon"
android:resource="@drawable/vr_icon" />
<meta-data android:name="com.google.android.vr.icon_background"
android:resource="@drawable/vr_icon_background" />
<!-- Intent filter that enables this app to be launched from the
Daydream Home menu. -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="com.google.intent.category.DAYDREAM"/>
</intent-filter>
<!-- Intent filter that enables this app to be launched from the
Cardboard app and from the traditional launcher. -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="com.google.intent.category.CARDBOARD" />
</intent-filter>
<!--Test opening a NOMAD url-->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="file" />
<data android:mimeType="*/*" />
<data android:pathPattern=".*\\.ncfg" />
<data android:host="*" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.BROWSABLE"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="content" android:pathPattern=".*\\.ncfg"
android:mimeType="application/octet-stream"/>
</intent-filter>
</activity>
</application>
</manifest>
/* Copyright 2017 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.vr.ndk.samples.treasurehunt;
import android.app.Activity;
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.os.Vibrator;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import com.google.vr.ndk.base.AndroidCompat;
import com.google.vr.ndk.base.GvrLayout;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
/** A Gvr API sample application. */
public class MainActivity extends Activity {
private GvrLayout gvrLayout;
private long nativeTreasureHuntRenderer;
private GLSurfaceView surfaceView;
// This is done on the GL thread because refreshViewerProfile isn't thread-safe.
private final Runnable refreshViewerProfileRunnable =
new Runnable() {
@Override
public void run() {
gvrLayout.getGvrApi().refreshViewerProfile();
}
};
static {
System.loadLibrary("gvr");
System.loadLibrary("gvr_audio");
System.loadLibrary("treasurehunt_jni");
}
//http://stackoverflow.com/questions/8854359/exception-open-failed-eacces-permission-denied-on-android
// Storage Permissions
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
android.Manifest.permission.READ_EXTERNAL_STORAGE,
android.Manifest.permission.WRITE_EXTERNAL_STORAGE
};
/**
* Checks if the app has permission to write to device storage
*
* If the app does not has permission then the user will be prompted to grant permissions
*
* @param activity
*/
public static void verifyStoragePermissions(Activity activity) {
// Check if we have write permission
int permission = android.support.v4.app.ActivityCompat.checkSelfPermission(activity, android.Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (permission != android.content.pm.PackageManager.PERMISSION_GRANTED) {
// We don't have permission so prompt the user
android.support.v4.app.ActivityCompat.requestPermissions(
activity,
PERMISSIONS_STORAGE,
REQUEST_EXTERNAL_STORAGE
);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
verifyStoragePermissions(this);
//intents
android.content.Intent intent = getIntent();
String s=intent.getDataString();
String uriString="/data/local/tmp/material.ncfg";
if (s!=null) {
if (s.startsWith("content://")) {
try {
java.io.InputStream input = getContentResolver().openInputStream(intent.getData());
byte[] buffer = new byte[8 * 1024];
java.io.FileOutputStream output = new java.io.FileOutputStream("/data/local/tmp/material.ncfg");
try{
int bytesRead;
while((bytesRead = input.read()) != -1){
output.write(buffer, 0, bytesRead);
}
} finally {
try{
output.close();
} catch (Exception e) {
uriString=null;
}
try {
input.close();
} catch (java.io.IOException e) {
uriString=null;
}
}
} catch (java.io.IOException e) {
uriString=null;
}
if (uriString!=null)
nativeSetConfigFile(uriString);
} else if (s.startsWith("file://")) {
uriString=s.substring(7);
nativeSetConfigFile(uriString);
} else {
android.util.Log.d("NOMADgvrT","Unknown protocol in intent:"+ s);
}
}
// Ensure fullscreen immersion.
setImmersiveSticky();
getWindow()
.getDecorView()
.setOnSystemUiVisibilityChangeListener(
new View.OnSystemUiVisibilityChangeListener() {
@Override
public void onSystemUiVisibilityChange(int visibility) {
if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
setImmersiveSticky();
}
}
});
// Initialize GvrLayout and the native renderer.
gvrLayout = new GvrLayout(this);
nativeTreasureHuntRenderer =
nativeCreateRenderer(
getClass().getClassLoader(),
this.getApplicationContext(),
gvrLayout.getGvrApi().getNativeGvrContext());
// Add the GLSurfaceView to the GvrLayout.
surfaceView = new GLSurfaceView(this);
surfaceView.setEGLContextClientVersion(3);
surfaceView.setEGLConfigChooser(8, 8, 8, 0, 0, 0);
surfaceView.setPreserveEGLContextOnPause(true);
surfaceView.setRenderer(
new GLSurfaceView.Renderer() {
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
nativeInitializeGl(nativeTreasureHuntRenderer);
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {}
@Override
public void onDrawFrame(GL10 gl) {
nativeDrawFrame(nativeTreasureHuntRenderer);
}
});
surfaceView.setOnTouchListener(
new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
// Give user feedback and signal a trigger event.
((Vibrator) getSystemService(Context.VIBRATOR_SERVICE)).vibrate(50);
nativeOnTriggerEvent(nativeTreasureHuntRenderer);
return true;
}
return false;
}
});
gvrLayout.setPresentationView(surfaceView);
// Add the GvrLayout to the View hierarchy.
setContentView(gvrLayout);
// Enable scan line racing.
if (gvrLayout.setAsyncReprojectionEnabled(true)) {
// Scanline racing decouples the app framerate from the display framerate,
// allowing immersive interaction even at the throttled clockrates set by
// sustained performance mode.
AndroidCompat.setSustainedPerformanceMode(this, true);
}
//intents
//java.lang.String s=GvrIntent.GetData();
//android.util.Log.d("NOMADgvrT, intent=", s);
// Enable VR Mode.
AndroidCompat.setVrModeEnabled(this, true);
// Prevent screen from dimming/locking.
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
@Override
protected void onPause() {
super.onPause();
nativeOnPause(nativeTreasureHuntRenderer);
gvrLayout.onPause();
surfaceView.onPause();
}
@Override
protected void onResume() {
super.onResume();
nativeOnResume(nativeTreasureHuntRenderer);
gvrLayout.onResume();
surfaceView.onResume();
surfaceView.queueEvent(refreshViewerProfileRunnable);
}
@Override
protected void onDestroy() {
super.onDestroy();
// Destruction order is important; shutting down the GvrLayout will detach
// the GLSurfaceView and stop the GL thread, allowing safe shutdown of
// native resources from the UI thread.
gvrLayout.shutdown();
nativeDestroyRenderer(nativeTreasureHuntRenderer);
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
setImmersiveSticky();
}
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
// Avoid accidental volume key presses while the phone is in the VR headset.
if (event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_UP
|| event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_DOWN) {
return true;
}
return super.dispatchKeyEvent(event);
}
private void setImmersiveSticky() {
getWindow()
.getDecorView()
.setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
}
private native long nativeCreateRenderer(
ClassLoader appClassLoader, Context context, long nativeGvrContext);
private native void nativeDestroyRenderer(long nativeTreasureHuntRenderer);
private native void nativeInitializeGl(long nativeTreasureHuntRenderer);
private native long nativeDrawFrame(long nativeTreasureHuntRenderer);
private native void nativeOnTriggerEvent(long nativeTreasureHuntRenderer);
private native void nativeOnPause(long nativeTreasureHuntRenderer);
private native void nativeOnResume(long nativeTreasureHuntRenderer);
private native void nativeSetConfigFile(String s);
}
/* Copyright 2017 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <android/log.h>
#include <jni.h>
#include <memory>
#include "treasure_hunt_renderer.h" // NOLINT
#include "vr/gvr/capi/include/gvr.h"
#include "vr/gvr/capi/include/gvr_audio.h"
#define JNI_METHOD(return_type, method_name) \
JNIEXPORT return_type JNICALL \
Java_com_google_vr_ndk_samples_treasurehunt_MainActivity_##method_name
namespace {
inline jlong jptr(TreasureHuntRenderer *native_treasure_hunt) {
return reinterpret_cast<intptr_t>(native_treasure_hunt);
}
inline TreasureHuntRenderer *native(jlong ptr) {
return reinterpret_cast<TreasureHuntRenderer *>(ptr);
}
} // anonymous namespace
extern "C" {
JNI_METHOD(jlong, nativeCreateRenderer)
(JNIEnv *env, jclass clazz, jobject class_loader, jobject android_context,
jlong native_gvr_api) {
std::unique_ptr<gvr::AudioApi> audio_context(new gvr::AudioApi);
audio_context->Init(env, android_context, class_loader,
GVR_AUDIO_RENDERING_BINAURAL_HIGH_QUALITY);
return jptr(
new TreasureHuntRenderer(reinterpret_cast<gvr_context *>(native_gvr_api),
std::move(audio_context)));
}
JNI_METHOD(void, nativeDestroyRenderer)
(JNIEnv *env, jclass clazz, jlong native_treasure_hunt) {
delete native(native_treasure_hunt);
}
JNI_METHOD(void, nativeInitializeGl)
(JNIEnv *env, jobject obj, jlong native_treasure_hunt) {
native(native_treasure_hunt)->InitializeGl();
}
JNI_METHOD(void, nativeDrawFrame)
(JNIEnv *env, jobject obj, jlong native_treasure_hunt) {
native(native_treasure_hunt)->DrawFrame();
}
JNI_METHOD(void, nativeOnTriggerEvent)
(JNIEnv *env, jobject obj, jlong native_treasure_hunt) {
native(native_treasure_hunt)->OnTriggerEvent();
}
JNI_METHOD(void, nativeOnPause)
(JNIEnv *env, jobject obj, jlong native_treasure_hunt) {
native(native_treasure_hunt)->OnPause();
}
JNI_METHOD(void, nativeOnResume)
(JNIEnv *env, jobject obj, jlong native_treasure_hunt) {
native(native_treasure_hunt)->OnResume();
}
JNI_METHOD(void, nativeSetConfigFile)
(JNIEnv *env, jobject obj, jstring s) {
configPath = env->GetStringUTFChars(s , NULL ) ;
}
} // extern "C"
/* Copyright 2017 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef TREASUREHUNT_APP_SRC_MAIN_JNI_TREASUREHUNTRENDERER_H_ // NOLINT
#define TREASUREHUNT_APP_SRC_MAIN_JNI_TREASUREHUNTRENDERER_H_ // NOLINT
#include <EGL/egl.h>
#include <GLES3/gl3.h>
#include <jni.h>
#include <memory>
#include <string>
#include <thread> // NOLINT
#include <vector>
#include "vr/gvr/capi/include/gvr.h"
#include "vr/gvr/capi/include/gvr_audio.h"
#include "vr/gvr/capi/include/gvr_controller.h"
#include "vr/gvr/capi/include/gvr_types.h"
extern const char * configPath;
class TreasureHuntRenderer {
public:
/**
* Create a TreasureHuntRenderer using a given |gvr_context|.
*
* @param gvr_api The (non-owned) gvr_context.
* @param gvr_audio_api The (owned) gvr::AudioApi context.
*/
TreasureHuntRenderer(gvr_context* gvr_context,
std::unique_ptr<gvr::AudioApi> gvr_audio_api);
/**
* Destructor.
*/
~TreasureHuntRenderer();
/**
* Initialize any GL-related objects. This should be called on the rendering
* thread with a valid GL context.
*/
void InitializeGl();
/**
* Draw the TreasureHunt scene. This should be called on the rendering thread.
*/
void DrawFrame();
/**
* Pause head tracking.
*/