更新时间:2025-09-11 GMT+08:00
代码示例
串流页面:
public class HuaweiCloudActivity extends AppCompatActivity {
private static final String TAG = "HuaweiCloudActivity";
private PlayerFragment mPlayerFragment;
private LinearLayout float_opt;
private CountDownTimer inactivityTimer;
private static final long INACTIVITY_TIMEOUT = 3000; // 3秒
private int failedNum;
private Bundle extras;
private LoadingLayout mLoadingLayout;
private static Integer timer = 0;
private CloudPhoneCallBack callBack ;
private Handler mHandler = new Handler();
@SuppressLint("MissingInflatedId")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initView(savedInstanceState);
ActivityManager.addActivity(this);
}
private void initView(Bundle savedInstanceState){
View decorView = getWindow().getDecorView();
Log.i(TAG, "======onCreate(Bundle savedInstanceState)");
int uiOptions =
View.SYSTEM_UI_FLAG_FULLSCREEN // 隐藏状态栏
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // 隐藏导航栏
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; // 沉浸式模式(触摸后自动恢复)
decorView.setSystemUiVisibility(uiOptions);
// 监听变化,防止退出沉浸模式
decorView.setOnSystemUiVisibilityChangeListener(visibility -> {
if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
decorView.setSystemUiVisibility(uiOptions);
}
});
setContentView(R.layout.activity_huawei_cloud);
initPlayer(savedInstanceState);
}
@Override
public boolean dispatchGenericMotionEvent(MotionEvent event) {
// 手柄事件
if (event.isFromSource(InputDevice.SOURCE_JOYSTICK) && event.getAction() == MotionEvent.ACTION_MOVE) {
CloudPhoneClient.sendJoypadEvent(event);
// 轴MotionEvent事件会额外触发对应的keyEvent
return true;
}
return super.onGenericMotionEvent(event);
}
private static final Set<Integer> JOYSTICK_KEYCODE_SET = new HashSet<>(
Arrays.asList(
// 方向键
KeyEvent.KEYCODE_DPAD_UP,
KeyEvent.KEYCODE_DPAD_DOWN,
KeyEvent.KEYCODE_DPAD_LEFT,
KeyEvent.KEYCODE_DPAD_RIGHT,
// ABXY
KeyEvent.KEYCODE_BUTTON_A,
KeyEvent.KEYCODE_BUTTON_B,
KeyEvent.KEYCODE_BUTTON_X,
KeyEvent.KEYCODE_BUTTON_Y,
// 左右肩键
KeyEvent.KEYCODE_BUTTON_L1,
KeyEvent.KEYCODE_BUTTON_L2,
KeyEvent.KEYCODE_BUTTON_R1,
KeyEvent.KEYCODE_BUTTON_R2,
// 左右摇杆按下
KeyEvent.KEYCODE_BUTTON_THUMBL,
KeyEvent.KEYCODE_BUTTON_THUMBR,
// 通用功能键
KeyEvent.KEYCODE_BUTTON_SELECT,
KeyEvent.KEYCODE_BUTTON_START
));
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
// 转发手柄对应的按键
int keyCode = event.getKeyCode();
if (JOYSTICK_KEYCODE_SET.contains(keyCode)) {
CloudPhoneClient.sendKeyEvent(keyCode, event.getAction());
return true;
}
return super.dispatchKeyEvent(event);
}
@Override
protected void onResume() {
Log.i(TAG, "======onResume()");
super.onResume();
// Activity恢复时重置计时器
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
CloudPhoneClient.bindFragment(mPlayerFragment);
CloudPhoneClient.switchStreamType(CloudPhoneConst.CLOUD_APP_SWITCH_STREAM_TYPE.BOTH);
}
@Override
protected void onPause() {
Log.i(TAG, "======onPause()");
super.onPause();
// Activity暂停时取消计时器
// inactivityTimer.cancel();
}
@Override
protected void onStop() {
Log.i(TAG, "======onStop()");
super.onStop();
}
@Override
protected void onStart() {
Log.i(TAG, "======onStart()");
super.onStart();
}
private void initPlayer(Bundle savedInstanceState) {
mPlayerFragment = (PlayerFragment) getFragmentManager().findFragmentById(R.id.fragment_player);
callBack = CloudPhoneCallBack.getInstance();
callBack.setProfileHandler(this::profileReceived);
CloudPhoneClient.setPlayerCallback(callBack);
CloudPhoneClient.setPlayerType(HMTP_PLAYER);
// CloudPhoneClient.enableAudioKeeping(true);
CloudPhoneClient.bindFragment(mPlayerFragment);
CloudPhoneClient.switchStreamType(CloudPhoneConst.CLOUD_APP_SWITCH_STREAM_TYPE.BOTH);
// CloudPhoneClient.switchStreamType(CloudPhoneConst.CLOUD_APP_SWITCH_STREAM_TYPE.BOTH);
//执行串流的,串流结果成功会从onSuccsss返回通知,失败则是onFailure带code
// CloudPhoneClient.start(mPlayerFragment, extras);
}
private void logBundleContents(Bundle bundle) {
if (bundle == null) return;
Log.i(TAG, "Bundle contains " + bundle.size() + " items:");
for (String key : bundle.keySet()) {
Log.i(TAG, key + " = " + bundle.get(key));
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
Log.i(TAG, "======onSaveInstanceState()");
NetworkInfoComp.netWorkMap.remove("帧率");
NetworkInfoComp.netWorkMap.remove("下行流量");
NetworkInfoComp.netWorkMap.remove("延迟");
super.onSaveInstanceState(outState);
outState.putBundle("EXTRA_BUNDLE", getIntent().getExtras());
}
@Override
protected void onDestroy() {
Log.i(TAG, "======onDestroy()");
super.onDestroy();
CloudPhoneClient.setUnPlayerCallback(callBack);
mHandler.removeCallbacksAndMessages(null);
ActivityManager.removeActivity(this);
}
private boolean isFmActive() {
final AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
if (am == null) {
Log.w(TAG, "isFmActive: couldn't get AudioManager reference");
return false;
}
return am.isMusicActive();
}
/**
* 再次连接
*/
private void linkAgain() {
//执行串流的,串流结果成功会从onSuccsss返回通知,失败则是onFailure带code
CloudPhoneClient.stop();
CloudPhoneClient.start(mPlayerFragment, extras);
onResume();
}
public void profileReceived(String s) {
NetInfo netInfo = JSONUtil.fromJson(s, NetInfo.class);
int rrt = Integer.parseInt(netInfo.getRtt().replaceAll("[^0-9]", ""));
if(rrt>100){
// CloudPhoneClient.setProfile(1);
timer = 3;
} else if (rrt<80) {
timer = Math.max(0, timer - 1);
if(timer==0){
// CloudPhoneClient.setProfile(0);
}
}
if(AppApplication.getInstance().getDebugMode()) {
String numberStr = netInfo.getBr().replaceAll("[^0-9.]", "");
String letters = netInfo.getBr().replaceAll("[^a-zA-Z]", "").toUpperCase();
double v = Double.parseDouble(numberStr) / 8;
DecimalFormat df = new DecimalFormat("#0.00");
String formattedResult = df.format(v);
List<NetworkConfig> networkConfigList = AppApplication.getInstance().getDebugConfig();
if(networkConfigList.stream().anyMatch(item->item.getLabel().equals("发送帧"))){
NetworkInfoComp.netWorkMap.put("发送帧", netInfo.getFps());
}
if(networkConfigList.stream().anyMatch(item->item.getLabel().equals("下行流量"))){
NetworkInfoComp.netWorkMap.put("下行流量",formattedResult+letters);
}
if(networkConfigList.stream().anyMatch(item->item.getLabel().equals("网络延迟"))){
NetworkInfoComp.netWorkMap.put("网络延迟", netInfo.getRtt());
}
NetworkInfoComp.reloadGirdView();
}
Log.i(TAG, "======onProfileReceived(String s).s="+s);
}
}
回调处理对象:
package com.KooCabin.service;
import android.app.Activity;
import android.util.Log;
import androidx.core.util.Consumer;
import com.KooCabin.activity.HuaweiCloudActivity;
import com.KooCabin.base.BasePresenter;
import com.KooCabin.ui.playerfloat.FloatWindowMainView;
import com.cloudphone.client.api.CloudPhoneClient;
import com.cloudphone.client.api.CloudPhoneConst;
import com.cloudphone.client.bean.AppInfo;
import com.cloudphone.client.bean.AppLifeCycle;
import com.cloudphone.client.bean.AppOperateResponse;
import com.cloudphone.client.bean.DiskUsageInfo;
import com.cloudphone.client.bean.GetAppsRsp;
import com.huawei.kp.KPClientStat;
import com.huawei.kp.KPCloudStat;
import lombok.Setter;
@Setter
public class CloudPhoneCallBack implements CloudPhoneClient.Callback, CloudPhoneClient.Callback.AppCallback {
private static volatile CloudPhoneCallBack instance;
// 私有构造方法
private CloudPhoneCallBack() {
// 防止外部实例化
}
// 公共静态获取实例方法
public static CloudPhoneCallBack getInstance() {
if (instance == null) {
synchronized (CloudPhoneCallBack.class) {
if (instance == null) {
instance = new CloudPhoneCallBack();
}
}
}
return instance;
}
private static final String TAG = "CloudPhoneCallback";
private Consumer<AppOperateResponse<GetAppsRsp>> appHandler;
private Consumer<Void> startHandler;
private Consumer<AppOperateResponse<String>> unInstallHandler;
private Consumer<AppOperateResponse<String>> unLoadAppHandler;
private Consumer<AppOperateResponse<String>> startAppHandler;
private Consumer<AppOperateResponse<String>> closeAppHandler;
private Consumer<String> profileHandler;
private Consumer<Void> streamSuccessHandler;
private Consumer<AppOperateResponse<DiskUsageInfo>> usageHandler;
@Override
public void onGetInstalledApps(AppOperateResponse<GetAppsRsp> appOperateResponse) {
if(appHandler != null) {
appHandler.accept(appOperateResponse);
}
Log.i(TAG, "onGetInstalledApps success");
}
@Override
public void onSuccess() {
if(streamSuccessHandler!=null){
streamSuccessHandler.accept(null);
}
}
@Override
public void onTerminated() {
}
@Override
public void onFailure(int i, String s) {
}
@Override
public void onMenuOnClick(Activity activity, int i) {
}
@Override
public String getUrl() {
return "";
}
@Override
public void lifecycle(Activity activity, int i) {
}
@Override
public void onOrientationChange(int i) {
}
@Override
public void onSlotsInfo(String s) {
}
@Override
public void onRoomInfoUpdate(String s) {
}
@Override
public void onPermissionRequest(String s) {
}
@Override
public void onPermissionResult(String s) {
}
@Override
public void onProfileReceived(String s) {
if(profileHandler!=null){
profileHandler.accept(s);
}
}
@Override
public void onProfileChanged(int i, boolean b) {
}
@Override
public void onExitConfirm(int i) {
}
@Override
public void onUserExit() {
}
@Override
public void onExtMessageReceived(Activity activity, String s) {
}
@Override
public void onScreenshotUpdate(String s, String s1) {
}
@Override
public void onScreenshotAuthFailed(String s) {
}
@Override
public void onKicked(String s) {
}
@Override
public void onPermissionGranted(String[] strings) {
}
@Override
public void onPermissionDenied(String[] strings) {
}
@Override
public void onHttpResponse(String s) {
}
@Override
public void onActionMessage(String s) {
}
@Override
public void onPerfLog(int i, String s) {
}
@Override
public void onSensorInjectEvent(String s) {
}
@Override
public void onCloudStatistics(KPCloudStat kpCloudStat) {
}
@Override
public void onClientStatistics(KPClientStat kpClientStat) {
}
@Override
public void onStreamStarted() {
Log.i("11111", "onStreamStarted======onSuccess()");
// CloudPhoneClient.switchStreamType(CloudPhoneConst.CLOUD_APP_SWITCH_STREAM_TYPE.BOTH);
if(startHandler!=null){
startHandler.accept(null);
}
}
@Override
public void onCloseApp(AppOperateResponse<String> appOperateResponse) {
Log.i("11111", "======onCloseApp()");
if(closeAppHandler!=null){
closeAppHandler.accept(appOperateResponse);
}
}
@Override
public void onStartApp(AppOperateResponse<String> appOperateResponse) {
Log.i("CALLBACK:","=====onStartApp=======");
if(startAppHandler!=null){
startAppHandler.accept(appOperateResponse);
}
}
@Override
public void onGetRunningApps(AppOperateResponse<GetAppsRsp> appOperateResponse) {
if(appHandler!=null){
appHandler.accept(appOperateResponse);
}
}
@Override
public void onRestartApp(AppOperateResponse<String> appOperateResponse) {
Log.i("11111", "======onRestartApp()");
}
@Override
public void onUninstallApp(AppOperateResponse<String> appOperateResponse) {
if(unInstallHandler!=null){
unInstallHandler.accept(appOperateResponse);
}
}
@Override
public void onLoadApp(AppOperateResponse<String> appOperateResponse) {
if(unLoadAppHandler!=null){
unLoadAppHandler.accept(appOperateResponse);
}
}
@Override
public void onGetDiskUsage(AppOperateResponse<DiskUsageInfo> appOperateResponse) {
if(usageHandler!=null){
usageHandler.accept(appOperateResponse);
}
}
@Override
public void onAPKInstallState(AppOperateResponse<AppInfo> appOperateResponse) {
Log.i("11111", "======onAPKInstallState()");
}
@Override
public void onAppLifeCycle(AppOperateResponse<AppLifeCycle> appOperateResponse) {
Log.i("11111", "======onAppLifeCycles()");
}
}
串流页面布局:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/player_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="@+id/fragment_player"
android:name="com.nbc.acsdk.widget.PlayerFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<!--串流页面其他自定义UI自行添加-->
<!-- 悬浮操作-->
<com.KooCabin.ui.NetworkInfoComp
android:id="@+id/network_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top|end"
/>
</FrameLayout>
父主题: 云车机开发指南