Simplevideowidget这个Demo运行起来的效果如下:
单击视频显示区域可以暂停/继续播放。
点击眼镜按钮可以进入到双眼VR模式:
现在分析下代码实现:
只有一个Activity文件:
主要是显示了一个SDK中的
VrVideoView控件
进入VR双眼模式和全屏显示的切换按钮都在这个控件里面。所以要分析下这个控件的实现。
模式切换的实现是在
VrVideoView的父类VrWidgetView中。如下:
private void initializeUiButtons() {
this.enterFullscreenButton = (ImageButton)this.uiView.findViewById(id.fullscreen_button);
this.enterFullscreenButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
VrWidgetView.this.setDisplayMode(2);
}
});
this.enterStereoModeButton = (ImageButton)this.uiView.findViewById(id.vr_mode_button);
this.enterStereoModeButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
VrWidgetView.this.setDisplayMode(3);
}
});
this.fullscreenBackButton = (ImageButton)this.uiView.findViewById(id.fullscreen_back_button);
this.fullscreenBackButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
VrWidgetView.this.setDisplayMode(1);
}
});
this.infoButton = (ImageButton)this.uiView.findViewById(id.info_button);
this.infoButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
VrWidgetView.this.activity.startActivity(VrWidgetView.getInfoButtonIntent());
}
});
this.updateButtonVisibility();
}
可以知道DisplayMode 3为VR模式。
现在看下setDisplayMode3的背后发生了什么。
public void setDisplayMode(int newDisplayMode) {
if(newDisplayMode != this.displayMode) {
this.renderer.updateCurrentYaw();
if(newDisplayMode <= 0 || newDisplayMode >= 4) {
Log.e(TAG, (new StringBuilder(38)).append("Invalid DisplayMode value: ").append(newDisplayMode).toString());
newDisplayMode = 1;
}
this.displayMode = newDisplayMode;
this.updateStereoMode();
if(this.isFullScreen()) {
this.orientationHelper.lockOrientation();
this.fullScreenDialog.show();
} else {
this.fullScreenDialog.dismiss();
this.orientationHelper.restoreOriginalOrientation();
}
this.updateControlsLayout();
this.updateTouchTracker();
this.eventListener.onDisplayModeChanged(this.displayMode);
}
}
这里可以知道,首先更新了Yaw(偏航角),然后调用了updateStereoMode(),之后关闭fullScreenDialog,并重新装载了原始四元素。
最后更新布局等。
这里看下updateStereoMode这个函数:
private void updateStereoMode() {
this.renderer.setStereoMode(this.displayMode == 3);
AndroidNCompat.setVrModeEnabled(this.activity, this.displayMode == 3, 0);
if(this.displayMode == 3) {
this.screenOnFlagHelper.start();
} else {
this.screenOnFlagHelper.stop();
}
this.updateButtonVisibility();
this.updateViewerName();
}
其调用到了AndroidNCompat.setVrModeEnabled以及
ScreenOnFlagHelper类型成员screenOnFlagHelper的start函数。
跟踪AndroidNCompat可以发现:
public static boolean setVrModeEnabled(Activity var0, boolean var1, int var2) {
if(!isVrModeSupported(var0)) {
if(isAtLeastN()) {
Log.d(TAG, "VR mode is not supported on this N device.");
}
return false;
} else {
ComponentName var3 = new ComponentName("com.google.vr.vrcore", "com.google.vr.vrcore.common.VrCoreListenerService");
String var10000;
String var5;
try {
var0.setVrModeEnabled(var1, var3);
return true;
} catch (NameNotFoundException var6) {
var10000 = TAG;
var5 = String.valueOf(var6);
Log.w(var10000, (new StringBuilder(25 + String.valueOf(var5).length())).append("No VR service component: ").append(var5).toString());
if((var2 & 1) != 0 && handleVrCoreAbsence(var0, checkForVrCorePresence(var0))) {
Log.w(TAG, "Failed to handle missing VrCore package.");
}
} catch (UnsupportedOperationException var7) {
var10000 = TAG;
var5 = String.valueOf(var7);
Log.w(var10000, (new StringBuilder(23 + String.valueOf(var5).length())).append("Failed to set VR mode: ").append(var5).toString());
}
return false;
}
}
核心在var0.setVrModeEnabled(var1,var3)这一句
查看AndroidN最新的Activity.java代码,有新增接口setVrModeEnabled
public void setVrModeEnabled(boolean enabled, @NonNull ComponentName requestedComponent)
throws PackageManager.NameNotFoundException {
try {
if (ActivityManagerNative.getDefault().setVrMode(mToken, enabled, requestedComponent)
!= 0) {
throw new PackageManager.NameNotFoundException(
requestedComponent.flattenToString());
}
} catch (RemoteException e) {
// pass
}
}
而screenOnFlagHelper的start函数主要是开启了传感器数据的发送,1为
Sensor.TYPE_ACCELEROMETER
1 加速度传感器 :
public void start() {
if(this.sensorManager == null) {
this.sensorManager = (SensorManager)this.activity.getSystemService("sensor");
}
if(this.sensor == null) {
this.sensor = this.sensorManager.getDefaultSensor(1);
}
this.isFlagSet = false;
this.setKeepScreenOnFlag(true);
this.sensorStats.reset();
this.sensorManager.registerListener(this, this.sensor, 250000);
}
所以,很好理解了。SDK中的这个控件封装了AndroidN中新增的Activity.setVrModeEnabled和加速度传感器的启用来实现了具备VR功能的video控件