diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 7aed78d0347f6136a4dc16c13a3b2efbcfa641db..3d7b485b9bd1a13e131853c8cbb7d93dfd38b5b6 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -8,6 +8,7 @@
+
diff --git a/cloudphone/src/main/java/com/huawei/cloudphone/virtualdevice/location/VirtualLocation.java b/cloudphone/src/main/java/com/huawei/cloudphone/virtualdevice/location/VirtualLocation.java
index baef69718cb5b9cc64882fb2872276875041c760..8f93088f85200cbdb6eaac77a76191ec80c5c5ec 100644
--- a/cloudphone/src/main/java/com/huawei/cloudphone/virtualdevice/location/VirtualLocation.java
+++ b/cloudphone/src/main/java/com/huawei/cloudphone/virtualdevice/location/VirtualLocation.java
@@ -25,6 +25,9 @@ import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
+import android.location.GnssClock;
+import android.location.GnssMeasurement;
+import android.location.GnssMeasurementsEvent;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
@@ -42,6 +45,7 @@ import android.telephony.CellInfoGsm;
import android.telephony.CellInfoLte;
import android.telephony.CellInfoWcdma;
import android.telephony.TelephonyManager;
+import android.util.Log;
import androidx.annotation.RequiresApi;
import androidx.core.app.ActivityCompat;
@@ -51,32 +55,66 @@ import com.huawei.cloudphone.api.CloudPhonePermissionRequestListener;
import com.huawei.cloudphone.common.CASLog;
import com.huawei.cloudphone.virtualdevice.common.IVirtualDeviceDataListener;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.text.DecimalFormat;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
import java.util.List;
public class VirtualLocation {
private static final String TAG = "VirtualLocation";
private final long MIN_TIME = 1000;
+
+ private static final int GNSSPACKET_SIZE = 7361;
private final float MIN_DISTANCE = 1;
+ private final int TYPE_LOCATION = 0;
+ private final int TYPE_GNSS_MEASUREMENT = 1;
+
+ private static final int HAS_SNR = (1<<0);
+ private static final int HAS_CARRIER_FREQUENCY = (1<<9);
+ private static final int HAS_CARRIER_CYCLES = (1<<10);
+ private static final int HAS_CARRIER_PHASE = (1<<11);
+ private static final int HAS_CARRIER_PHASE_UNCERTAINTY = (1<<12);
+ private static final int HAS_AUTOMATIC_GAIN_CONTROL = (1<<13);
+
+ private static final int HAS_LEAP_SECOND = (1<<0);
+ private static final int HAS_TIME_UNCERTAINTY = (1<<1);
+ private static final int HAS_FULL_BIAS = (1<<2);
+ private static final int HAS_BIAS = (1<<3);
+ private static final int HAS_BIAS_UNCERTAINTY = (1<<4);
+ private static final int HAS_DRIFT = (1<<5);
+ private static final int HAS_DRIFT_UNCERTAINTY = (1<<6);
private Context mContext;
private Location mLocation;
private LocationManager mLocationManager;
private LocationListener mLocationListener;
+ private GnssMeasurementsEvent.Callback mGnssMeasurementsEventCallback;
private String mLocationProvider;
- private IVirtualDeviceDataListener mListener = null;
+ private IVirtualDeviceDataListener mLocationDataListener = null;
+ private IVirtualDeviceDataListener mGnssMeasurementsDataListener = null;
public VirtualLocation(Context context) {
mContext = context;
}
public void registerLocationDataListener(IVirtualDeviceDataListener listener) {
- mListener = listener;
+ mLocationDataListener = listener;
+ }
+
+ public void registerGnssMeasurementsDataListener(IVirtualDeviceDataListener listener) {
+ mGnssMeasurementsDataListener = listener;
}
@RequiresApi(api = Build.VERSION_CODES.P)
@SuppressLint("MissingPermission")
- public void requestLocationUpdates(CloudPhonePermissionRequestListener listener) {
+ public void requestUpdates(CloudPhonePermissionRequestListener listener, int type) {
if ((ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED)
&& (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED)) {
CASLog.i(TAG, "request coarse and fine location permission");
@@ -92,54 +130,86 @@ public class VirtualLocation {
if (mLocationManager == null) {
mLocationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
}
- boolean locationEnable = mLocationManager.isLocationEnabled();
- if (!locationEnable) {
- CASLog.i(TAG, "location enable is false");
- Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
- mContext.startActivity(intent);
- return;
+ if (type == TYPE_LOCATION) {
+ requestLocationUpdates();
+ } else if (type == TYPE_GNSS_MEASUREMENT) {
+ requestGnssMeasurementUpdates();
}
+ }
+ }
- List providers = mLocationManager.getProviders(true);
- if (providers.contains(LocationManager.GPS_PROVIDER)) {
- mLocationProvider = LocationManager.GPS_PROVIDER;
- } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
- mLocationProvider = LocationManager.NETWORK_PROVIDER;
- } else {
- return;
- }
- CASLog.i(TAG, "location provider is " + mLocationProvider);
- mLocationListener = new LocationListener() {
- @Override
- public void onLocationChanged(Location location) {
- if (location != null) {
- mLocation = location;
- String locationInfo = getLocationInfo(location);
- mListener.onRecvData(locationInfo);
- }
+ @RequiresApi(api = Build.VERSION_CODES.P)
+ @SuppressLint("MissingPermission")
+ private void requestLocationUpdates() {
+ if (mLocationManager == null) {
+ return;
+ }
+ boolean locationEnable = mLocationManager.isLocationEnabled();
+ if (!locationEnable) {
+ CASLog.i(TAG, "location enable is false");
+ Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
+ mContext.startActivity(intent);
+ return;
+ }
+ List providers = mLocationManager.getProviders(true);
+ if (providers.contains(LocationManager.GPS_PROVIDER)) {
+ mLocationProvider = LocationManager.GPS_PROVIDER;
+ } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
+ mLocationProvider = LocationManager.NETWORK_PROVIDER;
+ } else {
+ return;
+ }
+ CASLog.i(TAG, "location provider is " + mLocationProvider);
+ mLocationListener = new LocationListener() {
+ @Override
+ public void onLocationChanged(Location location) {
+ if (location != null) {
+ mLocation = location;
+ String locationInfo = getLocationInfo(location);
+ mLocationDataListener.onRecvData(locationInfo);
}
+ }
- @Override
- public void onStatusChanged(String s, int i, Bundle bundle) {
- }
+ @Override
+ public void onStatusChanged(String s, int i, Bundle bundle) {
+ }
- @Override
- public void onProviderEnabled(String s) {
- }
+ @Override
+ public void onProviderEnabled(String s) {
+ }
- @Override
- public void onProviderDisabled(String s) {
- }
- };
- mLocationManager.requestLocationUpdates(mLocationProvider, MIN_TIME, MIN_DISTANCE, mLocationListener, Looper.getMainLooper());
- mLocation = mLocationManager.getLastKnownLocation(mLocationProvider);
- String locationInfo = getLocationInfo(mLocation);
- if (locationInfo != null) {
- mListener.onRecvData(locationInfo);
+ @Override
+ public void onProviderDisabled(String s) {
}
+ };
+ mLocationManager.requestLocationUpdates(mLocationProvider, MIN_TIME, MIN_DISTANCE, mLocationListener, Looper.getMainLooper());
+ mLocation = mLocationManager.getLastKnownLocation(mLocationProvider);
+ String locationInfo = getLocationInfo(mLocation);
+ if (locationInfo != null) {
+ mLocationDataListener.onRecvData(locationInfo);
}
}
+ @SuppressLint("MissingPermission")
+ @RequiresApi(api = Build.VERSION_CODES.N)
+ private void requestGnssMeasurementUpdates() {
+ if (mLocationManager == null) {
+ return;
+ }
+ mGnssMeasurementsEventCallback = new GnssMeasurementsEvent.Callback() {
+ @Override
+ public void onGnssMeasurementsReceived(GnssMeasurementsEvent eventArgs) {
+ super.onGnssMeasurementsReceived(eventArgs);
+ try {
+ handleReceivedGnssMeasurements(eventArgs);
+ } catch (JSONException e) {
+ CASLog.e(TAG, "Failed to handle received gnss measurements");
+ }
+ }
+ };
+ mLocationManager.registerGnssMeasurementsCallback(mGnssMeasurementsEventCallback);
+ }
+
@SuppressLint("MissingPermission")
public void closeLocationUpdates() {
if (mLocationManager != null) {
@@ -150,6 +220,16 @@ public class VirtualLocation {
}
}
+ @RequiresApi(api = Build.VERSION_CODES.N)
+ public void closeGnssMeasurementUpdates() {
+ if (mLocationManager != null) {
+ mLocationManager.unregisterGnssMeasurementsCallback(mGnssMeasurementsEventCallback);
+ }
+ if (mGnssMeasurementsEventCallback != null) {
+ mGnssMeasurementsEventCallback = null;
+ }
+ }
+
private String getLocationInfo(Location location) {
if (location == null) {
return null;
@@ -223,6 +303,190 @@ public class VirtualLocation {
return null;
}
+ @RequiresApi(api = Build.VERSION_CODES.N)
+ private void handleReceivedGnssMeasurements(GnssMeasurementsEvent event) throws JSONException {
+ mGnssMeasurementsDataListener.onRecvData(getData(event));
+ }
+
+ @RequiresApi(api = Build.VERSION_CODES.N)
+ private static void gnssMeasurementData(ByteBuffer buffer, GnssMeasurement measurement) {
+ int flags = 0;
+
+ if (measurement.hasCarrierFrequencyHz()) {
+ flags = flags | HAS_CARRIER_FREQUENCY;
+ }
+
+ if (measurement.hasCarrierCycles()) {
+ flags = flags | HAS_CARRIER_CYCLES;
+ }
+
+ if (measurement.hasCarrierPhase()) {
+ flags = flags | HAS_CARRIER_PHASE;
+ }
+
+ if (measurement.hasCarrierPhaseUncertainty()) {
+ flags = flags | HAS_CARRIER_PHASE_UNCERTAINTY;
+ }
+
+ if (measurement.hasSnrInDb()) {
+ flags = flags | HAS_SNR;
+ }
+
+ if (SDK_INT >= Build.VERSION_CODES.O) {
+ if (measurement.hasAutomaticGainControlLevelDb()) {
+ flags = flags | HAS_AUTOMATIC_GAIN_CONTROL;
+ }
+ }
+
+ buffer.putInt((short) flags);
+ buffer.putShort((short) measurement.getSvid());
+ buffer.put((byte) measurement.getConstellationType());
+ buffer.putDouble(measurement.getTimeOffsetNanos());
+ buffer.putInt(measurement.getState());
+ buffer.putLong(measurement.getReceivedSvTimeNanos());
+ buffer.putLong(measurement.getReceivedSvTimeUncertaintyNanos());
+ buffer.putDouble(measurement.getCn0DbHz());
+ buffer.putDouble(measurement.getPseudorangeRateMetersPerSecond());
+ buffer.putDouble(measurement.getPseudorangeRateUncertaintyMetersPerSecond());
+ buffer.putShort((short) measurement.getAccumulatedDeltaRangeState());
+ buffer.putDouble(measurement.getAccumulatedDeltaRangeMeters());
+ buffer.putDouble(measurement.getAccumulatedDeltaRangeUncertaintyMeters());
+
+ if (measurement.hasCarrierFrequencyHz()) {
+ buffer.putFloat(measurement.getCarrierFrequencyHz());
+ } else {
+ buffer.putFloat(0);
+ }
+
+ if (measurement.hasCarrierCycles()) {
+ buffer.putLong(measurement.getCarrierCycles());
+ } else {
+ buffer.putLong(0);
+ }
+
+ if (measurement.hasCarrierPhase()) {
+ buffer.putDouble(measurement.getCarrierPhase());
+ } else {
+ buffer.putDouble(0);
+ }
+
+ if (measurement.hasCarrierPhaseUncertainty()) {
+ buffer.putDouble(measurement.getCarrierPhaseUncertainty());
+ } else {
+ buffer.putDouble(0);
+ }
+
+ buffer.put((byte) measurement.getMultipathIndicator());
+
+ if (measurement.hasSnrInDb()) {
+ buffer.putDouble(measurement.getSnrInDb());
+ } else {
+ buffer.putDouble(0);
+ }
+ }
+
+ @RequiresApi(api = Build.VERSION_CODES.N)
+ private static void gnssClockData(ByteBuffer buffer, GnssClock gnssClock) {
+ int flags = 0;
+
+ if (gnssClock.hasLeapSecond()) {
+ flags = flags | HAS_LEAP_SECOND;
+ }
+
+ if (gnssClock.hasTimeUncertaintyNanos()) {
+ flags = flags | HAS_TIME_UNCERTAINTY;
+ }
+
+ if (gnssClock.hasFullBiasNanos()) {
+ flags = flags | HAS_FULL_BIAS;
+ }
+
+ if (gnssClock.hasBiasNanos()) {
+ flags = flags | HAS_BIAS;
+ }
+
+ if (gnssClock.hasBiasUncertaintyNanos()) {
+ flags = flags | HAS_BIAS_UNCERTAINTY;
+ }
+
+ if (gnssClock.hasDriftNanosPerSecond()) {
+ flags = flags | HAS_DRIFT;
+ }
+
+ if (gnssClock.hasDriftUncertaintyNanosPerSecond()) {
+ flags = flags | HAS_DRIFT_UNCERTAINTY;
+ }
+
+ buffer.putShort((short) flags);
+ if (gnssClock.hasLeapSecond()) {
+ buffer.putShort((short) gnssClock.getLeapSecond());
+ } else {
+ buffer.putShort((short) 0);
+ }
+
+ buffer.putLong(gnssClock.getTimeNanos());
+
+ if (gnssClock.hasTimeUncertaintyNanos()) {
+ buffer.putDouble(gnssClock.getTimeUncertaintyNanos());
+ } else {
+ buffer.putDouble(0);
+ }
+
+ if (gnssClock.hasFullBiasNanos()) {
+ buffer.putLong(gnssClock.getFullBiasNanos());
+ } else {
+ buffer.putLong(0);
+ }
+
+ if (gnssClock.hasBiasNanos()) {
+ buffer.putDouble(gnssClock.getBiasNanos());
+ } else {
+ buffer.putDouble(0);
+ }
+
+ if (gnssClock.hasBiasUncertaintyNanos()) {
+ buffer.putDouble(gnssClock.getBiasUncertaintyNanos());
+ } else {
+ buffer.putDouble(0);
+ }
+
+ if (gnssClock.hasDriftNanosPerSecond()) {
+ buffer.putDouble(gnssClock.getDriftNanosPerSecond());
+ } else {
+ buffer.putDouble(0);
+ }
+
+ if (gnssClock.hasDriftUncertaintyNanosPerSecond()) {
+ buffer.putDouble(gnssClock.getDriftUncertaintyNanosPerSecond());
+ } else {
+ buffer.putDouble(0);
+ }
+
+ buffer.putInt(gnssClock.getHardwareClockDiscontinuityCount());
+ }
+
+ @RequiresApi(api = Build.VERSION_CODES.N)
+ public static ByteBuffer getData(GnssMeasurementsEvent event) {
+ // 创建ByteBuffer,大小为 gnssMeasurementPacket结构体的字节数
+ ByteBuffer buffer = ByteBuffer.allocate(GNSSPACKET_SIZE);
+
+ // 设置字节序为小端序(与packed属性相对应)
+ buffer.order(ByteOrder.BIG_ENDIAN);
+ gnssClockData(buffer, event.getClock());
+ buffer.put((byte) event.getMeasurements().size());
+
+ int measurementCount = 1;
+ for (GnssMeasurement measurement : event.getMeasurements()) {
+ // 当Measurement卫星数量大于64时,取前64个卫星中的数据
+ if (measurementCount > 64){
+ break;
+ }
+ gnssMeasurementData(buffer, measurement);
+ measurementCount+=1;
+ }
+ return buffer;
+ }
+
private class CellInfoData {
private String cellType = "";
private int mcc = -1;
diff --git a/cloudphone/src/main/java/com/huawei/cloudphone/virtualdevice/location/VirtualLocationManager.java b/cloudphone/src/main/java/com/huawei/cloudphone/virtualdevice/location/VirtualLocationManager.java
index 582bedf924bd167f053fdd955735367c2bb1f83b..6344bf65dd777f990e339d33cac8e27d8062f73b 100644
--- a/cloudphone/src/main/java/com/huawei/cloudphone/virtualdevice/location/VirtualLocationManager.java
+++ b/cloudphone/src/main/java/com/huawei/cloudphone/virtualdevice/location/VirtualLocationManager.java
@@ -11,24 +11,35 @@ import android.util.Log;
import androidx.annotation.RequiresApi;
import com.huawei.cloudphone.api.CloudPhonePermissionRequestListener;
+import com.huawei.cloudphone.common.CASLog;
import com.huawei.cloudphone.virtualdevice.common.IVirtualDeviceDataListener;
import com.huawei.cloudphone.virtualdevice.common.VirtualDeviceManager;
import com.huawei.cloudphone.virtualdevice.common.VirtualDeviceProtocol;
+import java.nio.ByteBuffer;
public class VirtualLocationManager extends VirtualDeviceManager {
private static final String TAG = "VirtualLocationManager";
public static final short OPT_LOCATION_OPEN_REQ = 0x0;
public static final short OPT_LOCATION_CLOSE_REQ = 0x1;
public static final short OPT_LOCATION_DATA = 0x2;
+ public static final short OPT_GNSS_MEASUREMENT_OPEN_REQ = 0x3;
+ public static final short OPT_GNSS_MEASUREMENT_CLOSE_REQ = 0x4;
+ public static final short OPT_GNSS_MEASUREMENT_DATA = 0x5;
private VirtualLocation mVirtualLocation;
private VirtualDeviceProtocol mVirtualDeviceProtocol;
private CloudPhonePermissionRequestListener mPermissionListener;
+ private boolean mIsLocationOpen = false;
+ private boolean mIsGnssMeasurementOpen = false;
+ private static final int TYPE_LOCATION = 0;
+ private static final int TYPE_GNSS_MEASUREMENT = 1;
+
public VirtualLocationManager(VirtualDeviceProtocol virtualDeviceProtocol, Context context) {
mVirtualDeviceProtocol = virtualDeviceProtocol;
mVirtualLocation = new VirtualLocation(context);
mVirtualLocation.registerLocationDataListener(new LocationDataListener());
+ mVirtualLocation.registerGnssMeasurementsDataListener(new GnssMeasurementsDataListener());
}
@Override
@@ -38,24 +49,44 @@ public class VirtualLocationManager extends VirtualDeviceManager {
@RequiresApi(api = Build.VERSION_CODES.P)
public void init() {
- mVirtualLocation.requestLocationUpdates(mPermissionListener);
+ if (mIsLocationOpen) {
+ mVirtualLocation.requestUpdates(mPermissionListener, TYPE_LOCATION);
+ }
+ if (mIsGnssMeasurementOpen) {
+ mVirtualLocation.requestUpdates(mPermissionListener, TYPE_GNSS_MEASUREMENT);
+ }
}
+ @RequiresApi(api = Build.VERSION_CODES.N)
public void stop() {
mVirtualLocation.closeLocationUpdates();
+ mVirtualLocation.closeGnssMeasurementUpdates();
}
@RequiresApi(api = Build.VERSION_CODES.P)
public void processMsg(VirtualDeviceProtocol.MsgHeader header, byte[] body) {
+ Log.i(TAG,"processMsg:" + header);
switch (header.mOptType) {
case OPT_LOCATION_OPEN_REQ:
Log.i(TAG, "processMsg: open location");
- mVirtualLocation.requestLocationUpdates(mPermissionListener);
+ mIsLocationOpen = true;
+ mVirtualLocation.requestUpdates(mPermissionListener, TYPE_LOCATION);
break;
case OPT_LOCATION_CLOSE_REQ:
Log.i(TAG, "processMsg: close location");
+ mIsLocationOpen = false;
mVirtualLocation.closeLocationUpdates();
break;
+ case OPT_GNSS_MEASUREMENT_OPEN_REQ:
+ Log.i(TAG, "processMsg: open gnss measurement");
+ mIsGnssMeasurementOpen = true;
+ mVirtualLocation.requestUpdates(mPermissionListener, TYPE_GNSS_MEASUREMENT);
+ break;
+ case OPT_GNSS_MEASUREMENT_CLOSE_REQ:
+ Log.i(TAG, "processMsg: close gnss measurement");
+ mIsGnssMeasurementOpen = false;
+ mVirtualLocation.closeGnssMeasurementUpdates();
+ break;
default:
Log.e(TAG, "processMsg: error opt type");
}
@@ -74,4 +105,19 @@ public class VirtualLocationManager extends VirtualDeviceManager {
mVirtualDeviceProtocol.sendMsg(header, rspBody, LOCATION_DATA);
}
}
+
+ class GnssMeasurementsDataListener implements IVirtualDeviceDataListener {
+
+ @Override
+ public void onRecvData(Object... args) {
+ int type = 0;
+ ByteBuffer body = (ByteBuffer) args[0];
+ int bodyLen = body.position();
+ int rspMsgLen = bodyLen + MSG_HEADER_LEN;
+ VirtualDeviceProtocol.MsgHeader header = new VirtualDeviceProtocol.MsgHeader(OPT_GNSS_MEASUREMENT_DATA, DEV_TYPE_LOCATION, (short) type, rspMsgLen);
+ byte[] rspBody = new byte[bodyLen];
+ System.arraycopy(body.array(), 0, rspBody, 0, bodyLen);
+ mVirtualDeviceProtocol.sendMsg(header, rspBody, LOCATION_DATA);
+ }
+ }
}
diff --git a/cloudphone/src/main/java/com/huawei/cloudphone/virtualdevice/sensor/VirtualSensor.java b/cloudphone/src/main/java/com/huawei/cloudphone/virtualdevice/sensor/VirtualSensor.java
index 0580a0e03c1e37d8dadc0bc9a198939ce566b12d..4c148529af95cf5a9cb41a3400b0639cbb9f18fd 100644
--- a/cloudphone/src/main/java/com/huawei/cloudphone/virtualdevice/sensor/VirtualSensor.java
+++ b/cloudphone/src/main/java/com/huawei/cloudphone/virtualdevice/sensor/VirtualSensor.java
@@ -23,20 +23,29 @@ import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
+import com.huawei.cloudphone.common.CASLog;
import com.huawei.cloudphone.virtualdevice.common.IVirtualDeviceDataListener;
+import com.huawei.cloudphone.virtualdevice.common.VirtualDeviceProtocol;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
public class VirtualSensor implements SensorEventListener {
private static final String TAG = "VirtualSensor";
private SensorManager mSensorManager;
- private Sensor mSensor;
- private Sensor mAccelerationSensor;
private IVirtualDeviceDataListener mListener = null;
private HandlerThread mHandlerThread;
+ private Handler mHandler;
+ private Sensor mSensor;
+ private Sensor mAccelerationSensor;
+
private boolean mIsStart = false;
+ private Map mSensorMap = new HashMap<>();
public VirtualSensor(SensorManager sensorManager) {
mSensorManager = sensorManager;
- mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
mAccelerationSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
}
@@ -44,44 +53,51 @@ public class VirtualSensor implements SensorEventListener {
mListener = listener;
}
- public void startProcess() {
- Log.i(TAG, "startProcess");
+ public void start() {
+ Log.i(TAG, "start");
if (mIsStart) {
return;
}
mHandlerThread = new HandlerThread("sensorThread");
mHandlerThread.start();
- Handler handler = new Handler(mHandlerThread.getLooper());
- mSensorManager.registerListener(this, mSensor, SensorManager.SENSOR_DELAY_GAME, handler);
- mSensorManager.registerListener(this, mAccelerationSensor, SensorManager.SENSOR_DELAY_GAME, handler);
+ mHandler = new Handler(mHandlerThread.getLooper());
mIsStart = true;
}
- public void stopProcess() {
- Log.i(TAG, "stopProcess");
+ public void stop() {
+ Log.i(TAG, "stop");
if (!mIsStart) {
return;
}
- mSensorManager.unregisterListener(this, mSensor);
- mSensorManager.unregisterListener(this, mAccelerationSensor);
mHandlerThread.getLooper().quit();
mIsStart = false;
}
+ public void startProcess(short sensorId) {
+ Log.i(TAG, "register sensor id " + sensorId);
+ if (sensorId == 1) {
+ mSensorManager.registerListener(this, mAccelerationSensor, SensorManager.SENSOR_DELAY_GAME, mHandler);
+ return;
+ }
+ mSensor = mSensorManager.getDefaultSensor(sensorId);
+ mSensorManager.registerListener(this, mSensor, SensorManager.SENSOR_DELAY_GAME, mHandler);
+ }
+
+ public void stopProcess(short sensorId) {
+ Log.i(TAG, "unregister sensor id " + sensorId);
+ if (sensorId == 1) {
+ mSensorManager.unregisterListener(this, mAccelerationSensor);
+ }
+ mSensor = mSensorManager.getDefaultSensor(sensorId);
+ mSensorManager.unregisterListener(this, mSensor);
+ }
+
@Override
public void onSensorChanged(SensorEvent sensorEvent) {
if (mListener == null) {
return;
}
- float x = sensorEvent.values[0];
- float y = sensorEvent.values[1];
- float z = sensorEvent.values[2];
- int type = sensorEvent.sensor.getType();
- if (type == Sensor.TYPE_ACCELEROMETER) {
- mListener.onRecvData(x, y, z, sensorEvent.accuracy, 0);
- } else if (type == Sensor.TYPE_GYROSCOPE) {
- mListener.onRecvData(x, y, z, sensorEvent.accuracy, 1);
- }
+ mListener.onRecvData(sensorEvent);
}
@Override
diff --git a/cloudphone/src/main/java/com/huawei/cloudphone/virtualdevice/sensor/VirtualSensorManager.java b/cloudphone/src/main/java/com/huawei/cloudphone/virtualdevice/sensor/VirtualSensorManager.java
index 561f2d62651dbf872c99b0fa7680017c4f1fa6b6..f93ce01034d8bb5c6d61394a5a3e6d61867e3421 100644
--- a/cloudphone/src/main/java/com/huawei/cloudphone/virtualdevice/sensor/VirtualSensorManager.java
+++ b/cloudphone/src/main/java/com/huawei/cloudphone/virtualdevice/sensor/VirtualSensorManager.java
@@ -19,43 +19,71 @@ import static com.huawei.cloudphone.api.CloudPhoneParas.DEV_TYPE_SENSOR;
import static com.huawei.cloudphone.jniwrapper.JNIWrapper.SENSOR_DATA;
import static com.huawei.cloudphone.virtualdevice.common.VirtualDeviceProtocol.MSG_HEADER_LEN;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
import android.hardware.SensorManager;
import android.util.Log;
+import com.huawei.cloudphone.common.CASLog;
import com.huawei.cloudphone.virtualdevice.common.IVirtualDeviceDataListener;
import com.huawei.cloudphone.virtualdevice.common.VirtualDeviceManager;
import com.huawei.cloudphone.virtualdevice.common.VirtualDeviceProtocol;
import com.huawei.cloudphone.virtualdevice.common.VirtualDeviceProtocol.MsgHeader;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
public class VirtualSensorManager extends VirtualDeviceManager {
private static final String TAG = "VirtualSensorManager";
- public static final short DEV_ACCELERATION = 0x0;
- public static final short DEV_GYROSCOPE = 0x1;
public static final short OPT_SENSOR_ENABLE_REQ = 0x1;
public static final short OPT_SENSOR_ENABLE_RSP = 0x1001;
public static final short OPT_SENSOR_DISABLE_REQ = 0x2;
public static final short OPT_SENSOR_DISABLE_RSP = 0x1002;
+ public static final short OPT_SENSOR_STATUS_RSP = 0x1003;
+ public static final short OPT_SENSOR_INFO_RSP = 0x1004;
public static final short OPT_SENSOR_DATA = 0x10;
+ private final int SENSOR_TYPE_WAKE_GESTURE = 23;
+ private final int SENSOR_TYPE_GLANCE_GESTURE = 24;
+ private final int SENSOR_TYPE_PICK_UP_GESTURE = 25;
+
private VirtualSensor mVirtualSensor;
private VirtualDeviceProtocol mVirtualDeviceProtocol;
+ private Set mOneShotSet = new HashSet(Arrays.asList(
+ Sensor.TYPE_SIGNIFICANT_MOTION, Sensor.TYPE_STATIONARY_DETECT, Sensor.TYPE_MOTION_DETECT,
+ SENSOR_TYPE_WAKE_GESTURE, SENSOR_TYPE_GLANCE_GESTURE, SENSOR_TYPE_PICK_UP_GESTURE
+ ));
public VirtualSensorManager(VirtualDeviceProtocol virtualDeviceProtocol, SensorManager sensorManager) {
mVirtualDeviceProtocol = virtualDeviceProtocol;
mVirtualSensor = new VirtualSensor(sensorManager);
+ mVirtualSensor.registerSensorDataListener(new SensorDataListener());
}
public void processMsg(MsgHeader header, byte[] body) {
+ short sensorId = header.mDeviceId;
switch (header.mOptType) {
case OPT_SENSOR_ENABLE_RSP:
- Log.i(TAG, "processMsg: enable sensor");
- mVirtualSensor.registerSensorDataListener(new SensorDataListener());
- mVirtualSensor.startProcess();
+ Log.i(TAG, "processMsg: sensor id " + sensorId + " enable");
+ mVirtualSensor.startProcess(sensorId);
break;
case OPT_SENSOR_DISABLE_RSP:
- Log.i(TAG, "processMsg: disable sensor");
- mVirtualSensor.stopProcess();
+ Log.i(TAG, "processMsg: sensor id " + sensorId + " disable");
+ mVirtualSensor.stopProcess(sensorId);
+ break;
+ case OPT_SENSOR_STATUS_RSP:
+ int status = (body[0] << 8) | (body[1] & 0x0FF);
+ Log.i(TAG, "processMsg: sensor id " + sensorId + " status " + status);
+ MsgHeader msgHeader;
+ if (status != 0) {
+ msgHeader = new MsgHeader(OPT_SENSOR_ENABLE_REQ, DEV_TYPE_SENSOR, sensorId, MSG_HEADER_LEN);
+ mVirtualDeviceProtocol.sendMsg(msgHeader, null, SENSOR_DATA);
+ } else {
+ header = new MsgHeader(OPT_SENSOR_DISABLE_REQ, DEV_TYPE_SENSOR, sensorId, MSG_HEADER_LEN);
+ mVirtualDeviceProtocol.sendMsg(header, null, SENSOR_DATA);
+ }
break;
default:
Log.e(TAG, "processMsg: error opt type");
@@ -63,38 +91,39 @@ public class VirtualSensorManager extends VirtualDeviceManager {
}
public void start() {
- int rspMsgLen = MSG_HEADER_LEN;
- MsgHeader header = new MsgHeader(OPT_SENSOR_ENABLE_REQ, DEV_TYPE_SENSOR, DEV_GYROSCOPE, rspMsgLen);
- mVirtualDeviceProtocol.sendMsg(header, null, SENSOR_DATA);
- header = new MsgHeader(OPT_SENSOR_ENABLE_REQ, DEV_TYPE_SENSOR, DEV_ACCELERATION, rspMsgLen);
- mVirtualDeviceProtocol.sendMsg(header, null, SENSOR_DATA);
+ Log.e(TAG, "start");
+ mVirtualSensor.start();
}
public void stop() {
- mVirtualSensor.stopProcess();
- int rspMsgLen = MSG_HEADER_LEN;
- MsgHeader header = new MsgHeader(OPT_SENSOR_DISABLE_REQ, DEV_TYPE_SENSOR, DEV_GYROSCOPE, rspMsgLen);
- mVirtualDeviceProtocol.sendMsg(header, null, SENSOR_DATA);
- header = new MsgHeader(OPT_SENSOR_DISABLE_REQ, DEV_TYPE_SENSOR, DEV_ACCELERATION, rspMsgLen);
- mVirtualDeviceProtocol.sendMsg(header, null, SENSOR_DATA);
+ Log.e(TAG, "stop");
+ mVirtualSensor.stop();
}
class SensorDataListener implements IVirtualDeviceDataListener {
@Override
public void onRecvData(Object... args) {
- String xStr = Float.valueOf((float) args[0]).toString();
- String yStr = Float.valueOf((float) args[1]).toString();
- String zStr = Float.valueOf((float) args[2]).toString();
- String accurateStr = Integer.valueOf((int) args[3]).toString();
- String body = xStr + ":" + yStr + ":" + zStr + ":" + accurateStr + ":";
- int type = (int) args[4];
+ SensorEvent sensorEvent = (SensorEvent) args[0];
+ StringBuilder stringBuilder = new StringBuilder();
+ for (int i = 0; i < sensorEvent.values.length; i++) {
+ stringBuilder.append(Float.valueOf(sensorEvent.values[i]).toString() + ":");
+ }
+ stringBuilder.append(Integer.valueOf(sensorEvent.accuracy).toString() + ":");
+ String body = stringBuilder.toString();
+ int sensorId = sensorEvent.sensor.getType();
int bodyLen = body.getBytes().length;
int rspMsgLen = bodyLen + MSG_HEADER_LEN;
- MsgHeader header = new MsgHeader(OPT_SENSOR_DATA, DEV_TYPE_SENSOR, (short)type, rspMsgLen);
+ MsgHeader header = new MsgHeader(OPT_SENSOR_DATA, DEV_TYPE_SENSOR, (short)sensorId, rspMsgLen);
byte[] rspBody = new byte[bodyLen];
System.arraycopy(body.getBytes(), 0, rspBody, 0, bodyLen);
mVirtualDeviceProtocol.sendMsg(header, rspBody, SENSOR_DATA);
+ // oneshot模式需主动发送0x2
+ if (mOneShotSet.contains(sensorId)) {
+ header = new MsgHeader(OPT_SENSOR_DISABLE_REQ, DEV_TYPE_SENSOR, (short)sensorId, MSG_HEADER_LEN);
+ mVirtualDeviceProtocol.sendMsg(header, null, SENSOR_DATA);
+ mVirtualSensor.stopProcess((short)sensorId);
+ }
}
}
-}
+}
\ No newline at end of file