Added VR libraries
This commit is contained in:
@@ -0,0 +1,258 @@
|
||||
// Copyright 2016 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.
|
||||
|
||||
// This class is only used in the Editor, so make sure to only compile it on that platform.
|
||||
// Additionally, If this class is compiled on Android then Unity will insert the INTERNET permission
|
||||
// into the manifest because of the reference to the type TCPClient. Excluding this class in the android
|
||||
// build ensures that it is only included if the developer using the SDK actually uses INTERNET related services.
|
||||
// This MonoBehaviour is only ever instantiated dynamically, so it is fine that it is only compiled in the Editor,
|
||||
// Otherwise it would cause serialization issues.
|
||||
#if UNITY_EDITOR
|
||||
|
||||
using UnityEngine;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
|
||||
using proto;
|
||||
|
||||
/// @cond
|
||||
namespace Gvr.Internal {
|
||||
|
||||
public enum EmulatorClientSocketConnectionState {
|
||||
Disconnected = 0,
|
||||
Connecting = 1,
|
||||
Connected = 2,
|
||||
};
|
||||
|
||||
class EmulatorClientSocket : MonoBehaviour {
|
||||
private static readonly int kPhoneEventPort = 7003;
|
||||
private const int kSocketReadTimeoutMillis = 5000;
|
||||
|
||||
// Minimum interval, in seconds, between attempts to reconnect the socket.
|
||||
private const float kMinReconnectInterval = 1f;
|
||||
|
||||
private TcpClient phoneMirroringSocket;
|
||||
|
||||
private Thread phoneEventThread;
|
||||
|
||||
private volatile bool shouldStop = false;
|
||||
|
||||
// Flag used to limit connection state logging to initial failure and successful reconnects.
|
||||
private volatile bool lastConnectionAttemptWasSuccessful = true;
|
||||
|
||||
private EmulatorManager phoneRemote;
|
||||
public EmulatorClientSocketConnectionState connected { get; private set; }
|
||||
|
||||
public void Init(EmulatorManager remote) {
|
||||
phoneRemote = remote;
|
||||
|
||||
if (EmulatorConfig.Instance.PHONE_EVENT_MODE != EmulatorConfig.Mode.OFF) {
|
||||
phoneEventThread = new Thread(phoneEventSocketLoop);
|
||||
phoneEventThread.IsBackground = true;
|
||||
phoneEventThread.Start();
|
||||
}
|
||||
}
|
||||
|
||||
private void phoneEventSocketLoop() {
|
||||
while (!shouldStop) {
|
||||
long lastConnectionAttemptTime = DateTime.Now.Ticks;
|
||||
try {
|
||||
phoneConnect();
|
||||
} catch(Exception e) {
|
||||
if (lastConnectionAttemptWasSuccessful) {
|
||||
Debug.LogWarningFormat("{0}\n{1}", e.Message, e.StackTrace);
|
||||
// Suppress additional failures until we have successfully reconnected.
|
||||
lastConnectionAttemptWasSuccessful = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Wait a while in order to enforce the minimum time between connection attempts.
|
||||
TimeSpan elapsed = new TimeSpan(DateTime.Now.Ticks - lastConnectionAttemptTime);
|
||||
float toWait = kMinReconnectInterval - (float) elapsed.TotalSeconds;
|
||||
if (toWait > 0) {
|
||||
Thread.Sleep((int) (toWait * 1000));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void phoneConnect() {
|
||||
string addr = EmulatorConfig.Instance.PHONE_EVENT_MODE == EmulatorConfig.Mode.USB
|
||||
? EmulatorConfig.USB_SERVER_IP : EmulatorConfig.WIFI_SERVER_IP;
|
||||
|
||||
try {
|
||||
if (EmulatorConfig.Instance.PHONE_EVENT_MODE == EmulatorConfig.Mode.USB) {
|
||||
setupPortForwarding(kPhoneEventPort);
|
||||
}
|
||||
TcpClient tcpClient = new TcpClient(addr, kPhoneEventPort);
|
||||
connected = EmulatorClientSocketConnectionState.Connecting;
|
||||
ProcessConnection(tcpClient);
|
||||
tcpClient.Close();
|
||||
} finally {
|
||||
connected = EmulatorClientSocketConnectionState.Disconnected;
|
||||
}
|
||||
}
|
||||
|
||||
private void setupPortForwarding(int port) {
|
||||
#if !UNITY_WEBPLAYER
|
||||
string adbCommand = string.Format("adb forward tcp:{0} tcp:{0}", port);
|
||||
System.Diagnostics.Process myProcess = new System.Diagnostics.Process();
|
||||
string processFilename;
|
||||
string processArguments;
|
||||
int kExitCodeCommandNotFound;
|
||||
|
||||
if (Application.platform == RuntimePlatform.WindowsEditor ||
|
||||
Application.platform == RuntimePlatform.WindowsPlayer) {
|
||||
processFilename = "CMD.exe";
|
||||
processArguments = @"/k " + adbCommand + " & exit";
|
||||
// See "Common Error Lookup Tool" (https://www.microsoft.com/en-us/download/details.aspx?id=985)
|
||||
// MSG_DIR_BAD_COMMAND_OR_FILE (cmdmsg.h)
|
||||
kExitCodeCommandNotFound = 9009; // 0x2331
|
||||
} else { // Unix
|
||||
processFilename = "bash";
|
||||
processArguments = string.Format("-l -c \"{0}\"", adbCommand);
|
||||
// "command not found" (see http://tldp.org/LDP/abs/html/exitcodes.html)
|
||||
kExitCodeCommandNotFound = 127;
|
||||
}
|
||||
|
||||
System.Diagnostics.ProcessStartInfo myProcessStartInfo =
|
||||
new System.Diagnostics.ProcessStartInfo(processFilename, processArguments);
|
||||
myProcessStartInfo.UseShellExecute = false;
|
||||
myProcessStartInfo.RedirectStandardError = true;
|
||||
myProcessStartInfo.CreateNoWindow = true;
|
||||
myProcess.StartInfo = myProcessStartInfo;
|
||||
myProcess.Start();
|
||||
myProcess.WaitForExit();
|
||||
// Also wait for HasExited here, to avoid ExitCode access below occasionally throwing InvalidOperationException
|
||||
while (!myProcess.HasExited) {
|
||||
Thread.Sleep(1);
|
||||
}
|
||||
int exitCode = myProcess.ExitCode;
|
||||
string standardError = myProcess.StandardError.ReadToEnd();
|
||||
myProcess.Close();
|
||||
|
||||
if (exitCode == 0) {
|
||||
// Port forwarding setup successfully.
|
||||
return;
|
||||
}
|
||||
|
||||
if (exitCode == kExitCodeCommandNotFound) {
|
||||
// Caught by phoneEventSocketLoop.
|
||||
throw new Exception(
|
||||
"Android Debug Bridge (`adb`) command not found." +
|
||||
"\nVerify that the Android SDK is installed and that the directory containing" +
|
||||
" `adb` is included in your PATH environment variable.");
|
||||
}
|
||||
// Caught by phoneEventSocketLoop.
|
||||
throw new Exception(
|
||||
string.Format(
|
||||
"Failed to setup port forwarding." +
|
||||
" Exit code {0} returned by process: {1} {2}\n{3}",
|
||||
exitCode, processFilename, processArguments, standardError));
|
||||
#endif // !UNITY_WEBPLAYER
|
||||
}
|
||||
|
||||
private void ProcessConnection(TcpClient tcpClient) {
|
||||
byte[] buffer = new byte[4];
|
||||
NetworkStream stream = tcpClient.GetStream();
|
||||
stream.ReadTimeout = kSocketReadTimeoutMillis;
|
||||
tcpClient.ReceiveTimeout = kSocketReadTimeoutMillis;
|
||||
while (!shouldStop) {
|
||||
int bytesRead = blockingRead(stream, buffer, 0, 4);
|
||||
if (bytesRead < 4) {
|
||||
// Caught by phoneEventSocketLoop.
|
||||
throw new Exception(
|
||||
"Failed to read from controller emulator app event socket." +
|
||||
"\nVerify that the controller emulator app is running.");
|
||||
}
|
||||
int msgLen = unpack32bits(correctEndianness(buffer), 0);
|
||||
|
||||
byte[] dataBuffer = new byte[msgLen];
|
||||
bytesRead = blockingRead(stream, dataBuffer, 0, msgLen);
|
||||
if (bytesRead < msgLen) {
|
||||
// Caught by phoneEventSocketLoop.
|
||||
throw new Exception(
|
||||
"Failed to read from controller emulator app event socket." +
|
||||
"\nVerify that the controller emulator app is running.");
|
||||
}
|
||||
|
||||
PhoneEvent proto =
|
||||
PhoneEvent.CreateBuilder().MergeFrom(dataBuffer).Build();
|
||||
phoneRemote.OnPhoneEvent(proto);
|
||||
|
||||
connected = EmulatorClientSocketConnectionState.Connected;
|
||||
|
||||
if (!lastConnectionAttemptWasSuccessful) {
|
||||
Debug.Log("Successfully connected to controller emulator app.");
|
||||
// Log first failure after after successful read from event socket.
|
||||
lastConnectionAttemptWasSuccessful = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int blockingRead(NetworkStream stream, byte[] buffer, int index,
|
||||
int count) {
|
||||
int bytesRead = 0;
|
||||
while (!shouldStop && bytesRead < count) {
|
||||
try {
|
||||
int n = stream.Read(buffer, index + bytesRead, count - bytesRead);
|
||||
if (n <= 0) {
|
||||
// Failed to read.
|
||||
return -1;
|
||||
}
|
||||
bytesRead += n;
|
||||
} catch (IOException) {
|
||||
// Read failed or timed out.
|
||||
return -1;
|
||||
} catch (ObjectDisposedException) {
|
||||
// Socket closed.
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
void OnDestroy() {
|
||||
shouldStop = true;
|
||||
|
||||
if (phoneMirroringSocket != null) {
|
||||
phoneMirroringSocket.Close ();
|
||||
phoneMirroringSocket = null;
|
||||
}
|
||||
|
||||
if (phoneEventThread != null) {
|
||||
phoneEventThread.Join();
|
||||
}
|
||||
}
|
||||
|
||||
private int unpack32bits(byte[] array, int offset) {
|
||||
int num = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
num += array [offset + i] << (i * 8);
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
static private byte[] correctEndianness(byte[] array) {
|
||||
if (BitConverter.IsLittleEndian)
|
||||
Array.Reverse(array);
|
||||
|
||||
return array;
|
||||
}
|
||||
}
|
||||
}
|
||||
/// @endcond
|
||||
|
||||
#endif // UNITY_EDITOR
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6bf1f92fb4ae24291b71e77c1ccac323
|
||||
timeCreated: 1462051657
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,60 @@
|
||||
// Copyright 2016 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.
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
/// @cond
|
||||
namespace Gvr.Internal {
|
||||
class EmulatorConfig : MonoBehaviour {
|
||||
public static EmulatorConfig Instance {
|
||||
get {
|
||||
if (instance == null) {
|
||||
EmulatorConfig[] configs = (EmulatorConfig[]) FindObjectsOfType(typeof(EmulatorConfig));
|
||||
if (configs.Length == 1) {
|
||||
instance = configs[0];
|
||||
} else if (configs.Length > 1) {
|
||||
Debug.LogError(
|
||||
"Multiple PhoneRemote/Config objects in scene. Ignoring all.");
|
||||
}
|
||||
}
|
||||
if (instance == null) {
|
||||
var gameObject = new GameObject("PhoneRemoteConfig");
|
||||
instance = gameObject.AddComponent<EmulatorConfig>();
|
||||
DontDestroyOnLoad(instance);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
private static EmulatorConfig instance = null;
|
||||
|
||||
public enum Mode {
|
||||
OFF,
|
||||
USB,
|
||||
WIFI,
|
||||
}
|
||||
|
||||
// Set this value to match how the PC is connected to the phone that is
|
||||
// streaming gyro, accel, and touch events. Set to OFF if using Wifi instead.
|
||||
public Mode PHONE_EVENT_MODE = Mode.USB;
|
||||
|
||||
/*----- Internal Parameters (should not require any changes). -----*/
|
||||
|
||||
// IP address of the phone, when connected to the PC via USB.
|
||||
public static readonly string USB_SERVER_IP = "127.0.0.1";
|
||||
|
||||
// IP address of the phone, when connected to the PC via WiFi.
|
||||
public static readonly string WIFI_SERVER_IP = "192.168.43.1";
|
||||
}
|
||||
}
|
||||
/// @endcond
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a229fefd8ee7448b0b700f6000ebdec3
|
||||
timeCreated: 1462051657
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,189 @@
|
||||
// Copyright 2016 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.
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
using proto;
|
||||
|
||||
/// @cond
|
||||
namespace Gvr.Internal {
|
||||
struct EmulatorGyroEvent {
|
||||
public readonly long timestamp;
|
||||
public readonly Vector3 value;
|
||||
|
||||
public EmulatorGyroEvent(PhoneEvent.Types.GyroscopeEvent proto) {
|
||||
timestamp = proto.Timestamp;
|
||||
value = new Vector3(proto.X, proto.Y, proto.Z);
|
||||
}
|
||||
}
|
||||
|
||||
struct EmulatorAccelEvent {
|
||||
public readonly long timestamp;
|
||||
public readonly Vector3 value;
|
||||
|
||||
public EmulatorAccelEvent(PhoneEvent.Types.AccelerometerEvent proto) {
|
||||
timestamp = proto.Timestamp;
|
||||
value = new Vector3(proto.X, proto.Y, proto.Z);
|
||||
}
|
||||
}
|
||||
|
||||
struct EmulatorTouchEvent {
|
||||
// Action constants. These should match the constants in the Android
|
||||
// MotionEvent:
|
||||
// http://developer.android.com/reference/android/view/MotionEvent.html#ACTION_CANCEL
|
||||
public enum Action {
|
||||
kActionDown = 0,
|
||||
kActionUp = 1,
|
||||
kActionMove = 2,
|
||||
kActionCancel = 3,
|
||||
kActionPointerDown = 5,
|
||||
kActionPointerUp = 6,
|
||||
kActionHoverMove = 7,
|
||||
kActionHoverEnter = 9,
|
||||
kActionHoverExit = 10
|
||||
};
|
||||
|
||||
// Use getActionMasked() and getActionPointer() instead.
|
||||
private readonly int action;
|
||||
public readonly int relativeTimestamp;
|
||||
public readonly List<Pointer> pointers;
|
||||
|
||||
public struct Pointer {
|
||||
public readonly int fingerId;
|
||||
public readonly float normalizedX;
|
||||
public readonly float normalizedY;
|
||||
|
||||
public Pointer(int fingerId, float normalizedX, float normalizedY) {
|
||||
this.fingerId = fingerId;
|
||||
this.normalizedX = normalizedX;
|
||||
this.normalizedY = normalizedY;
|
||||
}
|
||||
|
||||
public override string ToString () {
|
||||
return string.Format ("({0}, {1}, {2})", fingerId, normalizedX,
|
||||
normalizedY);
|
||||
}
|
||||
}
|
||||
|
||||
public EmulatorTouchEvent(PhoneEvent.Types.MotionEvent proto, long lastDownTimeMs) {
|
||||
action = proto.Action;
|
||||
relativeTimestamp =
|
||||
(Action)(proto.Action & ACTION_MASK) == Action.kActionDown
|
||||
? 0 : (int) (proto.Timestamp - lastDownTimeMs);
|
||||
pointers = new List<Pointer>();
|
||||
foreach (PhoneEvent.Types.MotionEvent.Types.Pointer pointer in
|
||||
proto.PointersList) {
|
||||
pointers.Add(
|
||||
new Pointer(pointer.Id, pointer.NormalizedX, pointer.NormalizedY));
|
||||
}
|
||||
}
|
||||
|
||||
public EmulatorTouchEvent(Action action, int pointerId, int relativeTimestamp,
|
||||
List<Pointer> pointers) {
|
||||
int fingerIndex = 0;
|
||||
if (action == Action.kActionPointerDown
|
||||
|| action == Action.kActionPointerUp) {
|
||||
fingerIndex = findPointerIndex(pointerId, pointers);
|
||||
if (fingerIndex == -1) {
|
||||
Debug.LogWarning("Could not find specific fingerId " + pointerId
|
||||
+ " in the supplied list of pointers.");
|
||||
fingerIndex = 0;
|
||||
}
|
||||
}
|
||||
this.action = getActionUnmasked(action, fingerIndex);
|
||||
this.relativeTimestamp = relativeTimestamp;
|
||||
this.pointers = pointers;
|
||||
}
|
||||
|
||||
// See Android's getActionMasked() and getActionIndex().
|
||||
private static readonly int ACTION_POINTER_INDEX_SHIFT = 8;
|
||||
private static readonly int ACTION_POINTER_INDEX_MASK = 0xff00;
|
||||
private static readonly int ACTION_MASK = 0xff;
|
||||
|
||||
public Action getActionMasked() {
|
||||
return (Action)(action & ACTION_MASK);
|
||||
}
|
||||
|
||||
public Pointer getActionPointer() {
|
||||
int index =
|
||||
(action & ACTION_POINTER_INDEX_MASK) >> ACTION_POINTER_INDEX_SHIFT;
|
||||
return pointers[index];
|
||||
}
|
||||
|
||||
|
||||
private static int getActionUnmasked(Action action, int fingerIndex) {
|
||||
return ((int)action) | (fingerIndex << ACTION_POINTER_INDEX_SHIFT);
|
||||
}
|
||||
|
||||
private static int findPointerIndex(int fingerId, List<Pointer> pointers) {
|
||||
// Encode the fingerId info into the action, as Android does. See Android's
|
||||
// getActionMasked() and getActionIndex().
|
||||
int fingerIndex = -1;
|
||||
for (int i = 0; i < pointers.Count; i++) {
|
||||
if (fingerId == pointers[i].fingerId) {
|
||||
fingerIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return fingerIndex;
|
||||
}
|
||||
|
||||
public override string ToString () {
|
||||
System.Text.StringBuilder builder = new System.Text.StringBuilder ();
|
||||
builder.AppendFormat("t = {0}; A = {1}; P = {2}; N = {3}; [",
|
||||
relativeTimestamp, getActionMasked (), getActionPointer ().fingerId,
|
||||
pointers.Count);
|
||||
for (int i = 0; i < pointers.Count; i++) {
|
||||
builder.Append(pointers[i]).Append (", ");
|
||||
}
|
||||
builder.Append ("]");
|
||||
return builder.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
struct EmulatorOrientationEvent {
|
||||
public readonly long timestamp;
|
||||
public readonly Quaternion orientation;
|
||||
|
||||
public EmulatorOrientationEvent(PhoneEvent.Types.OrientationEvent proto) {
|
||||
timestamp = proto.Timestamp;
|
||||
// Convert from right-handed coordinates to left-handed.
|
||||
orientation = new Quaternion(proto.X, proto.Y, -proto.Z, proto.W);
|
||||
}
|
||||
}
|
||||
|
||||
struct EmulatorButtonEvent {
|
||||
// Codes as reported by the IC app (reuses Android KeyEvent codes).
|
||||
public enum ButtonCode {
|
||||
kNone = 0,
|
||||
kHome = 3, // android.view.KeyEvent.KEYCODE_HOME
|
||||
kVolumeUp = 25, // android.view.KeyEvent.KEYCODE_VOLUME_UP
|
||||
kVolumeDown = 24, // android.view.KeyEvent.KEYCODE_VOLUME_DOWN
|
||||
kClick = 66, // android.view.KeyEvent.KEYCODE_ENTER
|
||||
kApp = 82, // android.view.KeyEvent.KEYCODE_MENU
|
||||
}
|
||||
|
||||
public readonly ButtonCode code;
|
||||
public readonly bool down;
|
||||
public EmulatorButtonEvent(PhoneEvent.Types.KeyEvent proto) {
|
||||
code = (ButtonCode) proto.Code;
|
||||
down = proto.Action == 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
/// @endcond
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 76d2b695633884daf905c07095c8a01c
|
||||
timeCreated: 1462051657
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,250 @@
|
||||
// Copyright 2016 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.
|
||||
|
||||
// This class is only used in the Editor, so make sure to only compile it on that platform.
|
||||
// Additionally, it depends on EmulatorClientSocket which is only compiled in the editor.
|
||||
// This MonoBehaviour is only ever instantiated dynamically, so it is fine that it is only compiled in the Editor,
|
||||
// Otherwise it would cause serialization issues.
|
||||
#if UNITY_EDITOR
|
||||
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
|
||||
using proto;
|
||||
|
||||
/// @cond
|
||||
namespace Gvr.Internal {
|
||||
class EmulatorManager : MonoBehaviour {
|
||||
|
||||
private IEnumerator emulatorUpdate;
|
||||
private WaitForEndOfFrame waitForEndOfFrame = new WaitForEndOfFrame();
|
||||
|
||||
public static EmulatorManager Instance {
|
||||
get {
|
||||
if (instance == null) {
|
||||
var gameObject = new GameObject("PhoneRemote");
|
||||
instance = gameObject.AddComponent<EmulatorManager>();
|
||||
// This object should survive all scene transitions.
|
||||
GameObject.DontDestroyOnLoad(instance);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
private static EmulatorManager instance = null;
|
||||
|
||||
public delegate void OnGyroEvent(EmulatorGyroEvent gyroEvent);
|
||||
public event OnGyroEvent gyroEventListeners {
|
||||
add {
|
||||
if (value != null) {
|
||||
value(currentGyroEvent);
|
||||
}
|
||||
gyroEventListenersInternal += value;
|
||||
}
|
||||
|
||||
remove {
|
||||
gyroEventListenersInternal -= value;
|
||||
}
|
||||
}
|
||||
|
||||
public delegate void OnAccelEvent(EmulatorAccelEvent accelEvent);
|
||||
public event OnAccelEvent accelEventListeners {
|
||||
add {
|
||||
if (value != null) {
|
||||
value(currentAccelEvent);
|
||||
}
|
||||
accelEventListenersInternal += value;
|
||||
}
|
||||
|
||||
remove {
|
||||
accelEventListenersInternal -= value;
|
||||
}
|
||||
}
|
||||
|
||||
public delegate void OnTouchEvent(EmulatorTouchEvent touchEvent);
|
||||
public event OnTouchEvent touchEventListeners {
|
||||
add {
|
||||
if (value != null
|
||||
&& currentTouchEvent.pointers != null /* null only during init */) {
|
||||
value(currentTouchEvent);
|
||||
}
|
||||
touchEventListenersInternal += value;
|
||||
}
|
||||
|
||||
remove {
|
||||
touchEventListenersInternal -= value;
|
||||
}
|
||||
}
|
||||
|
||||
public delegate void OnOrientationEvent(EmulatorOrientationEvent orientationEvent);
|
||||
public event OnOrientationEvent orientationEventListeners {
|
||||
add {
|
||||
if (value != null) {
|
||||
value(currentOrientationEvent);
|
||||
}
|
||||
orientationEventListenersInternal += value;
|
||||
}
|
||||
|
||||
remove {
|
||||
orientationEventListenersInternal -= value;
|
||||
}
|
||||
}
|
||||
|
||||
public delegate void OnButtonEvent(EmulatorButtonEvent buttonEvent);
|
||||
public event OnButtonEvent buttonEventListeners {
|
||||
add {
|
||||
if (value != null) {
|
||||
value(currentButtonEvent);
|
||||
}
|
||||
buttonEventListenersInternal += value;
|
||||
}
|
||||
|
||||
remove {
|
||||
buttonEventListenersInternal -= value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void onGyroEvent(EmulatorGyroEvent e) {
|
||||
currentGyroEvent = e;
|
||||
if (gyroEventListenersInternal != null) {
|
||||
gyroEventListenersInternal(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void onAccelEvent(EmulatorAccelEvent e) {
|
||||
currentAccelEvent = e;
|
||||
if (accelEventListenersInternal != null) {
|
||||
accelEventListenersInternal(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void onTouchEvent(EmulatorTouchEvent e) {
|
||||
currentTouchEvent = e;
|
||||
if (touchEventListenersInternal != null) {
|
||||
touchEventListenersInternal(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void onOrientationEvent(EmulatorOrientationEvent e) {
|
||||
currentOrientationEvent = e;
|
||||
if (orientationEventListenersInternal != null) {
|
||||
orientationEventListenersInternal(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void onButtonEvent(EmulatorButtonEvent e) {
|
||||
currentButtonEvent = e;
|
||||
if (buttonEventListenersInternal != null) {
|
||||
buttonEventListenersInternal(e);
|
||||
}
|
||||
}
|
||||
|
||||
EmulatorGyroEvent currentGyroEvent;
|
||||
EmulatorAccelEvent currentAccelEvent;
|
||||
EmulatorTouchEvent currentTouchEvent;
|
||||
EmulatorOrientationEvent currentOrientationEvent;
|
||||
EmulatorButtonEvent currentButtonEvent;
|
||||
|
||||
private event OnGyroEvent gyroEventListenersInternal;
|
||||
private event OnAccelEvent accelEventListenersInternal;
|
||||
private event OnTouchEvent touchEventListenersInternal;
|
||||
private event OnOrientationEvent orientationEventListenersInternal;
|
||||
private event OnButtonEvent buttonEventListenersInternal;
|
||||
|
||||
private Queue pendingEvents = Queue.Synchronized(new Queue());
|
||||
private EmulatorClientSocket socket;
|
||||
private long lastDownTimeMs;
|
||||
|
||||
public bool Connected {
|
||||
get {
|
||||
return socket != null && socket.connected == EmulatorClientSocketConnectionState.Connected;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Connecting {
|
||||
get {
|
||||
return socket != null && socket.connected == EmulatorClientSocketConnectionState.Connecting;
|
||||
}
|
||||
}
|
||||
|
||||
public void Awake() {
|
||||
if (instance == null) {
|
||||
instance = this;
|
||||
}
|
||||
if (instance != this) {
|
||||
Debug.LogWarning("PhoneRemote must be a singleton.");
|
||||
enabled = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public void Start() {
|
||||
socket = gameObject.AddComponent<EmulatorClientSocket>();
|
||||
socket.Init(this);
|
||||
emulatorUpdate = EndOfFrame();
|
||||
StartCoroutine(emulatorUpdate);
|
||||
}
|
||||
|
||||
IEnumerator EndOfFrame() {
|
||||
while (true) {
|
||||
yield return waitForEndOfFrame;
|
||||
lock (pendingEvents.SyncRoot) {
|
||||
while (pendingEvents.Count > 0) {
|
||||
PhoneEvent phoneEvent = (PhoneEvent) pendingEvents.Dequeue();
|
||||
ProcessEventAtEndOfFrame(phoneEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnPhoneEvent(PhoneEvent e) {
|
||||
pendingEvents.Enqueue(e);
|
||||
}
|
||||
|
||||
private void ProcessEventAtEndOfFrame(PhoneEvent e) {
|
||||
switch (e.Type) {
|
||||
case PhoneEvent.Types.Type.MOTION:
|
||||
EmulatorTouchEvent touchEvent = new EmulatorTouchEvent(e.MotionEvent, lastDownTimeMs);
|
||||
onTouchEvent(touchEvent);
|
||||
if (touchEvent.getActionMasked() == EmulatorTouchEvent.Action.kActionDown) {
|
||||
lastDownTimeMs = e.MotionEvent.Timestamp;
|
||||
}
|
||||
break;
|
||||
case PhoneEvent.Types.Type.GYROSCOPE:
|
||||
EmulatorGyroEvent gyroEvent = new EmulatorGyroEvent(e.GyroscopeEvent);
|
||||
onGyroEvent(gyroEvent);
|
||||
break;
|
||||
case PhoneEvent.Types.Type.ACCELEROMETER:
|
||||
EmulatorAccelEvent accelEvent = new EmulatorAccelEvent(e.AccelerometerEvent);
|
||||
onAccelEvent(accelEvent);
|
||||
break;
|
||||
case PhoneEvent.Types.Type.ORIENTATION:
|
||||
EmulatorOrientationEvent orientationEvent =
|
||||
new EmulatorOrientationEvent(e.OrientationEvent);
|
||||
onOrientationEvent(orientationEvent);
|
||||
break;
|
||||
case PhoneEvent.Types.Type.KEY:
|
||||
EmulatorButtonEvent buttonEvent = new EmulatorButtonEvent(e.KeyEvent);
|
||||
onButtonEvent(buttonEvent);
|
||||
break;
|
||||
default:
|
||||
Debug.Log("Unsupported PhoneEvent type: " + e.Type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/// @endcond
|
||||
|
||||
#endif // UNITY_EDITOR
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c42ca6bb02b364893b127c681c158442
|
||||
timeCreated: 1462051658
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
3506
Assets/GoogleVR/Scripts/Controller/Internal/Emulator/PhoneEvent.cs
Normal file
3506
Assets/GoogleVR/Scripts/Controller/Internal/Emulator/PhoneEvent.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1a6b456eb0cd540a489e0f82c377b187
|
||||
timeCreated: 1462046540
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user