1/* 2 * Copyright (c) 2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import featureAbility from '@ohos.ability.featureAbility' 17import RemoteDeviceModel from '../../model/RemoteDeviceModel.js' 18import PlayerModel from '../../model/PlayerModel.js' 19import KvStoreModel from '../../model/KvStoreModel.js' 20import { logger } from '../../model/Logger' 21 22function getShownTimer(ms) { 23 var seconds = Math.floor(ms / 1000) 24 var sec = seconds % 60 25 var min = (seconds - sec) / 60 26 if (sec < 10) { 27 sec = '0' + sec 28 } 29 if (min < 10) { 30 min = '0' + min 31 } 32 return min + ':' + sec 33} 34 35const REMOTE_ABILITY_STARTED = 'remoteAbilityStarted' 36var DEVICE_LIST_LOCALHOST 37const TAG = 'Index' 38let lastTime = -1 39 40export default { 41 data: { 42 title: '', 43 currentTimeText: '', 44 totalTimeText: '', 45 totalMs: 0, 46 currentProgress: 0, 47 deviceList: [], 48 btnPlaySrc: '/common/media/ic_play.svg', 49 albumSrc: '/common/media/album.png', 50 remoteDeviceModel: new RemoteDeviceModel(), 51 playerModel: new PlayerModel(), 52 kvStoreModel: new KvStoreModel(), 53 isDialogShowing: false, 54 isSwitching: false, 55 }, 56 onInit() { 57 logger.info(TAG, `onInit begin`) 58 this.grantPermission() 59 DEVICE_LIST_LOCALHOST = { 60 name: this.$t('strings.localhost'), 61 id: 'localhost', 62 } 63 this.deviceList = [DEVICE_LIST_LOCALHOST] 64 65 this.currentTimeText = getShownTimer(0) 66 this.playerModel.setOnStatusChangedListener((isPlaying) => { 67 logger.debug(TAG, `on player status changed, isPlaying=${isPlaying} refresh ui`) 68 this.playerModel.setOnPlayingProgressListener((currentTimeMs) => { 69 if (lastTime === currentTimeMs) { 70 this.playerModel.pause() 71 } else { 72 lastTime = currentTimeMs 73 } 74 this.currentTimeText = getShownTimer(currentTimeMs) 75 this.currentProgress = Math.floor(currentTimeMs / this.totalMs * 100) 76 }) 77 if (isPlaying) { 78 this.btnPlaySrc = '/common/media/ic_pause.svg' 79 } else { 80 this.btnPlaySrc = '/common/media/ic_play.svg' 81 } 82 }) 83 this.playerModel.getPlaylist(() => { 84 logger.info(TAG, `on playlist generated, refresh ui`) 85 this.restoreFromWant() 86 }) 87 logger.info(TAG, `onInit end`) 88 }, 89 grantPermission() { 90 logger.info(TAG, `grantPermission`) 91 let context = featureAbility.getContext() 92 context.requestPermissionsFromUser(['ohos.permission.DISTRIBUTED_DATASYNC'], 666, function (result) { 93 logger.debug(TAG, `grantPermission,requestPermissionsFromUser,result.requestCode=${result.requestCode}`) 94 }) 95 }, 96 restoreFromWant() { 97 featureAbility.getWant((error, want) => { 98 logger.debug(TAG, `featureAbility.getWant=${JSON.stringify(want)}`) 99 var status = want.parameters 100 if (status != null && status.uri != null) { 101 this.kvStoreModel.broadcastMessage(REMOTE_ABILITY_STARTED) 102 logger.info(TAG, `restorePlayingStatus`) 103 this.playerModel.restorePlayingStatus(status, (index) => { 104 logger.debug(TAG, `restorePlayingStatus finished, index=${index}`) 105 if (index >= 0) { 106 this.refreshSongInfo(index) 107 } else { 108 this.playerModel.preLoad(0, () => { 109 this.refreshSongInfo(0) 110 }) 111 } 112 }) 113 } else { 114 this.playerModel.preLoad(0, () => { 115 this.refreshSongInfo(0) 116 }) 117 } 118 }) 119 }, 120 onNewRequest() { 121 logger.info(TAG, `onNewRequest`) 122 }, 123 onHide() { 124 logger.info(TAG, `onHide isDialogShowing=${this.isDialogShowing}`) 125 if (this.isDialogShowing === true) { 126 this.dismissDialog() 127 return true 128 } 129 return false 130 }, 131 onDestroy() { 132 logger.info(TAG, `onDestroy begin`) 133 if (this.playerModel === undefined) { 134 return 135 } 136 this.playerModel.release() 137 this.remoteDeviceModel.unregisterDeviceListCallback() 138 logger.info(TAG, `onDestroy end`) 139 }, 140 refreshSongInfo(index) { 141 logger.debug(TAG, `refreshSongInfo ${index}/${this.playerModel.playlist.audioFiles.length}`) 142 if (index >= this.playerModel.playlist.audioFiles.length) { 143 logger.warn(TAG, `refreshSongInfo ignored`) 144 return 145 } 146 // update song title 147 this.title = this.playerModel.playlist.audioFiles[index].name 148 this.albumSrc = (index % 2 === 0) ? '/common/media/album.png' : '/common/media/album2.png' 149 150 // update duration 151 this.totalMs = this.playerModel.getDuration() 152 this.totalTimeText = getShownTimer(this.totalMs) 153 this.currentTimeText = getShownTimer(0) 154 this.currentProgress = 0 155 156 logger.debug(TAG, `refreshSongInfo this.title=${this.title} this.totalMs=${this.totalMs}` 157 + ` this.totalTimeText=${this.totalTimeText}this.currentTimeText=${this.currentTimeText}`) 158 }, 159 setProgress(e) { 160 logger.debug(TAG, `setProgress ${e.mode}, ${e.value}`) 161 this.currentProgress = e.value 162 if (isNaN(this.totalMs)) { 163 this.currentProgress = 0 164 logger.debug(TAG, `setProgress ignored, totalMs=${this.totalMs}`) 165 return 166 } 167 var currentMs = this.currentProgress / 100 * this.totalMs 168 this.currentTimeText = getShownTimer(currentMs) 169 if (e.mode === 'end' || e.mode === 'click') { 170 logger.debug(TAG, `player.seek ${currentMs}`) 171 this.playerModel.seek(currentMs) 172 } 173 }, 174 onPreviousClick() { 175 if (this.isSwitching) { 176 logger.info(TAG, `onPreviousClick ignored, isSwitching`) 177 return 178 } 179 logger.info(TAG, `onPreviousClick`) 180 this.playerModel.index-- 181 if (this.playerModel.index < 0 && this.playerModel.playlist.audioFiles.length >= 1) { 182 this.playerModel.index = this.playerModel.playlist.audioFiles.length - 1 183 } 184 this.currentProgress = 0 185 this.isSwitching = true 186 this.playerModel.preLoad(this.playerModel.index, () => { 187 this.refreshSongInfo(this.playerModel.index) 188 this.playerModel.play(0, true) 189 this.isSwitching = false 190 }) 191 }, 192 onNextClick() { 193 if (this.isSwitching) { 194 logger.info(TAG, `onNextClick ignored, isSwitching`) 195 return 196 } 197 logger.info(TAG, `onNextClick`) 198 this.playerModel.index++ 199 if (this.playerModel.index >= this.playerModel.playlist.audioFiles.length) { 200 this.playerModel.index = 0 201 } 202 this.currentProgress = 0 203 this.isSwitching = true 204 this.playerModel.preLoad(this.playerModel.index, () => { 205 this.refreshSongInfo(this.playerModel.index) 206 this.playerModel.play(0, true) 207 this.isSwitching = false 208 }) 209 }, 210 onPlayClick() { 211 if (this.isSwitching) { 212 logger.info(TAG, `onPlayClick ignored, isSwitching`) 213 return 214 } 215 logger.debug(TAG, `onPlayClick, isPlaying=${this.playerModel.isPlaying}`) 216 if (this.playerModel.isPlaying) { 217 this.playerModel.pause() 218 } else { 219 this.playerModel.preLoad(this.playerModel.index, () => { 220 this.playerModel.play(-1, true) 221 }) 222 } 223 }, 224 onContinueAbilityClick() { 225 logger.info(TAG, `onContinueAbilityClick begin`) 226 this.remoteDeviceModel.registerDeviceListCallback(() => { 227 logger.info(TAG, `registerDeviceListCallback, callback entered`) 228 var list = [] 229 list[0] = DEVICE_LIST_LOCALHOST 230 var deviceList 231 if (this.remoteDeviceModel.discoverList.length > 0) { 232 deviceList = this.remoteDeviceModel.discoverList 233 } else { 234 deviceList = this.remoteDeviceModel.deviceList 235 } 236 logger.debug(TAG, `on remote device updated, count=${deviceList.length}`) 237 for (var i = 0; i < deviceList.length; i++) { 238 logger.debug(TAG, `device ${i}/${deviceList.length} deviceId=${deviceList[i].deviceId}` + 239 ` deviceName=${deviceList[i].deviceName} deviceType=${deviceList[i].deviceType}`) 240 list[i + 1] = { 241 name: deviceList[i].deviceName, 242 id: deviceList[i].deviceId, 243 } 244 } 245 this.deviceList = list 246 }) 247 this.$element('continueAbilityDialog').show() 248 this.isDialogShowing = true 249 logger.info(TAG, `onContinueAbilityClick end`) 250 }, 251 startAbilityContinuation(deviceId, deviceName) { 252 this.$element('continueAbilityDialog').close() 253 var params 254 if (this.playerModel.index >= 0 && this.playerModel.index <= this.playerModel.playlist.audioFiles.length) { 255 params = { 256 uri: this.playerModel.playlist.audioFiles[this.playerModel.index].fileUri, 257 seekTo: this.playerModel.getCurrentMs(), 258 isPlaying: this.playerModel.isPlaying 259 } 260 } else { 261 params = { 262 uri: '', 263 seekTo: 0, 264 isPlaying: false 265 } 266 } 267 logger.debug(TAG, `featureAbility.startAbility deviceId=${deviceId} deviceName=${deviceName}`) 268 var wantValue = { 269 bundleName: 'ohos.samples.distributedmusicplayer', 270 abilityName: 'ohos.samples.distributedmusicplayer.MainAbility', 271 deviceId: deviceId, 272 parameters: params 273 } 274 var timerId = setTimeout(() => { 275 logger.info(TAG, `onMessageReceiveTimeout, terminateSelf`) 276 featureAbility.terminateSelf((error) => { 277 logger.error(TAG, `terminateSelf finished, error=${error}`) 278 }) 279 }, 3000) 280 this.kvStoreModel.setOnMessageReceivedListener(REMOTE_ABILITY_STARTED, () => { 281 logger.info(`OnMessageReceived, terminateSelf`) 282 clearTimeout(timerId) 283 featureAbility.terminateSelf((error) => { 284 logger.error(`terminateSelf finished, error=${error}`) 285 }) 286 }) 287 featureAbility.startAbility({ 288 want: wantValue 289 }).then((data) => { 290 logger.debug(TAG, `featureAbility.startAbility finished, ${JSON.stringify(data)}`) 291 }) 292 logger.debug(TAG, `featureAbility.startAbility want=${JSON.stringify(wantValue)}`) 293 logger.info(TAG, `featureAbility.startAbility end`) 294 }, 295 onRadioChange(inputValue, e) { 296 logger.debug(TAG, `onRadioChange ${inputValue} ${e.value}`) 297 if (inputValue === e.value) { 298 if (e.value === 'localhost') { 299 this.$element('continueAbilityDialog').close() 300 return 301 } 302 if (this.remoteDeviceModel.discoverList.length > 0) { 303 logger.info(TAG, `continue to unauthed device`) 304 var name = null 305 for (var i = 0; i < this.remoteDeviceModel.discoverList.length; i++) { 306 if (this.remoteDeviceModel.discoverList[i].deviceId === e.value) { 307 name = this.remoteDeviceModel.discoverList[i].deviceName 308 break 309 } 310 } 311 if (name === null) { 312 logger.error(TAG, `onRadioChange failed, can not get name from discoverList`) 313 return 314 } 315 logger.debug(TAG, `onRadioChange name=${name}`) 316 this.$element('continueAbilityDialog').close() 317 318 this.remoteDeviceModel.authDevice(e.value, () => { 319 logger.info(TAG, `auth and online finished`) 320 for (i = 0; i < this.remoteDeviceModel.deviceList.length; i++) { 321 if (this.remoteDeviceModel.deviceList[i].deviceName === name) { 322 this.startAbilityContinuation(this.remoteDeviceModel.deviceList[i].networkId, this.remoteDeviceModel.deviceList[i].deviceName) 323 } 324 } 325 }) 326 } else { 327 logger.info(TAG, `continue to authed device`) 328 for (i = 0; i < this.remoteDeviceModel.deviceList.length; i++) { 329 if (this.remoteDeviceModel.deviceList[i].deviceId === e.value) { 330 this.startAbilityContinuation(this.remoteDeviceModel.deviceList[i].networkId, this.remoteDeviceModel.deviceList[i].deviceName) 331 } 332 } 333 } 334 } 335 }, 336 cancelDialog(e) { 337 this.remoteDeviceModel.unregisterDeviceListCallback() 338 this.isDialogShowing = false 339 }, 340 onDismissDialogClicked(e) { 341 this.dismissDialog() 342 }, 343 dismissDialog() { 344 this.$element('continueAbilityDialog').close() 345 this.remoteDeviceModel.unregisterDeviceListCallback() 346 this.isDialogShowing = false 347 } 348} 349