更新时间: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>
父主题: 云车机开发指南