diff --git a/app/build.gradle b/app/build.gradle index 4c0274f37b7bb29e40e9acb97e7c86ef480da40d..55292f658c256cfb0ba9039883911aa241c37fca 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -74,7 +74,7 @@ dependencies { implementation 'androidx.cardview:cardview:1.0.0' annotationProcessor 'com.github.bumptech.glide:compiler:4.14.0' implementation 'com.hyman:flowlayout-lib:1.1.2' - implementation 'com.github.Petterpx:FloatingX:1.3.3' + // implementation 'com.github.Petterpx:FloatingX:1.3.3' implementation 'com.android.support:design:28.0.0' implementation 'com.github.shem8:material-login:2.1.1' implementation 'com.github.Justson.AgentWeb:agentweb-core:v5.0.6-androidx' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 5575ca1a46bee3c88af2757865851f4567af68f5..a0492d33e72d3645d73a859e7e1f2fe36af56ca9 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -8,9 +8,11 @@ + + requestBody = new HashMap(); @@ -914,7 +919,7 @@ public class CasCloudPhoneActivity extends FragmentActivity { connectorInfo.setSessionId(sessionId); connectorInfo.setTicket("ticket_xxxxxx"); // 32位16进制数,测试使用 - connectorInfo.setAesKey("11111111111111111111111111111111"); + connectorInfo.setAesKey("d252bf88dccf4affa7c490f707a37dd2"); connectorInfo.setAuthTs("987654321"); connectorInfo.setTouchTimeout(touchTimeout.isEmpty() ? "0" : touchTimeout); return connectorInfo; diff --git a/cloudphone/src/main/cpp/cas_common/CasMsg.h b/cloudphone/src/main/cpp/cas_common/CasMsg.h index f591ff846bf06edc253bc95cfe1d0f24a3088df5..3f58e511f89cb1f206e90049814e0122e44c1f7e 100644 --- a/cloudphone/src/main/cpp/cas_common/CasMsg.h +++ b/cloudphone/src/main/cpp/cas_common/CasMsg.h @@ -39,6 +39,7 @@ enum CasMsgType : uint8_t { VirtualMicrophone = 22, VirtualSensor = 23, VirtualLocation = 24, + VirtualVibrator = 25, End, }; diff --git a/cloudphone/src/main/cpp/cas_stream/CasStreamRecvParser.cpp b/cloudphone/src/main/cpp/cas_stream/CasStreamRecvParser.cpp index 09746b90d9944d7f2f12a1a03801807f5d773186..6439dfc24279450567628bea9cbdb95aece221ea 100644 --- a/cloudphone/src/main/cpp/cas_stream/CasStreamRecvParser.cpp +++ b/cloudphone/src/main/cpp/cas_stream/CasStreamRecvParser.cpp @@ -75,7 +75,7 @@ void CasStreamRecvParser::SetServiceHandle(unsigned char type, CasPktHandle *ser CasPktHandle *CasStreamRecvParser::GetServiceHandle(unsigned char type) { - return VirtualLocation >= type && type >= VirtualCamera ? m_serviceHandles[VirtualDevice] : m_serviceHandles[type]; + return VirtualVibrator >= type && type >= VirtualCamera ? m_serviceHandles[VirtualDevice] : m_serviceHandles[type]; } CasStreamParseThread::CasStreamParseThread(CasSocket *socket, CasStreamRecvParser *streamRecvParser) diff --git a/cloudphone/src/main/java/com/huawei/cloudphone/api/CloudPhoneParas.java b/cloudphone/src/main/java/com/huawei/cloudphone/api/CloudPhoneParas.java index 1abef3663c31777417328c7886a2987f65d9312c..729c0d81908e7b1dacfd90b7f5eed0aaa4ad57af 100644 --- a/cloudphone/src/main/java/com/huawei/cloudphone/api/CloudPhoneParas.java +++ b/cloudphone/src/main/java/com/huawei/cloudphone/api/CloudPhoneParas.java @@ -31,4 +31,5 @@ public class CloudPhoneParas { public static final short DEV_TYPE_MICROPHONE = 2; public static final short DEV_TYPE_SENSOR = 3; public static final short DEV_TYPE_LOCATION = 4; + public static final short DEV_TYPE_VIBRATOR = 5; } diff --git a/cloudphone/src/main/java/com/huawei/cloudphone/service/CasProcessor.java b/cloudphone/src/main/java/com/huawei/cloudphone/service/CasProcessor.java index 1185123efa54d2520deb7012ed1f246e115158f7..24e25d9c327ac7874c6fb67adbd8f6f1a330d91f 100644 --- a/cloudphone/src/main/java/com/huawei/cloudphone/service/CasProcessor.java +++ b/cloudphone/src/main/java/com/huawei/cloudphone/service/CasProcessor.java @@ -285,6 +285,7 @@ public class CasProcessor { jsonObj.put("user_id", connectorInfo.getUserId()); jsonObj.put("touch_timeout", connectorInfo.getTouchTimeout()); // 加密信息 + CASLog.i(TAG, "aeskey = " + connectorInfo.getAesKey()); String encryptedData = CasAESUtils.encryptWithAESGCM(jsonObj.toString(), connectorInfo.getAesKey(), connectorInfo.getAesIv()); return encryptedData; } diff --git a/cloudphone/src/main/java/com/huawei/cloudphone/virtualdevice/common/VirtualDeviceProtocol.java b/cloudphone/src/main/java/com/huawei/cloudphone/virtualdevice/common/VirtualDeviceProtocol.java index 16906a5ac97aca5931b60a17aba8351617847163..b8e347aa74a8d3120d9ac7aa7feb95769f213e6f 100644 --- a/cloudphone/src/main/java/com/huawei/cloudphone/virtualdevice/common/VirtualDeviceProtocol.java +++ b/cloudphone/src/main/java/com/huawei/cloudphone/virtualdevice/common/VirtualDeviceProtocol.java @@ -19,6 +19,7 @@ import static com.huawei.cloudphone.api.CloudPhoneParas.DEV_TYPE_CAMERA; import static com.huawei.cloudphone.api.CloudPhoneParas.DEV_TYPE_LOCATION; import static com.huawei.cloudphone.api.CloudPhoneParas.DEV_TYPE_MICROPHONE; import static com.huawei.cloudphone.api.CloudPhoneParas.DEV_TYPE_SENSOR; +import static com.huawei.cloudphone.api.CloudPhoneParas.DEV_TYPE_VIBRATOR; import android.content.Context; import android.hardware.SensorManager; @@ -29,6 +30,7 @@ import com.huawei.cloudphone.virtualdevice.camera.VirtualCameraManager; import com.huawei.cloudphone.virtualdevice.location.VirtualLocationManager; import com.huawei.cloudphone.virtualdevice.microphone.VirtualMicrophoneManager; import com.huawei.cloudphone.virtualdevice.sensor.VirtualSensorManager; +import com.huawei.cloudphone.virtualdevice.vibrator.VirtualVibratorManager; import java.util.HashMap; import java.util.Map; @@ -56,6 +58,7 @@ public class VirtualDeviceProtocol { virtualDeviceManagers.put(DEV_TYPE_SENSOR, new VirtualSensorManager(this, (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE))); virtualDeviceManagers.put(DEV_TYPE_LOCATION, new VirtualLocationManager(this, mContext)); + virtualDeviceManagers.put(DEV_TYPE_VIBRATOR, new VirtualVibratorManager(this, mContext)); // 设置权限监听 if (listener != null) { @@ -85,6 +88,7 @@ public class VirtualDeviceProtocol { public void processMsg(MsgHeader header, byte[] body) { short devType = header.mDeviceType; + Log.e(TAG, "processMsg: device type :" + header.mDeviceType); if (devType == 0) devType = DEV_TYPE_SENSOR; VirtualDeviceManager virtualDeviceManager = virtualDeviceManagers.get(devType); if (virtualDeviceManager == null) { 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..8e477acc9ea72e28b01b25f701a4a8641069376c 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,64 @@ 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 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,52 +128,84 @@ 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") @@ -150,6 +218,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 +301,361 @@ public class VirtualLocation { return null; } + @RequiresApi(api = Build.VERSION_CODES.N) + private void handleReceivedGnssMeasurements(GnssMeasurementsEvent event) throws JSONException { + JSONObject gnssMesurementsJson = new JSONObject(); + + JSONObject gnssClockJsonObject = gnssClockToJsonObject(event.getClock()); + gnssMesurementsJson.put("clock", gnssClockJsonObject); + + JSONArray gnssMesurementsJsonArray = new JSONArray(); + JSONObject jsonObject; + List measurements = (List) event.getMeasurements(); + // 云手机接口文档最大64个,取64个卫星,当大于64时如何选择 + int measurementCount = measurements.size() <= 64 ? measurements.size() : 64; + for (int i = 0; i < measurementCount; i++) { + jsonObject = gnssMeasurementToJsonObject(measurements.get(i)); + gnssMesurementsJsonArray.put(jsonObject); + } + + gnssMesurementsJson.put("measurements", gnssMesurementsJsonArray); + // Log.i(TAG,"jwt gnssMesurementsJson:" + gnssMesurementsJson.toString()); + mGnssMeasurementsDataListener.onRecvData(getData(event)); + //mGnssMeasurementsDataListener.onRecvData(gnssMesurementsJson.toString()); + } + + @RequiresApi(api = Build.VERSION_CODES.N) + private JSONObject gnssClockToJsonObject(GnssClock gnssClock) throws JSONException { + DecimalFormat numberFormat = new DecimalFormat("#.#"); + JSONObject jsonObject = new JSONObject(); + int flags = 0; + + if (gnssClock.hasLeapSecond()) { + flags = flags | HAS_LEAP_SECOND; + jsonObject.put("leapSecond", gnssClock.getLeapSecond()); + } + + jsonObject.put("timeNs", gnssClock.getTimeNanos()); + + if (gnssClock.hasTimeUncertaintyNanos()) { + flags = flags | HAS_TIME_UNCERTAINTY; +// jsonObject.put("timeUncertaintyNs", numberFormat.format(gnssClock.getTimeUncertaintyNanos())); + jsonObject.put("timeUncertaintyNs", gnssClock.getTimeUncertaintyNanos()); + } + + if (gnssClock.hasFullBiasNanos()) { + flags = flags | HAS_FULL_BIAS; + jsonObject.put("fullBiasNs", gnssClock.getFullBiasNanos()); + } + + if (gnssClock.hasBiasNanos()) { + flags = flags | HAS_BIAS; +// jsonObject.put("biasNs", numberFormat.format(gnssClock.getBiasNanos())); + jsonObject.put("biasNs", gnssClock.getBiasNanos()); + } + + if (gnssClock.hasBiasUncertaintyNanos()) { + flags = flags | HAS_BIAS_UNCERTAINTY; +// jsonObject.put("biasUncertaintyNs", numberFormat.format(gnssClock.getBiasUncertaintyNanos())); + jsonObject.put("biasUncertaintyNs", gnssClock.getBiasUncertaintyNanos()); + } + + if (gnssClock.hasDriftNanosPerSecond()) { + flags = flags | HAS_DRIFT; +// jsonObject.put("driftNsps", numberFormat.format(gnssClock.getDriftNanosPerSecond())); + jsonObject.put("driftNsps", gnssClock.getDriftNanosPerSecond()); + } + + if (gnssClock.hasDriftUncertaintyNanosPerSecond()) { + flags = flags | HAS_DRIFT_UNCERTAINTY; +// jsonObject.put("driftUncertaintyNsps", numberFormat.format(gnssClock.getDriftUncertaintyNanosPerSecond())); + jsonObject.put("driftUncertaintyNsps", gnssClock.getDriftUncertaintyNanosPerSecond()); + } + + jsonObject.put("hwClockDiscontinuityCount", gnssClock.getHardwareClockDiscontinuityCount()); + jsonObject.put("flags", flags); + return jsonObject; + } + + private static boolean DEBUG = true; + + @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); + } + //buffer.putDouble(measurement.getAutomaticGainControlLevelDb()); + if (DEBUG) + Log.i(TAG, "taotao" + buffer.position() + " =====>:" + Arrays.toString(buffer.array())); + DEBUG = false; + } + + @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()); + if (DEBUG) + Log.i(TAG, "taotao" + buffer.position() + " =====>:" + Arrays.toString(buffer.array())); + } + + @RequiresApi(api = Build.VERSION_CODES.N) + private JSONObject gnssMeasurementToJsonObject(GnssMeasurement measurement) throws JSONException { + DecimalFormat numberFormat = new DecimalFormat("#.#"); + JSONObject jsonObject = new JSONObject(); + int flags = 0; + + jsonObject.put("svid", measurement.getSvid()); + jsonObject.put("constellation", measurement.getConstellationType()); +// jsonObject.put("timeOffsetNs", numberFormat.format(measurement.getTimeOffsetNanos())); + jsonObject.put("timeOffsetNs", measurement.getTimeOffsetNanos()); + jsonObject.put("state", measurement.getState()); + jsonObject.put("receivedSvTimeInNs", measurement.getReceivedSvTimeNanos()); + jsonObject.put("receivedSvTimeUncertaintyInNs", measurement.getReceivedSvTimeUncertaintyNanos()); +// jsonObject.put("cN0Dbhz", numberFormat.format(measurement.getCn0DbHz())); +// jsonObject.put("pseudorangeRateMps", numberFormat.format(measurement.getPseudorangeRateMetersPerSecond())); +// jsonObject.put("pseudorangeRateUncertaintyMps", numberFormat.format(measurement.getPseudorangeRateUncertaintyMetersPerSecond())); + + jsonObject.put("cN0Dbhz", measurement.getCn0DbHz()); + jsonObject.put("pseudorangeRateMps", measurement.getPseudorangeRateMetersPerSecond()); + jsonObject.put("pseudorangeRateUncertaintyMps", measurement.getPseudorangeRateUncertaintyMetersPerSecond()); + + jsonObject.put("accumulatedDeltaRangeState", measurement.getAccumulatedDeltaRangeState()); +// jsonObject.put("accumulatedDeltaRangeM", numberFormat.format(measurement.getAccumulatedDeltaRangeMeters())); +// jsonObject.put("accumulatedDeltaRangeUncertaintyM", numberFormat.format(measurement.getAccumulatedDeltaRangeUncertaintyMeters())); + + jsonObject.put("accumulatedDeltaRangeM", measurement.getAccumulatedDeltaRangeMeters()); + jsonObject.put("accumulatedDeltaRangeUncertaintyM", measurement.getAccumulatedDeltaRangeUncertaintyMeters()); + + if (measurement.hasCarrierFrequencyHz()) { + flags = flags | HAS_CARRIER_FREQUENCY; +// jsonObject.put("carrierFrequencyHz", numberFormat.format(measurement.getCarrierFrequencyHz())); + jsonObject.put("carrierFrequencyHz", measurement.getCarrierFrequencyHz()); + } + + if (measurement.hasCarrierCycles()) { + flags = flags | HAS_CARRIER_CYCLES; + jsonObject.put("carrierCycles", measurement.getCarrierCycles()); + } + + if (measurement.hasCarrierPhase()) { + flags = flags | HAS_CARRIER_PHASE; +// jsonObject.put("carrierPhase", numberFormat.format(measurement.getCarrierPhase())); + jsonObject.put("carrierPhase", measurement.getCarrierPhase()); + } + + if (measurement.hasCarrierPhaseUncertainty()) { + flags = flags | HAS_CARRIER_PHASE_UNCERTAINTY; +// jsonObject.put("carrierPhaseUncertainty", numberFormat.format(measurement.getCarrierPhaseUncertainty())); + jsonObject.put("carrierPhaseUncertainty", measurement.getCarrierPhaseUncertainty()); + } + + jsonObject.put("multipathIndicator", measurement.getMultipathIndicator()); + + if (measurement.hasSnrInDb()) { + flags = flags | HAS_SNR; +// jsonObject.put("snrDb", numberFormat.format(measurement.getSnrInDb())); + jsonObject.put("snrDb", measurement.getSnrInDb()); + } + + if (SDK_INT >= Build.VERSION_CODES.O) { + if (measurement.hasAutomaticGainControlLevelDb()) { + flags = flags | HAS_AUTOMATIC_GAIN_CONTROL; +// jsonObject.put("agcLevelDb", numberFormat.format(measurement.getAutomaticGainControlLevelDb())); + jsonObject.put("agcLevelDb", measurement.getAutomaticGainControlLevelDb()); + } + } + + jsonObject.put("flags", flags); + return jsonObject; + } + + public static String byteArrayToString(byte[] byteArray) { + StringBuilder sb = new StringBuilder(); + for (byte b : byteArray) { + sb.append(String.format("%02X ", b)); + } + return sb.toString().trim(); + } + @RequiresApi(api = Build.VERSION_CODES.N) + public static ByteBuffer getData(GnssMeasurementsEvent event) { + // 创建ByteBuffer,大小为结构体的字节数 + ByteBuffer buffer = ByteBuffer.allocate(7896); + + // 设置字节序为小端序(与packed属性相对应) + buffer.order(ByteOrder.BIG_ENDIAN); + gnssClockData(buffer, event.getClock()); +/* byte[] data = new byte[buffer.position()]; + System.arraycopy(buffer.array(),0,data,0,data.length); + CASLog.i(TAG, "jwt gnssClockData ===> %s",byteArrayToString(data));*/ + buffer.put((byte) event.getMeasurements().size()); + int x = (byte) event.getMeasurements().size(); + CASLog.i(TAG, "jwt event.getMeasurements().size()=%d", x); + + int measurementCount = 1; + for (GnssMeasurement measurement : event.getMeasurements()) { + if (measurementCount > 64){ + break; + } + + byte Constellation = (byte)measurement.getConstellationType(); + int svid = measurement.getSvid(); + double pseudorangeRateMps = measurement.getPseudorangeRateMetersPerSecond(); + long receivedSvTimeInNs = measurement.getReceivedSvTimeNanos(); + short accumulatedDeltaRangeState = (short)measurement.getAccumulatedDeltaRangeState(); + int state = measurement.getState(); + float carrierFrequencyHz= measurement.getCarrierFrequencyHz(); + //CASLog.i(TAG, "jwt Constellation=%d", Constellation); + CASLog.i(TAG, "jwt measurementCount=%d, svid=%d, Constellation=%d, pseudorangeRateMps=%f, receivedSvTimeInNs=%d, accumulatedDeltaRangeState=%d, state=%d, carrierFrequencyHz = %f" + + "",measurementCount, svid , Constellation, pseudorangeRateMps, receivedSvTimeInNs, accumulatedDeltaRangeState, state, carrierFrequencyHz); + 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..2fda54c36d0f4d684b58aade8a191dd8ca256b83 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"); } @@ -68,10 +99,30 @@ public class VirtualLocationManager extends VirtualDeviceManager { int type = 0; int bodyLen = body.getBytes().length; int rspMsgLen = bodyLen + MSG_HEADER_LEN; + CASLog.i(TAG, "location bodyLen=" + bodyLen + " body=" + body); VirtualDeviceProtocol.MsgHeader header = new VirtualDeviceProtocol.MsgHeader(OPT_LOCATION_DATA, DEV_TYPE_LOCATION, (short) type, rspMsgLen); byte[] rspBody = new byte[bodyLen]; System.arraycopy(body.getBytes(), 0, rspBody, 0, bodyLen); mVirtualDeviceProtocol.sendMsg(header, rspBody, LOCATION_DATA); } } + + class GnssMeasurementsDataListener implements IVirtualDeviceDataListener { + + @Override + public void onRecvData(Object... args) { +// String body = (String) args[0]; + int type = 0; +// int bodyLen = body.getBytes().length; + ByteBuffer body = (ByteBuffer) args[0]; + int bodyLen = body.position(); + CASLog.i(TAG, "gnssMeasurements size=" + bodyLen); + 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); +// System.arraycopy(body.getBytes(), 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..e6d3aeea774408f83df75dc3677230a4b2050683 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,65 +23,86 @@ 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); +// List sensorList = mSensorManager.getSensorList(Sensor.TYPE_ALL); +// CASLog.i(TAG, "sensor list size " + sensorList.size()); +// for (Sensor sensor : sensorList) { +// mSensorMap.put(sensor.getType(), mSensorManager.getDefaultSensor(sensor.getType())); +// } } void registerSensorDataListener(IVirtualDeviceDataListener listener) { 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..48b9c7d03052f5b1962692d595b01fcb8ec80b7b 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,40 @@ 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); + CASLog.i(TAG, "sensorid=" + sensorId + " bodyLen=" + bodyLen + " body=" + body); + 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 diff --git a/cloudphone/src/main/java/com/huawei/cloudphone/virtualdevice/vibrator/VirtualVibrator.java b/cloudphone/src/main/java/com/huawei/cloudphone/virtualdevice/vibrator/VirtualVibrator.java new file mode 100644 index 0000000000000000000000000000000000000000..e795dc7903b13ae4246201f531653aae98642797 --- /dev/null +++ b/cloudphone/src/main/java/com/huawei/cloudphone/virtualdevice/vibrator/VirtualVibrator.java @@ -0,0 +1,54 @@ +/* + * Copyright 2023 Huawei Cloud Computing Technology Co., Ltd. + * + * 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. + */ +package com.huawei.cloudphone.virtualdevice.vibrator; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.os.Vibrator; + +import com.huawei.cloudphone.common.CASLog; +import com.huawei.cloudphone.virtualdevice.common.VirtualDeviceProtocol; + +public class VirtualVibrator { + private static final String TAG = "VirtualVibrator"; + + private Context mContext; + private Vibrator mVibrator; + + public VirtualVibrator(Context context) { + mContext = context; + mVibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE); + } + + @SuppressLint("MissingPermission") + public void startVibrate(VirtualDeviceProtocol.MsgHeader header, byte[] body) { + if (!mVibrator.hasVibrator()) { + return; + } + long vibrateTime = ((body[0] << 24) | (body[1] << 16) | (body[2] << 8) | (body[3])); + CASLog.i(TAG, "vibrate time is " + vibrateTime); + mVibrator.cancel(); +// mVibrator.vibrate(vibrateTime); + } + + @SuppressLint("MissingPermission") + public void stopVibrate() { + if (!mVibrator.hasVibrator()) { + return; + } + mVibrator.cancel(); + } +} \ No newline at end of file diff --git a/cloudphone/src/main/java/com/huawei/cloudphone/virtualdevice/vibrator/VirtualVibratorManager.java b/cloudphone/src/main/java/com/huawei/cloudphone/virtualdevice/vibrator/VirtualVibratorManager.java new file mode 100644 index 0000000000000000000000000000000000000000..dd522a7af635499bd978d756ad921352e12b1f69 --- /dev/null +++ b/cloudphone/src/main/java/com/huawei/cloudphone/virtualdevice/vibrator/VirtualVibratorManager.java @@ -0,0 +1,36 @@ +package com.huawei.cloudphone.virtualdevice.vibrator; + +import android.content.Context; + +import com.huawei.cloudphone.common.CASLog; +import com.huawei.cloudphone.virtualdevice.common.VirtualDeviceManager; +import com.huawei.cloudphone.virtualdevice.common.VirtualDeviceProtocol; + +public class VirtualVibratorManager extends VirtualDeviceManager { + private static final String TAG = "VirtualVibratorManager"; + public static final short OPT_VIBRATOR_START_REQ = 0x1; + public static final short OPT_VIBRATOR_STOP_REQ = 0x2; + + private VirtualVibrator mVirtualVibrator; + private VirtualDeviceProtocol mVirtualDeviceProtocol; + + public VirtualVibratorManager(VirtualDeviceProtocol virtualDeviceProtocol, Context context) { + mVirtualDeviceProtocol = virtualDeviceProtocol; + mVirtualVibrator = new VirtualVibrator(context); + } + + public void processMsg(VirtualDeviceProtocol.MsgHeader header, byte[] body) { + switch (header.mOptType) { + case OPT_VIBRATOR_START_REQ: + CASLog.i(TAG, "processMsg: start vibrate"); + mVirtualVibrator.startVibrate(header, body); + break; + case OPT_VIBRATOR_STOP_REQ: + CASLog.i(TAG, "processMsg: stop vibrate"); + mVirtualVibrator.stopVibrate(); + break; + default: + CASLog.e(TAG, "processMsg: error opt type"); + } + } +}