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