Add more Daydream VR support

This commit is contained in:
Patrick Walton 2019-03-15 15:23:37 -07:00
parent 5db7edad0b
commit 49660a6b31
6 changed files with 104 additions and 141 deletions

View File

@ -22,6 +22,8 @@ android {
}
dependencies {
compile 'com.google.vr:sdk-base:1.160.0'
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support:support-v4:27.1.1'

View File

@ -11,17 +11,40 @@
android:theme="@style/AppTheme">
<activity
android:name=".PathfinderActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:configChanges="density|navigation|orientation|keyboardHidden|screenSize|uiMode"
android:label="@string/app_name"
android:theme="@style/FullscreenTheme">
android:theme="@style/VrActivityTheme"
android:resizeableActivity="false">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<!-- This marks the Activity as a Daydream Activity and allows it
to be launched from the Daydream Home. -->
<category android:name="com.google.intent.category.DAYDREAM" />
<!-- This marks the Activity as a Cardboard Activity and allows it
to be launched from the Cardboard app. -->
<category android:name="com.google.intent.category.CARDBOARD" />
<!-- This allows this Activity to be launched from the traditional
Android 2D launcher as well. Remove it if you do not want
this Activity to be launched directly from the 2D launcher. -->
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".PathfinderDemoVRListenerService"
android:label="@string/service_name"
android:permission="android.permission.BIND_VR_LISTENER_SERVICE">
<intent-filter>
<action android:name="android.service.vr.VrListenerService" />
</intent-filter>
</service>
</application>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-feature android:name="android.software.vr.mode" android:required="false"/>
<uses-feature android:name="android.hardware.vr.high_performance" android:required="false"/>
</manifest>

View File

@ -2,102 +2,42 @@ package graphics.pathfinder.pathfinderdemo;
import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Build;
import android.provider.Settings;
import android.support.annotation.NonNull;
import android.support.annotation.RequiresApi;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import java.util.ArrayList;
import java.util.Arrays;
import com.google.vr.cardboard.AndroidNCompat;
/**
* An example full-screen activity that shows and hides the system UI (i.e.
* status bar and navigation/system bar) with user interaction.
*/
public class PathfinderActivity extends AppCompatActivity {
public class PathfinderActivity extends Activity {
private PathfinderDemoRenderer mRenderer;
/**
* Whether or not the system UI should be auto-hidden after
* {@link #AUTO_HIDE_DELAY_MILLIS} milliseconds.
*/
private static final boolean AUTO_HIDE = true;
/**
* If {@link #AUTO_HIDE} is set, the number of milliseconds to wait after
* user interaction before hiding the system UI.
*/
private static final int AUTO_HIDE_DELAY_MILLIS = 3000;
/**
* Some older devices needs a small delay between UI widget updates
* and a change of the status and navigation bar.
*/
private static final int UI_ANIMATION_DELAY = 300;
private final Handler mHideHandler = new Handler();
private PathfinderDemoSurfaceView mContentView;
private final Runnable mHidePart2Runnable = new Runnable() {
@SuppressLint("InlinedApi")
@Override
public void run() {
// Delayed removal of status and navigation bar
// Note that some of these constants are new as of API 16 (Jelly Bean)
// and API 19 (KitKat). It is safe to use them, as they are inlined
// at compile-time and do nothing on earlier devices.
mContentView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
}
};
private View mControlsView;
private final Runnable mShowPart2Runnable = new Runnable() {
@Override
public void run() {
// Delayed display of UI elements
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.show();
}
mControlsView.setVisibility(View.VISIBLE);
}
};
private boolean mVisible;
private final Runnable mHideRunnable = new Runnable() {
@Override
public void run() {
hide();
}
};
/**
* Touch listener to use for in-layout UI controls to delay hiding the
* system UI. This is to prevent the jarring behavior of controls going away
* while interacting with activity UI.
*/
private final View.OnTouchListener mDelayHideTouchListener = new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (AUTO_HIDE) {
delayedHide(AUTO_HIDE_DELAY_MILLIS);
}
return false;
}
};
ComponentName mVRListenerComponentName;
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -122,13 +62,26 @@ public class PathfinderActivity extends AppCompatActivity {
init();
}
@RequiresApi(api = Build.VERSION_CODES.N)
void setVRMode(boolean enabled) {
try {
setVrModeEnabled(false, mVRListenerComponentName);
} catch (PackageManager.NameNotFoundException exception) {
startActivity(new Intent(Settings.ACTION_VR_LISTENER_SETTINGS));
}
}
@RequiresApi(api = Build.VERSION_CODES.N)
@SuppressLint("ClickableViewAccessibility")
private void init() {
mVRListenerComponentName = new ComponentName("graphics.pathfinder.pathfinderdemo",
"graphics.pathfinder.pathfinderdemo.PathfinderDemoVRListenerService");
setContentView(R.layout.activity_pathfinder);
mVisible = true;
mControlsView = findViewById(R.id.fullscreen_content_controls);
mContentView = findViewById(R.id.fullscreen_content);
mContentView.setStereoModeEnabled(false);
setVRMode(false);
/*
// Set up the user interaction to manually show or hide the system UI.
@ -141,7 +94,7 @@ public class PathfinderActivity extends AppCompatActivity {
*/
mContentView.setEGLContextClientVersion(3);
mRenderer = new PathfinderDemoRenderer(getAssets());
mRenderer = new PathfinderDemoRenderer(this);
mContentView.setRenderer(mRenderer);
mContentView.setOnTouchListener(new View.OnTouchListener() {
@ -203,53 +156,5 @@ public class PathfinderActivity extends AppCompatActivity {
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
// Trigger the initial hide() shortly after the activity has been
// created, to briefly hint to the user that UI controls
// are available.
delayedHide(100);
}
private void toggle() {
if (mVisible) {
hide();
} else {
show();
}
}
private void hide() {
// Hide UI first
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.hide();
}
mControlsView.setVisibility(View.GONE);
mVisible = false;
// Schedule a runnable to remove the status and navigation bar after a delay
mHideHandler.removeCallbacks(mShowPart2Runnable);
mHideHandler.postDelayed(mHidePart2Runnable, UI_ANIMATION_DELAY);
}
@SuppressLint("InlinedApi")
private void show() {
// Show the system bar
mContentView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
mVisible = true;
// Schedule a runnable to display UI elements after a delay
mHideHandler.removeCallbacks(mHidePart2Runnable);
mHideHandler.postDelayed(mShowPart2Runnable, UI_ANIMATION_DELAY);
}
/**
* Schedules a call to hide() in delay milliseconds, canceling any
* previously scheduled calls.
*/
private void delayedHide(int delayMillis) {
mHideHandler.removeCallbacks(mHideRunnable);
mHideHandler.postDelayed(mHideRunnable, delayMillis);
}
}

View File

@ -1,58 +1,89 @@
package graphics.pathfinder.pathfinderdemo;
import android.content.res.AssetManager;
import android.opengl.GLSurfaceView;
import android.content.pm.PackageManager;
import android.os.Build;
import android.support.annotation.RequiresApi;
import com.google.vr.sdk.base.Eye;
import com.google.vr.sdk.base.GvrView;
import com.google.vr.sdk.base.HeadTransform;
import com.google.vr.sdk.base.Viewport;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
public class PathfinderDemoRenderer extends Object implements GLSurfaceView.Renderer {
private AssetManager mAssetManager;
public class PathfinderDemoRenderer extends Object implements GvrView.Renderer {
private PathfinderActivity mActivity;
private boolean mInitialized;
private boolean mInVRMode;
private static native void init(PathfinderDemoResourceLoader resourceLoader,
int width,
int height);
private static native int prepareFrame();
private static native void drawScene(int sceneIndex);
private static native void finishDrawingFrame();
public static native void pushWindowResizedEvent(int width, int height);
public static native void pushMouseDownEvent(int x, int y);
public static native void pushMouseDraggedEvent(int x, int y);
public static native void pushLookEvent(float pitch, float yaw);
static {
System.loadLibrary("pathfinder_android_demo");
}
protected PathfinderDemoRenderer() {}
PathfinderDemoRenderer(AssetManager assetManager) {
PathfinderDemoRenderer(PathfinderActivity activity) {
super();
mAssetManager = assetManager;
mActivity = activity;
mInitialized = false;
}
@RequiresApi(api = Build.VERSION_CODES.N)
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
public void onDrawFrame(HeadTransform headTransform, Eye leftEye, Eye rightEye) {
boolean inVR = prepareFrame() > 1;
if (inVR != mInVRMode) {
mInVRMode = inVR;
try {
mActivity.setVrModeEnabled(mInVRMode, mActivity.mVRListenerComponentName);
} catch (PackageManager.NameNotFoundException exception) {
throw new RuntimeException(exception);
}
}
for (int sceneIndex = 0; sceneIndex < (inVR ? 2 : 1); sceneIndex++)
drawScene(sceneIndex);
finishDrawingFrame();
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
public void onFinishFrame(Viewport viewport) {
}
@Override
public void onSurfaceChanged(int width, int height) {
if (!mInitialized) {
init(new PathfinderDemoResourceLoader(mAssetManager), width, height);
init(new PathfinderDemoResourceLoader(mActivity.getAssets()), width, height);
mInitialized = true;
} else {
pushWindowResizedEvent(width, height);
}
}
@Override
public void onDrawFrame(GL10 gl) {
int sceneCount = prepareFrame();
for (int sceneIndex = 0; sceneIndex < sceneCount; sceneIndex++)
drawScene(sceneIndex);
finishDrawingFrame();
public void onSurfaceCreated(EGLConfig config) {
}
@Override
public void onRendererShutdown() {
}
}

View File

@ -5,8 +5,9 @@ import android.opengl.GLSurfaceView;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import com.google.vr.sdk.base.GvrView;
public class PathfinderDemoSurfaceView extends GLSurfaceView {
public class PathfinderDemoSurfaceView extends GvrView {
public PathfinderDemoSurfaceView(Context context) {
super(context);
}

View File

@ -3,4 +3,5 @@
<string name="dummy_button">Dummy Button</string>
<string name="dummy_content">DUMMY\nCONTENT</string>
<string name="service_name">PathfinderVRListenerService</string>
</resources>