diff --git a/app/src/main/java/com/huawei/cloudapp/ui/activity/CasCloudPhoneActivity.java b/app/src/main/java/com/huawei/cloudapp/ui/activity/CasCloudPhoneActivity.java index 3494f9cef125fc7841019b22804c034c45072f41..c525802df5bcabd9ffa40d513640950a2adf723b 100644 --- a/app/src/main/java/com/huawei/cloudapp/ui/activity/CasCloudPhoneActivity.java +++ b/app/src/main/java/com/huawei/cloudapp/ui/activity/CasCloudPhoneActivity.java @@ -181,6 +181,10 @@ public class CasCloudPhoneActivity extends FragmentActivity implements IHandleDa private TextView mNavigationTextView; private TextView mStatisticsTextView; private CheckBox mStatisticsCheckBox; + + private TextView mSensorInfoTextView; + + private CheckBox mSensorInfoCheckBox; private Timer mTimer = new Timer(); private boolean isReadyToExit; private Toast mToast; @@ -278,9 +282,26 @@ public class CasCloudPhoneActivity extends FragmentActivity implements IHandleDa mTimer.schedule(new TimerTask() { @Override public void run() { - runOnUiThread(() -> onUpdateStatisticInfo()); + runOnUiThread(() -> { + onUpdateSensorInfo(); + onUpdateStatisticInfo(); + }); + } + }, 1000, 1000); + + mSensorInfoTextView = findViewById(R.id.cas_sensor_view); + mSensorInfoTextView.setTextColor(Color.GREEN); + + mSensorInfoCheckBox = findViewById(R.id.cas_sensor_checkBox); + mSensorInfoCheckBox.setOnCheckedChangeListener((buttonView, isChecked) -> { + if (isChecked) { + mSensorInfoTextView.setVisibility(View.VISIBLE); + float density = getResources().getDisplayMetrics().density; + mSensorInfoTextView.setHeight((int) (50 * density)); + } else { + mSensorInfoTextView.setVisibility(View.INVISIBLE); } - }, 1000, 1000); // 1000 毫秒后执行,之后每隔 1000 毫秒执行一次 + }); mNavigationTextView = findViewById(R.id.cas_navigaiton); mNavigationTextView.setOnTouchListener(new View.OnTouchListener() { @@ -360,6 +381,16 @@ public class CasCloudPhoneActivity extends FragmentActivity implements IHandleDa mStatisticsTextView.setText(str); } + public void onUpdateSensorInfo() { + if (mSensorInfoTextView.getVisibility() != View.VISIBLE) { + return; + } + + String str = "传感器启停状况>>"; + str += mCloudPhone.getSensorStatusInfo(); + mSensorInfoTextView.setText(str); + } + /** * Activity:onStart */ @@ -732,6 +763,10 @@ public class CasCloudPhoneActivity extends FragmentActivity implements IHandleDa return; } CASLog.d(TAG, "stop cloud phone"); + if (mTimer != null) { + mTimer.cancel(); + mTimer = null; + } handler.removeCallbacksAndMessages(null); mIsStopCloudPhoneCalled = true; mProgressBar.setVisibility(View.VISIBLE); diff --git a/app/src/main/res/layout/cas_activity_fullscreen.xml b/app/src/main/res/layout/cas_activity_fullscreen.xml index f170d41be6a4fe2a3aa44692e9c778a827ba4cd1..dd685cb17503954d1927851601d3f22c34d574f1 100644 --- a/app/src/main/res/layout/cas_activity_fullscreen.xml +++ b/app/src/main/res/layout/cas_activity_fullscreen.xml @@ -24,18 +24,37 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="165dp" + android:layout_marginStart="20dp" + android:layout_gravity="start" /> + + + + GetCmdSendStats(&cmdSendStats)) { + WARN("GetCmdSendStats failed"); + } else { + stream << "指令发送码率(需操作) : " << cmdSendStats.encBitrate << "kbps" << std::endl; + } } #endif stream << "帧率 : " << GetCurrentFPS() << "fps" << std::endl; diff --git a/cloudphone/src/main/cpp/libs/Arm64/libmtrans.a b/cloudphone/src/main/cpp/libs/Arm64/libmtrans.a index af361d9ba15ba74d1dd334dee88284ea8cca3b87..1306a9e703a6f76f085da496d2aef1022cb0e303 100644 Binary files a/cloudphone/src/main/cpp/libs/Arm64/libmtrans.a and b/cloudphone/src/main/cpp/libs/Arm64/libmtrans.a differ diff --git a/cloudphone/src/main/cpp/libs/mtrans/include/net_trans.h b/cloudphone/src/main/cpp/libs/mtrans/include/net_trans.h index 6b11c44a087f2c447a03e5fd94dee624a10087e6..c7029119c7b8f5b21f454527ce04baa4cf6c3c23 100644 --- a/cloudphone/src/main/cpp/libs/mtrans/include/net_trans.h +++ b/cloudphone/src/main/cpp/libs/mtrans/include/net_trans.h @@ -54,6 +54,7 @@ public: int GetVideoRecvStats(StreamRecvStats* stats); int GetAudioRecvStats(StreamRecvStats* stats); int GetRtt(); + int GetCmdSendStats(StreamSendStats* stats); private: class NetTransPri; diff --git a/cloudphone/src/main/cpp/libs/mtrans/include/net_trans_def.h b/cloudphone/src/main/cpp/libs/mtrans/include/net_trans_def.h index f5c4331975f6fe04a45d8c525cd51a28fa6dd51e..cd9af0b8e1ae07e816114ac534e2a4c4b4627875 100644 --- a/cloudphone/src/main/cpp/libs/mtrans/include/net_trans_def.h +++ b/cloudphone/src/main/cpp/libs/mtrans/include/net_trans_def.h @@ -115,6 +115,33 @@ struct StreamRecvStats { }; }; +struct VideoSendStats { + uint32_t sendFrameRate; + uint32_t availableEncBitrate; + uint32_t inputFrameCnt; + uint32_t sendFrameCnt; + uint32_t redRate; + uint32_t recvKeyRequestCnt; + uint32_t recvNackRequestCnt; + uint32_t nackResponsePktCnt; + uint32_t nackNotRspCnt; +}; + +struct StreamSendStats { + uint32_t encBitrate; + uint32_t fecBitrate; + uint32_t arqBitrate; + uint32_t packetRate; + uint32_t rtt; + uint32_t remoteJitter; + uint32_t remoteLostRate; + uint32_t pacingSendMaxDelay; + uint32_t pacingSendAveDelay; + uint32_t periodNotSendPktCnt; + uint64_t periodNotSendPktTime; + VideoSendStats videoStats; +}; + typedef int32_t (*RecvVideoDataCallback)(uint8_t* data, uint32_t length); typedef int32_t (*RecvAudioDataCallback)(uint8_t* data, uint32_t length); typedef int32_t (*RecvAudioDecodeCallback)(int32_t streamId, AudioJbDecode* audioJbDecode); diff --git a/cloudphone/src/main/java/com/huawei/cloudphone/api/ICloudPhone.java b/cloudphone/src/main/java/com/huawei/cloudphone/api/ICloudPhone.java index dfb1c5db1f699f474b0654f6253de29fb238052a..dc0f818ff6ea4c0a54cbf6257d5a78dcdf18b3cf 100644 --- a/cloudphone/src/main/java/com/huawei/cloudphone/api/ICloudPhone.java +++ b/cloudphone/src/main/java/com/huawei/cloudphone/api/ICloudPhone.java @@ -154,4 +154,6 @@ public interface ICloudPhone { int getState(); String getVideoStatisticInfo(); + + String getSensorStatusInfo(); } diff --git a/cloudphone/src/main/java/com/huawei/cloudphone/apiimpl/CloudPhoneImpl.java b/cloudphone/src/main/java/com/huawei/cloudphone/apiimpl/CloudPhoneImpl.java index 734f7e06efc6ecddef4b39a907386ead85c944b4..1f2ed91eebbae317460619f5fe5c23c9aa2fd828 100644 --- a/cloudphone/src/main/java/com/huawei/cloudphone/apiimpl/CloudPhoneImpl.java +++ b/cloudphone/src/main/java/com/huawei/cloudphone/apiimpl/CloudPhoneImpl.java @@ -57,6 +57,7 @@ import com.huawei.cloudphone.virtualdevice.camera.VirtualCameraManager; import com.huawei.cloudphone.virtualdevice.common.RingBufferVirtualDeviceIO; import com.huawei.cloudphone.virtualdevice.common.VirtualDeviceManager; import com.huawei.cloudphone.virtualdevice.common.VirtualDeviceProtocol; +import com.huawei.cloudphone.virtualdevice.sensor.VirtualSensorManager; import java.util.HashMap; import java.util.Map; @@ -67,6 +68,7 @@ import static android.view.KeyEvent.KEYCODE_BACK; import static android.view.KeyEvent.KEYCODE_VOLUME_DOWN; import static android.view.KeyEvent.KEYCODE_VOLUME_UP; import static com.huawei.cloudphone.api.CloudPhoneParas.DEV_TYPE_CAMERA; +import static com.huawei.cloudphone.api.CloudPhoneParas.DEV_TYPE_SENSOR; import static com.huawei.cloudphone.api.CloudPhoneParas.DisplayMode.DISPLAY_MODE_FILL; import static com.huawei.cloudphone.common.CasState.CAS_CONNECT_EXCEPTION; import static com.huawei.cloudphone.utils.CasMediaUtils.isValidMediaConfig; @@ -355,6 +357,19 @@ public class CloudPhoneImpl implements ICloudPhone { } } + @Override + public String getSensorStatusInfo() { + VirtualDeviceProtocol virtualDevice = mVirtualDeviceSession.getVirtualDevice(); + if (virtualDevice == null) { + return ""; + } + VirtualDeviceManager virtualDeviceManager = virtualDevice.getVirtualDeviceManager(DEV_TYPE_SENSOR); + if (virtualDeviceManager == null) { + return ""; + } + return ((VirtualSensorManager) virtualDeviceManager).getSensorStatus(); + } + @Override public int getState() { return mCurrentState; 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 4c148529af95cf5a9cb41a3400b0639cbb9f18fd..303e56ed0d47168ded34b602dbe33255a4634d90 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,11 +23,9 @@ 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.lang.reflect.Type; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -43,10 +41,56 @@ public class VirtualSensor implements SensorEventListener { private boolean mIsStart = false; private Map mSensorMap = new HashMap<>(); + private Map mSensorActiveMap = new HashMap<>(); + + private Map mSensorTypeToNameMap = new HashMap(){{ + + put(Sensor.TYPE_PROXIMITY, "接近传感器"); + put(Sensor.TYPE_GRAVITY, "重力传感器"); + put(Sensor.TYPE_LINEAR_ACCELERATION, "线性加速度传感器"); + put(Sensor.TYPE_ROTATION_VECTOR, "旋转矢量传感器"); + put(Sensor.TYPE_RELATIVE_HUMIDITY, "湿度传感器"); + put(Sensor.TYPE_AMBIENT_TEMPERATURE, "温度传感器"); + put(Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED, "未校准磁力传感器"); + put(Sensor.TYPE_GAME_ROTATION_VECTOR, "游戏矢量传感器"); + put(Sensor.TYPE_GYROSCOPE_UNCALIBRATED, "未校准陀螺仪"); + put(Sensor.TYPE_SIGNIFICANT_MOTION, "大幅动作传感器"); + put(Sensor.TYPE_STEP_DETECTOR, "步数检测器"); + put(Sensor.TYPE_STEP_COUNTER, "计步器"); + put(Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR, "地磁旋转矢量传感器"); + put(Sensor.TYPE_HEART_RATE, "心率传感器"); + put(Sensor.TYPE_POSE_6DOF, "6向姿势传感器"); + put(Sensor.TYPE_STATIONARY_DETECT, "静止检测传感器"); + put(Sensor.TYPE_MOTION_DETECT, "运动检测传感器"); + put(Sensor.TYPE_HEART_BEAT, "心跳传感器"); + put(Sensor.TYPE_LOW_LATENCY_OFFBODY_DETECT, "低延迟离开身体检测"); + put(Sensor.TYPE_ACCELEROMETER_UNCALIBRATED, "未校准加速度传感器"); + put(Sensor.TYPE_ACCELEROMETER, "加速度传感器"); + put(Sensor.TYPE_MAGNETIC_FIELD, "磁力传感器"); + put(Sensor.TYPE_ORIENTATION, "方向传感器"); + put(Sensor.TYPE_GYROSCOPE, "陀螺仪"); + put(Sensor.TYPE_LIGHT, "光线传感器"); + put(Sensor.TYPE_PRESSURE, "压力传感器"); + put(Sensor.TYPE_TEMPERATURE, "温度传感器2"); + put(22, "倾斜检测传感器"); + put(23, "手势唤醒传感器"); + put(24, "快览手势传感器"); + put(25, "唤醒手势传感器"); + put(26, "抬腕倾斜传感器"); + put(27, "设备方向传感器"); + }}; public VirtualSensor(SensorManager sensorManager) { mSensorManager = sensorManager; mAccelerationSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); + List sensorList = mSensorManager.getSensorList(Sensor.TYPE_ALL); + for (Sensor sensor: sensorList) { + int type = sensor.getType(); + if (type >= Sensor.TYPE_DEVICE_PRIVATE_BASE) { + continue; + } + mSensorActiveMap.put(type, false); + } } void registerSensorDataListener(IVirtualDeviceDataListener listener) { @@ -75,6 +119,10 @@ public class VirtualSensor implements SensorEventListener { public void startProcess(short sensorId) { Log.i(TAG, "register sensor id " + sensorId); + + if (mSensorActiveMap.containsKey((int) sensorId)) { + mSensorActiveMap.replace((int) sensorId, true); + } if (sensorId == 1) { mSensorManager.registerListener(this, mAccelerationSensor, SensorManager.SENSOR_DELAY_GAME, mHandler); return; @@ -85,6 +133,11 @@ public class VirtualSensor implements SensorEventListener { public void stopProcess(short sensorId) { Log.i(TAG, "unregister sensor id " + sensorId); + + if (mSensorActiveMap.containsKey((int) sensorId)) { + mSensorActiveMap.replace((int) sensorId, false); + } + if (sensorId == 1) { mSensorManager.unregisterListener(this, mAccelerationSensor); } @@ -92,6 +145,26 @@ public class VirtualSensor implements SensorEventListener { mSensorManager.unregisterListener(this, mSensor); } + public String getSensorStatus() { + StringBuilder status = new StringBuilder(); + + for (Map.Entry entry : mSensorActiveMap.entrySet()) { + status.append("\n"); + status.append(getSensorNameByType(entry.getKey())); + status.append(" : "); + if (entry.getValue()) { + status.append("启用"); + } else { + status.append("关闭"); + } + } + return status.toString(); + } + + private String getSensorNameByType(Integer type) { + return mSensorTypeToNameMap.getOrDefault(type, type.toString()); + } + @Override public void onSensorChanged(SensorEvent sensorEvent) { if (mListener == null) { 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 f93ce01034d8bb5c6d61394a5a3e6d61867e3421..40410e7dd3580228ab3fed7e01af7eeea8b6ab5a 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 @@ -24,7 +24,6 @@ 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; @@ -100,6 +99,10 @@ public class VirtualSensorManager extends VirtualDeviceManager { mVirtualSensor.stop(); } + public String getSensorStatus() { + return mVirtualSensor.getSensorStatus(); + } + class SensorDataListener implements IVirtualDeviceDataListener { @Override public void onRecvData(Object... args) {