DistributedVideoPlayer 分散ビデオプレーヤー (パート 2)

DistributedVideoPlayer 分散ビデオプレーヤー (パート 2)

[[430308]]

詳細については、以下をご覧ください。

51CTOとHuaweiが共同で構築したHongmengテクノロジーコミュニティ

https://harmonyos..com

導入

前回は動画再生機能、プレイリスト、コメント機能を実装しました。今回は、モバイル端末で遠隔テレビ動画再生のリモコン機能を実現する方法を見ていきます。

【この記事は優秀クリエイター奨励金に参加しています】

エフェクト表示


環境を構築する

DevEco Studio をインストールします。詳細については、DevEco Studio のダウンロードを参照してください。

DevEco Studio 開発環境をセットアップします。 DevEco Studio 開発環境はネットワーク環境に依存する必要があります。ツールを正常に使用するには、ネットワークに接続する必要があります。次の 2 つの状況に応じて開発環境を構成できます。

インターネットに直接アクセスできる場合は、HarmonyOS SDK をダウンロードするだけで済みます。

ネットワークがインターネットに直接アクセスできず、プロキシ サーバー経由でアクセスする必要がある場合は、「開発環境の構成」を参照してください。

ソースコードをダウンロードしたら、DevEco を使用してプロジェクトを開きます。

コード構造

携帯

Javaバックエンド

  1. │ config.json
  2. ├─ジャワ
  3. │ └─com
  4. │ └─ブティ
  5. │ └─分散ビデオプレイヤー
  6. │ │ メインアビリティ.java
  7. │ │MyApplication.java
  8. │ │
  9. │ ├─能力
  10. │ │ DevicesSelectAbility.java #利用可能なデバイスのリスト
  11. │ │ MainAbilitySlice.java #ビデオ再生リストページ
  12. │ │ SyncControlServiceAbility.java #同期制御サービス、TV --> 電話 
  13. │ │ VideoPlayAbility.java #ビデオ再生機能
  14. │ │ VideoPlayAbilitySlice.java #ビデオ再生の詳細とコメントページ
  15. │ │
  16. │ ├─コンポーネント
  17. │ │ EpisodesSelectionDialog.java
  18. │ │ RemoteController.java #リモートコントローラー
  19. │ │ VideoPlayerPlaybackButton.java #再生ボタンコンポーネント
  20. │ │ VideoPlayerSlider.java #再生時間プログレスバー
  21. │ │
  22. │ ├─定数
  23. │ │ 定数.java
  24. │ │ ResolutionEnum.java #解像度列挙
  25. │ │ RouteRegister.java #カスタムルーティング
  26. │ │
  27. │ ├─データ
  28. │ │ VideoInfo.java #基本的なビデオ情報
  29. │ │ VideoInfoService.java #シミュレーションデータに使用されるビデオ情報サービス
  30. │ │ Videos.java #ビデオリスト
  31. │ │
  32. │ ├─モデル
  33. │ │ CommentModel.java #コメントモデル
  34. │ │ DeviceModel.java #デバイスモデル
  35. │ │ ResolutionModel.java #解像度モデル
  36. │ │ VideoModel.java #ビデオモデル
  37. │ │
  38. │ ├─プロバイダー
  39. │ │ CommentItemProvider.java #コメントデータプロバイダ
  40. │ │ DeviceItemProvider.java #デバイスリストプロバイダー
  41. │ │ ResolutionItemProvider.java #解像度データプロバイダー
  42. │ │ VideoItemProvider.java #ビデオデータプロバイダ
  43. │ │
  44. │ └─ユーティリティ
  45. │ AppUtil.java #Toolクラス
  46. │ DateUtils.java

ページレイアウト

  1. │ │
  2. │ ├─レイアウト
  3. │ │ ability_main.xml #プレイリストレイアウト
  4. │ │ comments_item.xml #単一コメントレイアウト
  5. │ │ ダイアログプレイリスト.xml
  6. │ │ ダイアログ解像度リスト.xml
  7. │ │ ダイアログテーブルレイアウト.xml
  8. │ │ hm_sample_ability_video_box.xml #ビデオ再生コンポーネントページ
  9. │ │ hm_sample_ability_video_comments.xml #再生詳細レイアウトページ
  10. │ │ hm_sample_view_video_box_seek_bar_style1.xml #再生進捗バーのレイアウト
  11. │ │ hm_sample_view_video_box_seek_bar_style2.xml
  12. │ │ remote_ability_control.xml #リモートコントローラレイアウト
  13. │ │ リモートアビリティエピソード.xml
  14. │ │ remote_ability_select_devices.xml #転送可能なデバイスのリスト
  15. │ │ リモートアビリティサウンド機器.xml
  16. │ │ remote_device_item.xml #デバイスサブアイテム表示レイアウト
  17. │ │ リモートエピソードアイテム.xml
  18. │ │ リモートビデオ品質アイテム.xml

テレビ

Javaバックエンド

  1. ├─メイン
  2. │ │ config.json
  3. │ │
  4. │ ├─ジャワ
  5. │ │ └─com
  6. │ │ └─ブティ
  7. │ │ └─分散ビデオプレイヤー
  8. │ │ │ メインアビリティ.java
  9. │ │ │MyApplication.java
  10. │ │ │ VideoControlServiceAbility.java #ビデオ制御サービス 電話---> TV  
  11. │ │ │
  12. │ │ ├─コンポーネント
  13. │ │ │ ビデオ設定.java
  14. │ │ │
  15. │ │ ├─constant #いくつかの定数と列挙値
  16. │ │ │ 定数.java
  17. │ │ │ ResolutionEnum.java
  18. │ │ │SettingOptionEnum.java
  19. │ │ │ SpeedEnum.java
  20. │ │ │
  21. │ │ ├─データ
  22. │ │ │ VideoInfo.java #基本的なビデオ情報
  23. │ │ │ VideoInfoService.java #ビデオデータサービス、json でデータを読み取ります
  24. │ │ │ Videos.java #ビデオオブジェクト
  25. │ │ │
  26. │ │ ├─model #いくつかのデータモデル
  27. │ │ │ ResolutionModel.java
  28. │ │ │ 設定コンポーネントタグ.java
  29. │ │ │ 設定モデル.java
  30. │ │ │ ビデオモデル.java
  31. │ │ │
  32. │ │ ├─プロバイダー
  33. │ │ │ 設定プロバイダー.java
  34. │ │ │ VideoepisodesSelectProvider.java
  35. │ │ │ VideoSettingProvider.java
  36. │ │ │
  37. │ │ ├─スライス
  38. │ │ │ MainAbilitySlice.java
  39. │ │ │ VideoPlayAbilitySlice.java #ビデオ再生機能ページ
  40. │ │ │
  41. │ │ ├─ユーティリティ
  42. │ │ │AppUtil.java
  43. │ │ │
  44. │ │ └─表示 
  45. │ │ VideoPlayerPlaybackButton.java
  46. │ │ VideoPlayerSlider.java

ページレイアウト

  1. │ │ │
  2. │ │ ├─レイアウト
  3. │ │ │ 能力_メイン.xml
  4. │ │ │ ability_video_box.xml #プレイヤーレイアウトページ
  5. │ │ │ ビデオ共通アイテム.xml
  6. │ │ │ ビデオエピソードアイテム.xml
  7. │ │ │ ビデオ設定.xml
  8. │ │ │ ビデオ設定項目.xml
  9. │ │ │ view_video_box_seek_bar_style1.xml #プレーヤーの進行状況バーのレイアウト

実装手順

1. 携帯電話

1.1.ページレイアウト、コントローラーレイアウトページ remote_ability_control.xml

DependentLayout、DirectionalLayout、TableLayout レイアウト コンポーネントやその他のよく使用されるコンポーネントを使用します。


  1. <?xml バージョン = "1.0"エンコーディング = "utf-8" ?>
  2. <依存レイアウト
  3. xmlns:ohos= "http://schemas.huawei.com/res/ohos"  
  4. ohos:height= "match_parent"  
  5. ohos:width= "match_parent"  
  6. ohos:clickable= "true" >
  7. <方向レイアウト
  8. ohos:height= "match_parent"  
  9. ohos:width= "match_parent"  
  10. ohos:background_element= "$graphic:background_ability_control_bg"  
  11. ohos:orientation= "垂直" >
  12. <スタックレイアウト
  13. ohos:id= "$+id:control_app_bar"  
  14. ohos:height= "match_content"  
  15. ohos:width= "match_parent" >
  16.  
  17. <方向レイアウト
  18. ohos:id= "$+id:control_app_bar_left"  
  19. ohos:height= "56vp"  
  20. ohos:width= "match_content"  
  21. ohos:layout_alignment= "垂直中央"  
  22. ohos:orientation= "水平" >
  23. <画像
  24. ohos:id= "$+id:app_bar_back"  
  25. ohos:height= "$float:default_image_size"  
  26. ohos:width= "$float:default_image_size"  
  27. ohos:foreground_element= "$media:ic_back"  
  28. ohos:layout_alignment= "中央"  
  29. ohos:start_margin= "$float:default_margin" >
  30. </画像>
  31.  
  32. <テキスト
  33. ohos:id= "$+id:app_bar_device_name"  
  34. ohos:height= "match_parent"  
  35. ohos:width= "match_content"  
  36. ohos:start_margin= "12vp"  
  37. ohos:text= ""  
  38. ohos:text_color= "$color:default_white_color"  
  39. ohos:text_size= "$float:normal_text_size_20"  
  40. ohos:truncation_mode= "ellipsis_at_end" />
  41. </方向レイアウト>
  42. </スタックレイアウト>
  43. <方向レイアウト
  44. ohos:height= "match_content"  
  45. ohos:width= "match_parent"  
  46. ohos:layout_alignment= "垂直中央"  
  47. ohos:orientation= "水平" >
  48. <画像
  49. ohos:height= "16vp"  
  50. ohos:width= "16vp"  
  51. ohos:foreground_element= "$media:ic_play"  
  52. ohos:layout_alignment= "中央"  
  53. ohos:start_margin= "$float:default_margin" >
  54. </画像>
  55.  
  56. <テキスト
  57. ohos:id= "$+id:device_video_desc"  
  58. ohos:height= "match_content"  
  59. ohos:width= "match_parent"  
  60. ohos:auto_scrolling_count= "無制限"  
  61. ohos:end_margin= "$float:default_margin"  
  62. ohos:start_margin= "16vp"  
  63. ohos:text= ""  
  64. ohos:text_color= "$color:default_white_color"  
  65. ohos:text_size= "$float:little_text_size_12"  
  66. ohos:truncation_mode= "自動スクロール" />
  67. </方向レイアウト>
  68. <方向レイアウト
  69. ohos:id= "$+id:control_middle_panel"  
  70. ohos:height= "225vp"  
  71. ohos:width= "225vp"  
  72. ohos:background_element= "$graphic:background_ability_control_middle"  
  73. ohos:layout_alignment= "中央"  
  74. ohos:orientation= "垂直"  
  75. ohos:top_margin= "64vp" >
  76. <方向レイアウト
  77. ohos:id= "$+id:control_middle_panel_top"  
  78. ohos:height= "75vp"  
  79. ohos:width= "match_parent" >
  80. <画像
  81. ohos:id= "$+id:control_voice_up"  
  82. ohos:height= "$float:default_image_size"  
  83. ohos:width= "$float:default_image_size"  
  84. ohos:background_element= "$graphic:background_button_click"  
  85. ohos:foreground_element= "$media:ic_voice"  
  86. ohos:layout_alignment= "中央"  
  87. ohos:top_margin= "28vp" />
  88. </方向レイアウト>
  89. <方向レイアウト
  90. ohos:id= "$+id:control_middle_panel_center"  
  91. ohos:height= "75vp"  
  92. ohos:width= "match_parent"  
  93. ohos:orientation= "水平" >
  94. <方向レイアウト
  95. ohos:id= "$+id:control_backword_parent"  
  96. ohos:height= "match_parent"  
  97. ohos:width= "75vp"  
  98. ohos:alignment= "垂直中央" >
  99. <画像
  100. ohos:id= "$+id:control_backword"  
  101. ohos:height= "$float:default_image_size"  
  102. ohos:width= "$float:default_image_size"  
  103. ohos:background_element= "$graphic:background_button_click"  
  104. ohos:foreground_element= "$media:ic_anthology"  
  105. ohos:layout_alignment= "center" />
  106.  
  107. </方向レイアウト>
  108. <方向レイアウト
  109. ohos:id= "$+id:control_play_parent"  
  110. ohos:height= "match_parent"  
  111. ohos:width= "75vp"  
  112. ohos:alignment= "center" >
  113. <画像
  114. ohos:id= "$+id:control_play"  
  115. ohos:height= "45vp"  
  116. ohos:width= "45vp"  
  117. ohos:background_element= "$graphic:background_ability_control_ok"  
  118. ohos:image_src= "$media:ic_pause_black"  
  119. ohos:layout_alignment= "center" />
  120. </方向レイアウト>
  121. <方向レイアウト
  122. ohos:id= "$+id:control_forward_parent"  
  123. ohos:height= "match_parent"  
  124. ohos:width= "75vp"  
  125. ohos:alignment= "垂直中央" >
  126. <画像
  127. ohos:id= "$+id:control_forward"  
  128. ohos:height= "$float:default_image_size"  
  129. ohos:width= "$float:default_image_size"  
  130. ohos:background_element= "$graphic:background_button_click"  
  131. ohos:foreground_element= "$media:ic_anthology"  
  132. ohos:layout_alignment= "中央"  
  133. ohos:rotate= "180" />
  134. </方向レイアウト>
  135. </方向レイアウト>
  136. <方向レイアウト
  137. ohos:id= "$+id:control_middle_panel_bottom"  
  138. ohos:height= "75vp"  
  139. ohos:width= "match_parent" >
  140. <画像
  141. ohos:id= "$+id:control_voice_down"  
  142. ohos:height= "$float:default_image_size"  
  143. ohos:width= "$float:default_image_size"  
  144. ohos:background_element= "$graphic:background_button_click"  
  145. ohos:foreground_element= "$media:ic_voice"  
  146. ohos:layout_alignment= "中央"  
  147. ohos:top_margin= "23vp" />
  148. </方向レイアウト>
  149. </方向レイアウト>
  150. <方向レイアウト
  151. ohos:height= "0vp"  
  152. ohos:width= "match_parent"  
  153. ohos:alignment= "垂直中央"  
  154. ohos:orientation= "水平"  
  155. ohos:weight= "2" >
  156. <テキスト
  157. ohos:id= "$+id:control_current_time"  
  158. ohos:height= "match_content"  
  159. ohos:width= "match_content"  
  160. ohos:end_margin= "4vp"  
  161. ohos:start_margin= "$float:default_margin"  
  162. ohos:text= ""  
  163. ohos:text_color= "$color:default_white_color"  
  164. ohos:text_size= "12vp" />
  165.  
  166. <スライダー
  167. ohos:id= "$+id:control_progress"  
  168. ohos:height= "10vp"  
  169. ohos:width= "0vp"  
  170. ohos:orientation= "水平"  
  171. ohos:progress_color= "#FF6103"  
  172. ohos:thumb_element= "$graphic:background_slide_thumb"  
  173. ohos:weight= "5" />
  174.  
  175. <テキスト
  176. ohos:id= "$+id:control_end_time"  
  177. ohos:height= "match_content"  
  178. ohos:width= "match_content"  
  179. ohos:end_margin= "$float:default_margin"  
  180. ohos:text= ""  
  181. ohos:text_color= "$color:default_white_color"  
  182. ohos:text_size= "12vp" />
  183.  
  184. </方向レイアウト>
  185. <方向レイアウト
  186. ohos:height= "match_content"  
  187. ohos:width= "match_parent"  
  188. ohos:bottom_margin= "48vp"  
  189. ohos:start_margin= "16vp"  
  190. ohos:top_margin= "48vp" >
  191. <スタックレイアウト
  192. ohos:height= "26vp"  
  193. ohos:width= "match_parent" >
  194. <方向レイアウト
  195. ohos:height= "match_parent"  
  196. ohos:width= "match_parent" >
  197. <テキスト
  198. ohos:height= "match_parent"  
  199. ohos:width= "match_parent"  
  200. ohos:text= "$string:control_episodes"  
  201. ohos:text_alignment= "垂直中央"  
  202. ohos:text_color= "#000000"  
  203. ohos:text_size= "18fp" />
  204. </方向レイアウト>
  205. <方向レイアウト
  206. ohos:height= "match_parent"  
  207. ohos:width= "match_parent"  
  208. ohos:alignment= "右"  
  209. ohos:orientation= "水平" >
  210. <テキスト
  211. ohos:id= "$+id:control_episodes_num"  
  212. ohos:height= "match_parent"  
  213. ohos:width= "match_content"  
  214. ohos:background_element= "$graphic:background_button_click"  
  215. ohos:text= ""  
  216. ohos:text_color= "$color:default_black_color"  
  217. ohos:text_size= "14fp" />
  218. <画像
  219. ohos:id= "$+id:control_all_episodes"  
  220. ohos:height= "$float:default_image_size"  
  221. ohos:width= "$float:default_image_size"  
  222. ohos:background_element= "$graphic:background_button_click"  
  223. ohos:end_margin= "8vp"  
  224. ohos:foreground_element= "$media:ic_right_arrow"  
  225. ohos:layout_alignment= "center" />
  226. </方向レイアウト>
  227. </スタックレイアウト>
  228. <テーブルレイアウト
  229. ohos:id= "$+id:cotrol_bottom_item"  
  230. ohos:height= "match_content"  
  231. ohos:width= "match_parent"  
  232. ohos:below= "$id:episodes_header"  
  233. ohos:列数= "6"  
  234. ohos:top_margin= "12vp" >
  235. </テーブルレイアウト>
  236. </方向レイアウト>
  237. </方向レイアウト>
  238. </依存レイアウト>

1.2.ページレイアウト、デバイスコンポーネントレイアウトページの選択 remote_ability_select_devices.xml

DependentLayout、DirectionalLayout レイアウト コンポーネント、および ListContainer コンポーネントを使用します。


  1. <?xml バージョン = "1.0"エンコーディング = "utf-8" ?>
  2. <方向レイアウト
  3. xmlns:ohos= "http://schemas.huawei.com/res/ohos"  
  4. ohos:height= "match_parent"  
  5. ohos:width= "match_parent"  
  6. ohos:alignment= "垂直中央"  
  7. ohos:background_element= "$color:default_panel_background"  
  8. ohos:orientation= "垂直" >
  9.  
  10. <依存レイアウト
  11. ohos:height= "100vp"  
  12. ohos:width= "match_parent"  
  13. ohos:background_element= "$graphic:background_ability_devices"  
  14. ohos:end_margin= "12vp"  
  15. ohos:end_padding= "$float:default_margin"  
  16. ohos:layout_alignment= "垂直中央"  
  17. ohos:start_margin= "12vp"  
  18. ohos:start_padding= "$float:default_margin" >
  19. <テキスト
  20. ohos:id= "$+id:devices_title"  
  21. ohos:height= "match_content"  
  22. ohos:width= "match_parent"  
  23. ohos:text= "$string:local_machine"  
  24. ohos:text_color= "$color:default_black_color"  
  25. ohos:text_size= "14fp"  
  26. ohos:top_margin= "12vp" />
  27. <画像
  28. ohos:id= "$+id:devices_head_icon"  
  29. ohos:height= "$float:default_image_size"  
  30. ohos:width= "$float:default_image_size"  
  31. ohos:below= "$id:devices_title"  
  32. ohos:foreground_element= "$media:icon"  
  33. ohos:top_margin= "20vp" />
  34. <方向レイアウト
  35. ohos:height= "match_content"  
  36. ohos:width= "match_parent"  
  37. ohos:below= "$id:devices_title"  
  38. ohos:end_of= "$id:devices_head_icon"  
  39. ohos:orientation= "垂直"  
  40. ohos:start_padding= "12vp"  
  41. ohos:top_margin= "12vp" >
  42. <テキスト
  43. ohos:id= "$+id:デバイスヘッドアプリ名"  
  44. ohos:height= "match_content"  
  45. ohos:width= "match_parent"  
  46. ohos:max_height= "28vp"  
  47. ohos:text= ""  
  48. ohos:text_color= "$color:default_black_color"  
  49. ohos:text_size= "14fp" />
  50. <テキスト
  51. ohos:id= "$+id:デバイスヘッドビデオ名"  
  52. ohos:height= "18vp"  
  53. ohos:width= "match_parent"  
  54. ohos:text= ""  
  55. ohos:text_color= "#99000000"  
  56. ohos:text_size= "12fp"  
  57. ohos:truncation_mode= "ellipsis_at_end" />
  58. </方向レイアウト>
  59. </依存レイアウト>
  60. <方向レイアウト
  61. ohos:height= "300vp"  
  62. ohos:width= "match_parent"  
  63. ohos:background_element= "$graphic:background_ability_devices"  
  64. ohos:end_margin= "12vp"  
  65. ohos:orientation= "垂直"  
  66. ohos:padding= "$float:default_margin"  
  67. ohos:start_margin= "12vp"  
  68. ohos:top_margin= "12vp" >
  69. <テキスト
  70. ohos:height= "21vp"  
  71. ohos:width= "match_parent"  
  72. ohos:bottom_margin= "10vp"  
  73. ohos:text= "$string:my_devices"  
  74. ohos:text_color= "$color:default_black_color"  
  75. ohos:text_size= "16vp" />
  76. <リストコンテナ
  77. ohos:id= "$+id:デバイスコンテナ"  
  78. ohos:height= "match_parent"  
  79. ohos:width= "match_parent"  
  80. ohos:layout_alignment= "水平中央"  
  81. ohos:orientation= "垂直" />
  82. </方向レイアウト>
  83. </方向レイアウト>

1.3.Java コード、リモート コントローラ ビュー コンポーネント RemoteController.java

RemoteController は DependentLayout レイアウト コンポーネントを継承し、クリック イベントとスライダー スライド イベントを処理するために Component.ClickedListener と Slider.ValueChangedListener を実装します。

  1. /**
  2. * コントローラーパネルのコンポーネント
  3. * リモートコントロールページ
  4. */
  5. パブリッククラス RemoteController は DependentLayout を拡張します
  6. //コンポーネントのクリック監視とスライダー値の変更監視のインターフェースを実装しました
  7. Component.ClickedListener、Slider.ValueChangedListenerを実装します。
  8. ...

コントローラー パネル ビュー コンポーネントは、次の 2 つの部分で構成されます。

最初の部分は、コンポーネントの初期化です。これには、制御コンポーネントの初期化、再生進行コンポーネントの初期化、エピソードコンポーネントの初期化が含まれます。

  1. /**
  2. * リモートコントロールビューのコンポーネントを初期化する
  3. */
  4. プライベートvoid initView() {
  5. //非表示に設定
  6. 可視性をINVISIBLEに設定します。
  7. コントローラビューnullの場合
  8. コントローラービュー =
  9. LayoutScatter.getInstance(スライス).parse(ResourceTable.Layout_remote_ability_control, this, false );
  10. }
  11.  
  12. // テキストを初期化する
  13. アイテムテキストを初期化します。
  14. アイテムサイズの初期化();
  15. アイテムイメージを初期化します。
  16.  
  17. //進捗スライダー
  18. 進捗スライダーを初期化します。
  19. //ボタンを初期化する
  20. ボタンを初期化します(ResourceTable.Id_app_bar_back);
  21. initButton(リソーステーブル.Id_control_episodes_num);
  22. initButton(ResourceTable.Id_control_all_episodes);
  23. ボタンを初期化します(ResourceTable.Id_control_play);
  24. ボタンを初期化します(ResourceTable.Id_control_backword);
  25. ボタンを初期化します(ResourceTable.Id_control_forward);
  26. ボタンを初期化します(ResourceTable.Id_control_voice_down);
  27. ボタンを初期化します(ResourceTable.Id_control_voice_up);
  28.  
  29. //下部に表示されるビデオエピソードを初期化します
  30. 下部コンポーネントを初期化します。
  31.  
  32. //コンポーネントをキューの最後に追加します
  33. コントローラビューにコンポーネントを追加します。
  34.  
  35. // エピソードダイアログを初期化する
  36. エピソードダイアログを初期化します。
  37.  
  38. 再生中 = true ;
  39. }

2 番目の部分は、コントロール リスナー (RemoteControllerListener) とインターフェイスをカスタマイズし、クリック イベントとスライダー スライド イベントを組み合わせて、独自の操作をモバイル ビデオ プレーヤー クラス (VideoPlayAbilitySlice) に渡すことです。

  1. /**
  2. * コントローラーパネル操作監視
  3. * 再生/早戻し/早送り/音量アップ/ダウン/接続停止/ビデオ切り替え/解像度切り替え
  4. * リモートコントローラリスナー
  5. */
  6. パブリックインターフェイスRemoteControllerListener {
  7. //このインターフェースの実装に制御コードを送信します
  8. void sendControl( int code, String extra);
  9. }
  10. /**
  11. *
  12. * コントローラーリスナーを設定する
  13. * リモートコントローラコールバックの設定
  14. *
  15. * @param リスナー リスナー
  16. */
  17. パブリックvoid setRemoteControllerCallback(RemoteControllerListener リスナー) {
  18. リモートコントローラリスナー = リスナー;
  19. }
  20.  
  21.  
  22. /**
  23. * クリックイベントは均一に処理され、sendControl経由で送信されます。
  24. */
  25. @オーバーライド
  26. パブリックvoid onClick(コンポーネント コンポーネント) {
  27. スイッチ (component.getId()) {
  28. //コンポーネントを返す
  29. ResourceTable.Id_app_bar_backの場合:
  30. 非表示( true );
  31. 壊す;
  32.  
  33. ケースResourceTable.Id_control_episodes_num:
  34. // エピソード コンポーネント、エピソード ダイアログを表示する
  35. ResourceTable.Id_control_all_episodes の場合:
  36. エピソードダイアログにVisibilityを設定します(VISIBLE);
  37. 壊す;
  38. //コンポーネントを再生し、再生制御命令を送信します
  39. ResourceTable.Id_control_playの場合:
  40. リモート コントローラ リスナー。sendControl(ControlCode.PLAY.getCode(), "" );
  41. 壊す;
  42. // 高速巻き戻しコンポーネント、高速巻き戻しコマンドを送信
  43. ResourceTable.Id_control_backwordの場合:
  44. リモート コントローラ リスナー。sendControl(ControlCode.BACKWARD.getCode(), "" );
  45. 壊す;
  46. //早送りコンポーネント、早送りコマンドを送信
  47. ResourceTable.Id_control_forwardの場合:
  48. remoteControllerListener.sendControl( ControlCode.FORWARD.getCode (), "" );
  49. 壊す;
  50. // 音量を上げるには、音量を上げるコマンドを送信します
  51. ResourceTable.Id_control_voice_upの場合:
  52. リモートコントローラリスナー.sendControl(ControlCode.VOLUME_ADD.getCode(), "" );
  53. 壊す;
  54. //音量を下げるには、音量を下げるコマンドを送信します
  55. ResourceTable.Id_control_voice_downの場合:
  56. //表示されたダイアログボックスを閉じる
  57. ダイアログの可視性を取得する場合
  58. リモート コントローラ リスナー。sendControl(ControlCode.VOLUME_REDUCED.getCode(), "" );
  59. }
  60. 壊す;
  61. デフォルト
  62. 壊す;
  63. }
  64. }
  65.  
  66. /**
  67. * 時間進行バーの値が変わったら、現在の再生時間を設定します
  68. * @param スライダー
  69. * @パラメータ値
  70. * @param ユーザーから
  71. */
  72. @オーバーライド
  73. パブリックvoid onProgressUpdated(スライダー slider, int値, boolean fromUser) {
  74. HiLog.debug(LABEL、 「onProgressUpdated」 );
  75. スライス.getUITaskDispatcher()
  76. .delayDispatch() は、
  77. () -> {
  78. //現在の再生時間の進行状況
  79. テキスト currentTime =
  80. (テキスト) controllerView.findComponentById(ResourceTable.Id_control_current_time);
  81. //表示時間を設定する
  82. 現在の時刻.setText()
  83. DateUtils.msToString(合計時間 * 値 / Constants.ONE_HUNDRED_PERCENT));
  84. },
  85. 0);
  86. }
  87.  
  88. @オーバーライド
  89. パブリックvoid onTouchStart(スライダー スライダー) {
  90. スライダータッチ = true ;
  91. }
  92.  
  93.  
  94. /**
  95. * ドラッグが終了するとプログレスバースライダーがトリガーされ、sendControlが送信されます。
  96. * @param スライダー
  97. */
  98. @オーバーライド
  99. パブリックvoid onTouchEnd(スライダー スライダー) {
  100. // ポップアップ ボックスはスライダーのタッチ イベントをブロックできません。
  101. // このイベント ダイアログ ボックス表示された場合は処理されません
  102. //スライドが終了し、リモートエンドにシークコマンドを送信します
  103. ダイアログの可視性を取得する場合
  104. //
  105. リモート コントローラ リスナー。sendControl(ControlCode.SEEK.getCode()、String.valueOf(slider.getProgress()));
  106. }
  107. スライダータッチ = false ;
  108. }

1.4.Java コード、フロー デバイス リスト ページ DevicesSelectAbility.java

主にデバイス選択リストを提供し、デバイスを選択した後にデバイス情報を返します。

  1. /**
  2. * オプションのリモートデバイス機能
  3. * リモートデバイス選択機能
  4. */
  5. パブリッククラスDevicesSelectAbilityはAbilityを拡張します{
  6. @オーバーライド
  7. パブリックvoid onStart(インテント インテント) {
  8.  
  9. //データ転送許可を要求する
  10. requestPermissionsFromUser(新しい文字列[]{ "ohos.permission.DISTRIBUTED_DATASYNC" }, 0);
  11.  
  12. super.onStart(インテント);
  13. super.setUIContent(ResourceTable.Layout_remote_ability_select_devices);
  14.  
  15. this.initPage(インテント);
  16. }
  17.  
  18. /**
  19. * ページコンポーネントを初期化する
  20. *
  21. * @param 意図
  22. */
  23. プライベート void initPage(インテントインテント) {
  24. //JSONからビデオデータを取得する
  25. VideoInfoService videoService = 新しい VideoInfoService(this);
  26.  
  27. //アプリ名を設定する
  28. テキスト appName = (テキスト) findComponentById(ResourceTable.Id_devices_head_app_name);
  29. appName.setText(ResourceTable.String_entry_MainAbility);
  30.  
  31. //ビデオ名コンポーネント
  32. テキスト videoName = (テキスト) findComponentById(ResourceTable.Id_devices_head_video_name);
  33. //現在再生中のビデオのインデックス
  34. 現在の再生インデックスを取得します。
  35. //現在再生中のビデオのエピソード
  36. 弦楽器演奏エピソード =
  37. AppUtil.getStringResource(これ、ResourceTable.String_control_playing_episodes)
  38. .replaceAll( "\\?" , String.valueOf(currentPlayingIndex));
  39. //再生するビデオの名前とエピソードを設定します
  40. videoName.setText(videoService.getAllVideoInfo().getVideoName() + " " + playingEpisodes);
  41.  
  42. //オンラインデバイスのリスト、クリックリスナーイベントの設定、データ転送
  43. ListContainer listContainer = (ListContainer) findComponentById(ResourceTable.Id_devices_container);
  44. <DeviceModel> デバイスのリスト = AppUtil.getDevicesInfo();
  45.  
  46. //コンテナはデータプロバイダをバインドします
  47. DeviceItemProvider プロバイダー = 新しい DeviceItemProvider(this, devices);
  48. listContainer.setItemProvider(プロバイダー);
  49.  
  50. //クリック監視処理を設定する
  51. listContainer.setItemClickedListener(
  52. (コンテナ、コンポーネント、位置、ID) -> {
  53. //クリックされた項目を取得する
  54. DeviceModel item = (DeviceModel) listContainer.getItemProvider().getItem(position);
  55.  
  56. //データインテントを返す
  57. インテントのintentResult = 新しいIntent();
  58. //返されるパラメータを設定する
  59. 定数PARAM_DEVICE_TYPE、item.getDeviceType();
  60. 定数PARAM_DEVICE_ID、item.getDeviceId();
  61. 定数PARAM_DEVICE_NAME、item.getDeviceName();
  62. //戻り値を設定する
  63. 結果を設定します(0、インテント結果);
  64.  
  65. //現在のアビリティを無効にする
  66. この能力を終了させます。
  67. });
  68. }
  69. }

利用可能なデバイス リスト プロバイダー DeviceItemProvider.java

  1. /**
  2. * デバイスリストプロバイダー
  3. * デバイス情報リスト処理クラス
  4. */
  5. パブリッククラスDeviceItemProviderはBaseItemProviderを拡張します。
  6. プライベート最終コンテキストコンテキスト;
  7. プライベート最終リスト<DeviceModel> リスト;
  8.  
  9. /**
  10. * 初期化
  11. */
  12. パブリックDeviceItemProvider(コンテキスト コンテキスト、List<DeviceModel> リスト) {
  13. this.context = コンテキスト;
  14. this.list = リスト;
  15. }
  16.  
  17. @オーバーライド
  18. 公共 整数getCount() {
  19. 戻りリスト == null ? 0 : リスト。サイズ();
  20. }
  21.  
  22. @オーバーライド
  23. パブリックオブジェクトgetItem( int位置){
  24. if (list != null && position >= 0 && position < list.size ( )) {
  25. リストを返します。get(position);
  26. }
  27. 新しいDeviceModel()を返します
  28. }
  29.  
  30. @オーバーライド
  31. パブリックlong getItemId( int位置) {
  32. 位置を戻す
  33. }
  34.  
  35. @オーバーライド
  36. パブリックコンポーネント getComponent( int position, Component convertComponent, ComponentContainer componentContainer) {
  37. 最終コンポーネント cpt;
  38. (convertComponent == null )の場合{
  39. cpt = LayoutScatter.getInstance(context).parse(ResourceTable.Layout_remote_device_item, null false );
  40. }それ以外{
  41. cpt = convertComponent;
  42. }
  43. デバイスモデルデバイスアイテム = list.get(位置);
  44. //デバイス名
  45. テキスト deviceName = (テキスト) cpt.findComponentById(ResourceTable.Id_device_item_name);
  46. デバイス名.setText(デバイスアイテム.getDeviceName());
  47.  
  48. //デバイスアイコン
  49. 画像デバイスアイコン = (画像) cpt.findComponentById(ResourceTable.Id_device_item_icon);
  50. AppUtil.setDeviceIcon(deviceItem.getDeviceType(), deviceIcon);
  51.  
  52. if (位置 == リスト.サイズ() - 1) {
  53. コンポーネント ディバイダ = cpt.findComponentById(ResourceTable.Id_device_item_divider);
  54. 区切り線.setVisibility(Component.INVISIBLE);
  55. }
  56.  
  57. cptを返します
  58. }
  59. }

1.5.Java コード、ビデオ プレーヤー ページ VideoPlayAbilitySlice.java

ビデオ プレーヤー ページのリモート コントロール操作のコードは、主に次の 2 つの部分で構成されます。

最初の部分は次のとおりです。「ストリーム」ボタンをクリックすると、利用可能なデバイスのリストが開き、ストリーミングするデバイスをクリックし、onAbilityResult メソッドで、リモート TV デバイスのプレーヤー機能ページ (MainAbility) を開いて、コントロール メタサービス (VideoControlServiceAbility) に接続します。

  1. /**
  2. * デバイスを開いてアビリティを選択した後、転送するデバイスを選択するとsetResultがトリガーされます
  3. * @param リクエストコード
  4. * @param 結果コード
  5. * @param 結果インテント
  6. */
  7. @オーバーライド
  8. 保護されたvoid onAbilityResult( int requestCode, int resultCode, Intent resultIntent) {
  9. HiLog.debug(LABEL、 "onAbilityResult" );
  10. //
  11. リクエストコード == Constants.PRESENT_SELECT_DEVICES_REQUEST_CODE && resultIntent != null の場合{
  12. //
  13. リモートアビリティPaを開始します(結果インテント);
  14. 戻る;
  15. }
  16. //
  17. setDisplayOrientation( AbilityInfo.DisplayOrientation.values ()[sourceDisplayOrientation + 1]);
  18. if (isVideoPlaying) {
  19. プレイヤーを起動します。
  20. }
  21. }
  22. /**
  23. * リモート機能を有効にする
  24. *
  25. * @param 結果インテント
  26. */
  27. プライベート void startRemoteAbilityPa(インテント resultIntent) {
  28.  
  29. //リモート TV デバイス ID
  30. 文字列デバイスID = resultIntent.getStringParam(Constants.PARAM_DEVICE_ID);
  31. インテントのintent = 新しいIntent();
  32. 操作操作 =
  33. 新しい Intent.OperationBuilder()
  34. .withDeviceId(デバイスID)
  35. .withBundleName(バンドル名を取得())
  36. .withAbilityName( "com.buty.distributedvideoplayer.MainAbility" )
  37. .withAction( "アクション.ビデオ.再生" )
  38. .withFlags(Intent.FLAG_ABILITYSLICE_MULTI_DEVICE)
  39. 。建てる();
  40. //ローカルストレージデバイスID
  41. 文字列 localDeviceId =
  42. KvManagerFactory.getInstance().createKvManager(新しい KvManagerConfig(this)).getLocalDeviceInfo().getId();
  43.  
  44. HiLog.debug(LABEL、 "remoteDevicesId:" + devicesId + "、localDeviceId:" + localDeviceId);
  45.  
  46. //ビデオパスを再生
  47. 文字列パス =
  48. ビデオサービス
  49. .getVideoInfoByIndex(現在の再生インデックス)
  50. .getResolutions()
  51. .get(現在の再生解像度インデックス)
  52. .getUrl();
  53. //ローカル電話()デバイスID
  54. リモートコンスタントにパラメータを設定します。
  55. //ビデオURLを再生する
  56. リモートコンスタントに、パスを設定します。
  57. //異なる解像度のビデオを再生するためのインデックス
  58. パラメータを設定します。
  59. //再生進行位置
  60. リモートコンスタントにパラメータ設定する
  61. インテントをsetOperation(操作);
  62. //リモート再生機能を開始する
  63. 開始アビリティ(インテント);
  64.  
  65. //リモートビデオコントロールメタサービス
  66. インテント remotePaIntent = 新しい Intent();
  67. オペレーションpaOperation =
  68. 新しい Intent.OperationBuilder()
  69. .withDeviceId(デバイスID)
  70. .withBundleName(バンドル名を取得())
  71. .withAbilityName( "com.buty.distributedvideoplayer.VideoControlServiceAbility" )
  72. .withFlags(Intent.FLAG_ABILITYSLICE_MULTI_DEVICE)
  73. 。建てる();
  74. リモートペイントインテントの設定操作(paOperation)。
  75. //リモート ビデオ コントロール サービスに接続します。 2 つの P40 端末エミュレータを使用した接続に失敗しました。
  76. //Context::connectRemoteAbility が失敗しました。エラーコードは1319です
  77. ブール型 connectFlag = connectAbility(remotePaIntent、接続);
  78.  
  79. if (接続フラグ) {
  80. HiLog.debug(LABEL, "リモート機能PAの開始が成功しました" );
  81. // ディスプレイの向きを垂直に設定する
  82. ディスプレイの向きを設定します。
  83.  
  84. // リモコンを初期化する
  85. リモートコントローラーを初期化します。
  86.  
  87. //再生の進行状況、ステータスなどを設定します。
  88. リモートコントローラ.setVideoInfo()
  89. resultIntent.getStringParam(Constants.PARAM_DEVICE_NAME)、
  90. 現在の再生インデックス、
  91. ( int ) player.getCurrentPosition(),
  92. ( int ) player.getDuration());
  93. リモートコントローラーを表示します。
  94. }それ以外{
  95. HiLog.error(LABEL, "リモート機能PAの開始に失敗しました" );
  96. stopAbility(インテント);
  97. }
  98. }

2 番目の部分は、リモート ビデオ コントロール メタ サービスに正常に接続した後、リモート コントローラー (RemoteController) を初期化し、コントローラー パネルのリスナー インターフェイス (sendControl) を実装し、mProxy (sendDataToRemote) を介して TV 側に制御命令を送信します。

  1. /**
  2. * コントローラとリスナーを初期化する
  3. */
  4. プライベートvoid initRemoteController() {
  5. リモートコントローラnullの場合
  6. リモートコントローラ = 新しいリモートコントローラ(これ);
  7.  
  8. //モバイルコントロールパネル操作のコールバックを監視する
  9. リモートコントローラ.setRemoteControllerCallback()
  10. (コード、追加) -> {
  11. mProxy == null の場合{
  12. 戻る;
  13. }
  14. //制御命令をテレビ側に送信する
  15. ブール結果 =
  16. mProxy.sendDataToRemote(RemoteConstant.REQUEST_CONTROL_REMOTE_DEVICE、コード、追加);
  17.  
  18. if (!結果) {
  19. 新しい ToastDialog(getContext())
  20. .setText() メソッド
  21. AppUtil.getStringResource() 関数は、
  22. getContext()、ResourceTable.String_send_failed_tips))
  23. 。見せる();
  24. リモートコントローラを非表示にします( false );
  25. }
  26. });
  27.  
  28. StackLayout のルートレイアウト = (StackLayout) findComponentById(ResourceTable.Id_root_layout);
  29. ルートレイアウトにコンポーネントを追加します(リモートコントローラ)。
  30. }
  31. }

3番目の部分は、携帯電話制御イベント(Constants.PHONE_CONTROL_EVENT)をサブスクライブして、同期制御サービス(SyncControlServiceAbility)によって送信されたイベントを処理し、テレビ側のステータスを携帯電話制御側に同期させることです。

  1. /**
  2. * 「TV->モバイル」方向の再生ステータスの同期イベントをサブスクライブします
  3. */
  4. プライベートvoid subscribe() {
  5. HiLog.debug(LABEL、 「購読」 );
  6. マッチングスキル matchingSkills = new MatchingSkills();
  7. //モバイルコントロールパネルのイベントを制御する
  8. マッチングスキルにイベントを追加します(Constants.PHONE_CONTROL_EVENT);
  9. マッチングスキル。イベントを追加します(CommonEventSupport.COMMON_EVENT_SCREEN_ON);
  10. CommonEventSubscribeInfo subscribeInfo = 新しい CommonEventSubscribeInfo(matchingSkills);
  11.  
  12. //イベント サブスクライバー TODO
  13. サブスクライバー = 新しい MyCommonEventSubscriber(subscribeInfo);
  14. 試す {
  15. CommonEventManager.subscribeCommonEvent(サブスクライバー);
  16. } キャッチ (RemoteException e) {
  17. HiLog.error(LABEL, "subscribeCommonEvent例外が発生しました。" );
  18. }
  19. }
  20.  
  21. /**
  22. * 登録解除
  23. */
  24. プライベートvoid unSubscribe() {
  25. HiLog.debug(LABEL、 「購読解除」 );
  26. 試す {
  27. CommonEventManager.unsubscribeCommonEvent(サブスクライバー);
  28. } キャッチ (RemoteException e) {
  29. HiLog.error(LABEL、 「unsubscribecommonevent例外が発生します。」 );
  30. }
  31. }
  32. /**
  33. * イベントサブスクライバー。TV側→モバイル側方向の再生ステータスの同期に使用します。
  34. */
  35. クラス MyCommonEventSubscriber は CommonEventSubscriber を拡張します {
  36. MyCommonEventSubscriber(CommonEventSubscribeInfo 情報) {
  37. スーパー(情報);
  38. }
  39.  
  40. @オーバーライド
  41. パブリックvoid onReceiveEvent(CommonEventData commonEventData) {
  42. インテント intent = commonEventData.getIntent();
  43. //イベントパラメータ、制御命令コードを取得する
  44. コントロールコードを取得します
  45.  
  46. HiLog.debug(LABEL、 "onReceiveEvent: controlCode" +controlCode);
  47.  
  48. //リモコンなし
  49. リモートコントローラがnullの場合、リモートコントローラは表示されます (!remoteController.isShown()) {
  50. HiLog.debug(LABEL, "リモート コントローラーは現在非表示になっています" );
  51. 戻る;
  52. }
  53. //ビデオ再生進行指示の場合
  54. (controlCode == ControlCode.SYNC_VIDEO_PROCESS.getCode()) の場合 {
  55. int totalTime = Integer .parseInt(intent.getStringParam(Constants.KEY_CONTROL_VIDEO_TIME));
  56. int進行状況 = Integer .parseInt(intent.getStringParam(Constants.KEY_CONTROL_VIDEO_PROGRESS));
  57. //コントロールパネルの進行状況バーを更新する
  58. リモートコントローラ.syncVideoPlayProcess(合計時間、進行状況);
  59.  
  60. //コントロールパネルのビデオ再生ステータスを更新します
  61. }そうでない場合 (controlCode == ControlCode.SYNC_VIDEO_STATUS.getCode()) {
  62.  
  63. ブール値 isPlaying =
  64. ブール値。parseBoolean(intent.getStringParam(Constants.KEY_CONTROL_VIDEO_PLAYBACK_STATUS));
  65. (remoteController.getPlayingStatus() != isPlaying)の場合{
  66. リモートコントローラーの再生ステータスを変更します。
  67. }
  68.  
  69. //コントロールパネルの音量を更新する
  70. }それ以外{
  71. int currentVolume = Integer .parseInt(intent.getStringParam(Constants.KEY_CONTROL_VIDEO_VOLUME));
  72. リモートコントローラー。現在のボリュームアイコンを変更します。
  73.  
  74. }
  75. }
  76. }

1.6.Java コード、リモート ビデオ コントロール同期サービス SyncControlServiceAbility.java

このサービスはテレビ接続に使用されます。もう一方の端が接続されると、再生ステータス、再生の進行状況、音量値が同期されます。

  1. /**
  2. * 同期制御メタサービス
  3. * ビデオ制御同期サービス
  4. */
  5. パブリッククラスSyncControlServiceAbilityはAbilityを拡張します{
  6. プライベート静的最終 HiLogLabel LABEL = new HiLogLabel(0, 0, "=>SyncControlServiceAbility" );
  7.  
  8. //リモートデバイスプロキシ
  9. プライベート最終 MyRemote リモート = 新しい MyRemote(RemoteConstant.REQUEST_SYNC_VIDEO_STATUS);
  10.  
  11. @オーバーライド
  12. パブリックvoid onStart(インテント インテント) {
  13. super.onStart(インテント);
  14. //
  15. リモート.setRemoteRequestCallback()
  16. これは::sendEventです);
  17. }
  18.  
  19. @オーバーライド
  20. パブリックvoid onBackground() {
  21. スーパーのonBackground();
  22. }
  23.  
  24. @オーバーライド
  25. パブリックボイドonStop() {
  26. スーパーのonStop();
  27. }
  28.  
  29. @オーバーライド
  30. 保護された IRemoteObject onConnect(インテントインテント) {
  31. super.onConnect(インテント);
  32. リモート.asObject()を返します
  33. }
  34.  
  35. /**
  36. * プレイヤーイベントを送信する
  37. * @param コントロールコード
  38. * @パラメータ値
  39. */
  40. プライベートvoid sendEvent( int controlCode, Map<?, ?> value) {
  41. HiLog.debug(LABEL、 "sendEvent、コントロールコード:" +controlCode+ "、値:" +value.toString());
  42. 試す {
  43. インテントのintent = 新しいIntent();
  44. 操作 operation = new Intent.OperationBuilder().withAction(Constants.PHONE_CONTROL_EVENT).build();
  45. インテントをsetOperation(操作);
  46. 定数KEY_CONTROL_CODE、コントロールコードを設定します。
  47. // プレイの進行状況
  48. (controlCode == ControlCode.SYNC_VIDEO_PROCESS.getCode()) の場合 {
  49. インテント.setParam(定数.KEY_CONTROL_VIDEO_TIME,
  50. String.valueOf(value.get(RemoteConstant.REMOTE_KEY_VIDEO_TOTAL_TIME)));
  51. インテント.setParam(定数.KEY_CONTROL_VIDEO_PROGRESS,
  52. String.valueOf(value.get(RemoteConstant.REMOTE_KEY_VIDEO_CURRENT_PROGRESS)));
  53. //再生ステータス
  54. }そうでない場合 (controlCode == ControlCode.SYNC_VIDEO_STATUS.getCode()) {
  55. インテント.setParam(定数.KEY_CONTROL_VIDEO_PLAYBACK_STATUS,
  56. String.valueOf(value.get(RemoteConstant.REMOTE_KEY_VIDEO_CURRENT_PLAYBACK_STATUS)));
  57.  
  58. //再生音量
  59. }それ以外{
  60. インテント.setParam(定数.KEY_CONTROL_VIDEO_VOLUME,
  61. String.valueOf(value.get(RemoteConstant.REMOTE_KEY_VIDEO_CURRENT_VOLUME)));
  62. }
  63. CommonEventData イベントデータ = 新しい CommonEventData(intent);
  64.  
  65. //イベントを公開
  66. CommonEventManager.publishCommonEvent(イベントデータ)。
  67. } キャッチ (RemoteException e) {
  68. HiLog.error(LABEL, "publishCommonEvent例外が発生しました。" );
  69. }
  70. }
  71. }

2. テレビ

2.1.ページレイアウト、ビデオプレーヤーレイアウトコンポーネント ability_video_box.xml

プレーヤーコンポーネント VideoPlayerView

  1. <?xml バージョン = "1.0"エンコーディング = "utf-8" ?>
  2. <スタックレイアウト
  3. xmlns:ohos= "http://schemas.huawei.com/res/ohos"  
  4. ohos:id= "$+id:root_layout"  
  5. ohos:height= "match_parent"  
  6. ohos:width= "match_parent"  
  7. ohos:background_element= "#FFFFFFFF"  
  8. ohos:orientation= "垂直" >
  9.  
  10. <com.buty.distributedvideoplayer.player.ui.widget.media.VideoPlayerView
  11. ohos:id= "$+id:video_view"  
  12. ohos:height= "match_parent"  
  13. ohos:width= "match_parent" />
  14.  
  15. </スタックレイアウト>

2.2.ページレイアウト、ビデオプレーヤーの進行状況バーレイアウトコンポーネント view_video_box_seek_bar_style1.xml

  1. <?xml バージョン = "1.0"エンコーディング = "utf-8" ?>
  2. <! --時間はプログレスバーの上にあります-->  
  3. <依存レイアウト
  4. xmlns:ohos= "http://schemas.huawei.com/res/ohos"  
  5. ohos:height= "54vp"  
  6. ohos:width= "match_parent"  
  7. ohos:orientation= "水平" >
  8.  
  9. <テキスト
  10. ohos:id= "$+id:現在の時刻"  
  11. ohos:height= "match_content"  
  12. ohos:width= "match_content"  
  13. ohos:above= "$id:seek_bar"  
  14. ohos:align_parent_start= "true"  
  15. ohos:start_margin= "12vp"  
  16. ohos:text_color= "白"  
  17. ohos:text_size= "10fp" />
  18.  
  19. <スライダー
  20. ohos:id= "$+id:seek_bar"  
  21. ohos:height= "match_content"  
  22. ohos:width= "match_parent"  
  23. ohos:background_instruct_element= "$color:seek_bar_background_instruct_color"  
  24. ohos:center_in_parent= "true"  
  25. ohos:progress_element= "$color:seek_bar_progress_color"  
  26. ohos:thumb_element= "$graphic:hm_sample_slider_thumb"  
  27. ohos:vice_progress_element= "$color:seek_bar_vice_progress_color"  
  28. />
  29.  
  30. <テキスト
  31. ohos:id= "$+id:end_time"  
  32. ohos:height= "match_content"  
  33. ohos:width= "match_content"  
  34. ohos:above= "$id:seek_bar"  
  35. ohos:align_parent_end = "true"  
  36. ohos:end_margin= "12vp"  
  37. ohos:text_color= "白"  
  38. ohos:text_size= "10fp" />
  39. </依存レイアウト>

2.3.Java コード、ビデオ制御メタサービス VideoControlServiceAbility.java

2つの部分に分かれており、

最初の部分は次のとおりです: 携帯電話が接続された後、asObject。

  1. /**
  2. * リモートデバイスプロキシ、ソース commonlib
  3. */
  4. プライベート最終 MyRemote リモート = 新しい MyRemote(RemoteConstant.REQUEST_CONTROL_REMOTE_DEVICE);
  5.  
  6. @オーバーライド
  7. 保護された IRemoteObject onConnect(インテントインテント) {
  8. HiLog.debug(LABEL、 "onConnect" );
  9. super.onConnect(インテント);
  10. //プロキシオブジェクトを返す
  11. リモート.asObject()を返します
  12. }

2 番目の部分は、サブスクライバーにイベント通知を送信することです (VideoPlayAbilitySlice)

  1. /**
  2. * イベント通知を送信する VideoPlayAbilitySlice
  3. * @param controlCode 制御コード
  4. * @パラメータ値
  5. */
  6. プライベートvoid sendEvent( int controlCode, Map<?, ?> value) {
  7. HiLog.debug(LABEL、 "sendEvent:" +controlCode+ "," +value.toString());
  8. 試す {
  9. //意図
  10. インテントのintent = 新しいIntent();
  11. //TV制御イベント操作
  12. 操作 operation = new Intent.OperationBuilder()
  13. .withAction(Constants.TV_CONTROL_EVENT)
  14. 。建てる();
  15. インテントをsetOperation(操作);
  16. //制御パラメータを設定する
  17. 定数KEY_CONTROL_CODE、コントロールコードを設定します。
  18. intent.setParam(Constants.KEY_CONTROL_VALUE、(文字列) value.get(RemoteConstant.REMOTE_KEY_CONTROL_VALUE));
  19. //時間データをカプセル化する
  20. CommonEventData イベントデータ = 新しい CommonEventData(intent);
  21. //一般イベント マネージャー、イベントの公開
  22. CommonEventManager.publishCommonEvent(イベントデータ)。
  23.  
  24. } キャッチ (RemoteException e) {
  25. HiLog.error(LABEL, "publishCommonEvent例外が発生しました。" );
  26. }
  27. }

2.4.Java コード、ビデオ プレーヤー機能ページ VideoPlayAbilitySlice.java

最初の部分は、携帯電話に接続された同期制御メタ サービス (SyncControlServiceAbility) です。接続を確立した後、リモート プロキシが初期化されます (MyRemoteProxy)。

  1. //接続された電話デバイス
  2. リモートデバイスを接続する(
  3. //インテンションからリモート電話のデバイスIDを取得します
  4. リモートデバイスIDを取得します。
  5.  
  6. /**
  7. * リモート電話デバイスに接続する同期サービス
  8. * @param デバイスID
  9. */
  10. プライベートvoid connectRemoteDevice(String deviceId) {
  11. HiLog.debug(LABEL、 「connectRemoteDevice:」 +デバイスID);
  12. インテント connectPaIntent = 新しい Intent();
  13. 操作操作 =
  14. 新しい Intent.OperationBuilder()
  15. .withDeviceId(デバイスID)
  16. .withBundleName(バンドル名を取得())
  17. .withAbilityName(リモート電話の能力)
  18. .withFlags(Intent.FLAG_ABILITYSLICE_MULTI_DEVICE)
  19. 。建てる();
  20. connectPaIntent.setOperation(操作);
  21.  
  22. connectAbility(connectPaIntent、接続);
  23. }
  24.  
  25. //接続コールバックインスタンスの作成
  26. プライベートファイナルIAbilityConnection接続=
  27. 新しいIAbilityConnection() {
  28. //サービス接続するためのコールバック
  29. @オーバーライド
  30. パブリックvoid onAbilityConnectDone(ElementName elementName, IRemoteObject iRemoteObject, int resultCode) {
  31. myProxy = 新しい MyRemoteProxy(iRemoteObject);
  32. }
  33.  
  34. //サービスから切断するためのコールバック
  35. @オーバーライド
  36. パブリックvoid onAbilityDisconnectDone(要素名要素名、 int結果コード) {
  37. 切断可能性(これ);
  38. }
  39. };

2番目の部分は、リモートコントロールコールバックの登録、ビデオプレーヤーコンポーネントのRemoteControlcallbackインターフェイス(VideoPlayerview)の実装、および現在のプレーヤー情報を同期するために携帯電話にデータを送信することです。

  1. //リモートコントロールコールバックを登録します
  2. videobox.registerRemotecontrolcallback(RemoteControlCallback);
  3.  
  4.  
  5.  
  6. /**
  7. *リモートコントロールコールバック、ソースCommonlib、進行状況バーの進行状況/再生ステータス/ボリュームの同期に使用されます
  8. */
  9. private videoplayerview.Remotecontrolcallback Remotecontrolcallback =
  10. 新しいvideoplayerview.remotecontrolcallback(){
  11. @オーバーライド
  12. //進捗バーの変更
  13. Public void onprogresschanged(長い合計、 int進行){
  14. hilog.debug(label、 "onprogresschanged、myproxy:" +myproxy);
  15. if(myproxy!= null ){
  16. map <string、string> progressValue = new Hashmap <>();
  17. //合計時間と進捗値を設定します
  18. ProgressValue.put(RemoteConstant.Remote_Key_video_total_time、string.valueof(totaltime));
  19. ProgressValue.put(RemoteConstant.Remote_Key_video_current_progress、string.valueof(progress));
  20.  
  21. //携帯電話のコントロールパネルへの同期の進行
  22. myproxy.senddatatoremote(
  23. RemoteConstant.Request_sync_video_status、
  24. controlCode.sync_video_process.getCode()、
  25. ProgressValue);
  26. }
  27. }
  28.  
  29. @オーバーライド
  30. //再生ステータスが変更されます
  31. public void onplayingstatuschanged(boolean isplaying){
  32. if(myproxy!= null ){
  33. map <string、string> videostatusmap = new Hashmap <>();
  34. videostatusmap.put(
  35. RemoteConstant.Remote_Key_video_current_playback_status、string.valueof(isplaying));
  36. hilog.debug(label、 "isplaying =" + string.valueof(isplaying));
  37. myproxy.senddatatoremote(
  38. RemoteConstant.Request_sync_video_status、
  39. controlCode.sync_video_status.getCode()、
  40. videostatusmap);
  41. }
  42. }
  43.  
  44. @オーバーライド
  45. //ボリュームの変更
  46. public void onvolumechanged( int volume){
  47. if(myproxy!= null ){
  48. map <string、string> volumemap = new Hashmap <>();
  49. volumemap.put(RemoteConstant.Remote_key_video_current_volume、string.valueof(volume));
  50. myproxy.senddatatoremote(
  51. RemoteConstant.Request_sync_video_status、
  52. controlCode.sync_video_volume.getCode()、
  53. volumemap);
  54. }
  55. }
  56. };

3番目の部分は、ビデオコントロールサービス(VideoControlServiceability)によって送信されたイベントを購読し、プレーヤーコントロールイベントを処理することです。

  1. /**
  2. *ユニバーサルイベントサブスクリプション
  3. */
  4. private void subscribe(){
  5. hilog.debug(label、 "subscribe" );
  6. MatchingsKills MatchingSkills = new MatchingsKills();
  7. Matchingskills.addevent(constants.tv_control_event);
  8. Matchingskills.addevent(commoneventsupport.common_event_screen_on);
  9. commoneventsubscribeinfo subscribeinfo = new commoneventsubscribeinfo(matchingskills);
  10. //購読者
  11. tvsubscriber = new myCommoneventsubscriber(subscribeinfo);
  12. 試す {
  13. commoneventmanager.subscribecommonevent(tvsubscriber);
  14. } catch(remoteexception e){
  15. hilog.error(label、 "subscribscommoneventは例外を発生します。" );
  16. }
  17. }
  18.  
  19. /**
  20. *登録解除
  21. */
  22. private void unsubscribe(){
  23. hilog.debug(label、 "subscribe" );
  24. 試す {
  25. commoneventmanager.unsubscribecommonevent(tvsubscriber);
  26. } catch(remoteexception e){
  27. hilog.error(ラベル、 「登録解除例外」 );
  28. }
  29. }
  30.  
  31. /**
  32. *ビデオ制御サービス(VideoControlServiceAbility)イベント加入者
  33. */
  34. クラスmycommoneventsubscriberはcommoneventsubscriberを拡張します{
  35. mycommoneventsubscriber(commoneventsubscribeinfo info){
  36. super(info);
  37. }
  38.  
  39. @オーバーライド
  40. public void onreceiveEvent(commoneventdata commoneventdata){
  41. hilog.info(label、 "onreceiveEvent ..." );
  42.  
  43. Intent Intent = commoneventdata.getIntent();
  44. int controlcode = intent.getintparam(constants.key_control_code、0);
  45. string extras = intent.getStringParam(constants.key_control_value);
  46.  
  47. //再生または一時停止
  48. if(controlCode == controlCode.play.getCode()){
  49. if(videobox.isplaying()){
  50. videobox.pause();
  51. } else if(!videobox.isplaying()&&!needresumestatus){
  52. videobox.start();
  53. }それ以外{
  54. hilog.error(ラベル、 「プレーヤーステータスでケースを無視する」 );
  55. }
  56. //再生の進行状況をドラッグします
  57. } else if(controlcode == controlcode.seek.getCode()){
  58. videobox.seekto(videobox.getDuration() * integer .parseint(extras) / 100);
  59. //早送り
  60. } else if(controlCode ==controlCode。forward.getCode )){
  61. videobox.seekto(videobox.getCurrentPosition() + constants.rewind_step);
  62. //すばやく後退します
  63. } else if(controlcode == controlcode.backward.getCode()){
  64. videobox.seekto(videobox.getCurrentPosition() - constants.rewind_step);
  65. //ボリュームアップ
  66. } else if(controlcode == controlcode.volume_add.getCode()){
  67. videobox.setvolume(constants.volume_step);
  68. //ボリュームをダウンロードします
  69. } else if(controlcode == controlcode.volume_reduced.getCode()){
  70. videobox.setvolume(-constants.volume_step);
  71. //再生速度を切り替えます
  72. } else if(controlcode == controlcode.switch_speed.getCode()){
  73. videobox.setPlayBackSpeed( float .Parsefloat(extras));
  74. // HDなどのビデオソースを切り替えます
  75. } else if(controlCode == ControlCode.switch_Resolution.getCode()){
  76. long currentposition = videobox.getCurrentPosition();
  77. int ResolutionIndex = integer .Parseint(extras);
  78. videoinfo videolinfo = videoinfoservice.getVideoinfobyIndex(currentPlayingIndex);
  79. videobox.pause();
  80.  
  81. //新しい再生URLを設定します
  82. videobox.setvideopath(videoinfo.getResolutions()。get(ResolutionIndex).geturl());
  83. //元の再生位置に調整します
  84. videobox.setPlayeronPreparedListener(
  85. () - > {
  86. videobox.seekto(currentPosition);
  87. videobox.start();
  88. });
  89. //ビデオを切り替えます
  90. } else if(controlcode == controlcode.switch_video.getCode()){
  91. videobox.pause();
  92. currentPlayingIndex = integer .parseint(extras);
  93. videoinfo videolinfo = videoinfoservice.getVideoinfobyIndex(currentPlayingIndex);
  94. videobox.setvideopathandtitle(videoinfo.getResolutions()。
  95. videobox.setPlayeronPreparedListener(() - > videobox.start());
  96.  
  97. //接続を停止します
  98. } else if(controlcode == controlcode.stop_connection.getCode()){
  99. 終了();
  100. }それ以外{
  101. hilog.error(ラベル、 「コントロールコードでケースを無視する」 );
  102. }
  103. }
  104. }

この時点で、携帯電話のコントロールとテレビの終わりの間のプロセスが解釈されており、ビデオ解像度の切り替え、ビデオシリーズの切り替えなどの詳細は、グローバルプロセスに影響を与えることなく拡張されません。

両端に関係する権限は次のとおりです。

  1. {
  2. 「名前」 "ohos.permiss.internet"
  3. "理由" ""
  4. 「使用シーン」 : {
  5. "能力" : [
  6. 「VideoPlayabilitySlice」  
  7. ]、
  8. 「いつ」 「inuse」  
  9. }
  10. },
  11. {
  12. 「名前」 : 「ohos.permission.DISTRIBUTED_DATASYNC」
  13. "理由" ""
  14. 「使用シーン」 : {
  15. "能力" : [
  16. 「VideoPlayabilitySlice」  
  17. ]、
  18. 「いつ」 「inuse」  
  19. }
  20. },
  21. {
  22. "name" "ohos.permiss.distributed_device_state_change"
  23. "理由" ""
  24. 「使用シーン」 : {
  25. "能力" : [
  26. 「VideoPlayabilitySlice」  
  27. ]、
  28. 「いつ」 「inuse」  
  29. }
  30. },
  31. {
  32. "name" "ohos.permiss.get_distributed_device_info"
  33. "理由" ""
  34. 「使用シーン」 : {
  35. "能力" : [
  36. 「VideoPlayabilitySlice」  
  37. ]、
  38. 「いつ」 「inuse」  
  39. }
  40. },
  41. {
  42. "name" "ohos.permission.get_bundle_info"
  43. "理由" ""
  44. 「使用シーン」 : {
  45. "能力" : [
  46. 「VideoPlayabilitySlice」  
  47. ]、
  48. 「いつ」 「inuse」  
  49. }
  50. },
  51. {
  52. "name" "ohos.permiss.keep_background_running"
  53. "理由" ""
  54. 「使用シーン」 : {
  55. "能力" : [
  56. 「VideoPlayabilitySlice」  
  57. ]、
  58. 「いつ」 「inuse」  
  59. }
  60. }

レビューの概要

携帯電話でのテレビのビデオ再生を制御するプロセス

携帯電話:

点击手机端播放器(VideoPlayAbilitySlice)的【流转】按钮-------获取&选择可以流转的设备----启动TV端播放器(MainAbility/VideoPlayAbilitySlice) & 连接TV端播放控制服务(VideoControlServiceAbility)-----在建立连接后,初始化控制面板并且对控制操作进行监听。

コントロールパネル(RemoteController)を操作する場合 - リリースイベント通知プレーヤーコンポーネント(VideoPlayabilitySlice)は、コントロールサービスのリモートプロキシ(MyRemoteproxy、CommonLibが提供)を使用して、TV Playback Controlサービス(VideoControlServiceability)にコントロール指示を送信します。

テレビの終わり:

当TV端播放器(VideoPlayAbilitySlice)被启动时-----初始化视频播放器组件& 注册远端控制回调(registerRemoteControlCallback) & 获取手机端Intent传递的视频索引+视频URL+播放进度+手机端设备ID-----然后连接手机端的同步控制服务(SyncControlServiceAbility)— 在建立连接后,初始化代理(MyRemoteProxy)-----订阅手机端播放器控制事件。

当播放控制服务(VideoControlServiceAbility)收到控制指令后-----通过事件方式发布通知-----视频播放器(VideoPlayAbilitySlice)收到通知后对播放器进行设置-----注册远端控制回调(remoteControlCallback)将状态同步给远端的手机端。

記事に関連する添付ファイルをダウンロードするには、以下のリンクをクリックしてください。

https://harmonyos..com/resource/1356

詳細については、以下をご覧ください。

51CTOとHuaweiが共同で構築したHongmengテクノロジーコミュニティ

https://harmonyos..com

<<:  ファーウェイクラウドの張秀正氏:ユーザー数の増加からビジネスの収益性まで、技術革新は電子商取引のアップグレードの継続的な原動力です

>>:  SAP、2021年第3四半期の財務レポートを発表: SAPクラウドビジネスの成長が大幅に加速、SAP導入が急増

推薦する

errantweb-4 USD/3 コア/1 GB RAM/50 GB ハードドライブ/2 TB トラフィック/サンディエゴ

errantwebは1月に設立されたVPS業者です。openvzとkVM仮想化をベースにしたVPSを...

bettervps-512m メモリ KVM/20g ハードディスク/1T 月間トラフィック/月額 5 ドル

BetterVPS は、2011 年に Web デザイナーと開発者によって設立された ShoveHo...

ウェブサイトのSEO戦略と事例分析

ウェブサイトの SEO 戦略は、ウェブサイトの運用と開発に関係しています。大規模なウェブサイトの運用...

WeChatパブリックアカウントの運用とプロモーション方法!

個人のWeChatパブリックアカウントの運用は、一般的に初期段階、中期段階、後期段階の3段階を経ます...

AIOpsはハイブリッドマルチクラウド管理のゲームチェンジャーです

認知と自動化を組み合わせた運用プラットフォームを通じて、エンタープライズハイブリッドマルチクラウドア...

ローカルフォーラムで投稿署名を使用して、高いコンバージョン率のトラフィックを引き付ける方法

ウェブマスターなら誰でもフォーラム署名をよく知っています。これはウェブサイトが外部リンクを作成する方...

実際のWeiboマーケティング事例 - 140語の遊び方を教える

WeChatは現在非常に人気がありますが、それに比べるとWeiboははるかに暗いようです。どちらにも...

Weibo SEO最適化のマーケティング戦略に関する予備的研究

実際のWeiboマーケティングは、活動によって推進され、詳細で慎重なマーケティング計画とプロモーショ...

SEOツール Dibz

Dibz は使いやすい SEO ツールです。導入Dibz を使用すると、ユーザーは特定の検索基準に基...

インターネット上でブランドアーキテクチャを定義する方法

ブランドは、私たち一人ひとりにとって、大なり小なり意味を持つ定義です。なぜなら、Web サイトを作成...

サーバーレスによるソフトウェアパフォーマンスの向上

01. 研究開発効率向上の目標と課題1.1 研究開発効率管理の目的まず、典型的な SaaS ソフトウ...

Kubernetes の高度なデプロイメント戦略

最新のアプリケーション テクノロジーの分野では、コンテナ オーケストレーション プラットフォームによ...

dataplugs - イースター、香港専用サーバー、最大 1000 香港ドルの割引

Duoxiantong のイースター イベントが始まりました: 2020 年 3 月 22 日から ...