闹钟FA开发闹钟界面
本节之前,我们已经完成了闹钟设置FA的开发。本节我们将在闹钟FA开发一个界面显示闹钟和一个关闭按钮,并播放闹钟声音。
1.添加播放闹钟声音的封装类
1.1 代码来自codelab分布式“HarmonyOS 分布式视频播放”,新增PlayerStateListener.java和PlayerManager.java封装音乐播放。 PlayerStateListener.java
package com.madixin.clock.clock.util;
/**
* PlayerStateListener
*/
public interface PlayerStateListener {
void onPlaySuccess(int totalTime);
void onPauseSuccess();
void onPositionChange(int currentTime);
void onMusicFinished();
void onUriSet(String name);
}
PlayerStateListener.java
package com.madixin.clock.clock.util;
import com.madixin.clock.common.util.LogUtil;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.eventhandler.InnerEvent;
import ohos.global.resource.BaseFileDescriptor;
import ohos.global.resource.RawFileEntry;
import ohos.media.audio.SoundPlayer;
import ohos.media.player.Player;
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;
/**
* player manager
*/
public class PlayerManager {
private static final String TAG = PlayerManager.class.getSimpleName();
private static final int PLAY_STATE_PLAY = 0x0000001;
private static final int PLAY_STATE_PAUSE = 0x0000002;
private static final int PLAY_STATE_FINISH = 0x0000003;
private static final int PLAY_STATE_PROGRESS = 0x0000004;
private static final int DELAY_TIME = 1000;
private static final int PERIOD = 1000;
private Player musicPlayer;
private Context context;
private String currentUri;
private TimerTask timerTask;
private Timer timer;
private PlayerStateListener playerStateListener;
private boolean isPrepared;
public PlayerManager(Context context, String currentUri) {
this.context = context;
this.currentUri = currentUri;
}
/**
* init media resource
*/
public void init() {
musicPlayer = new Player(context);
musicPlayer.setPlayerCallback(new PlayCallBack());
setResource(currentUri);
}
/**
* set source
*
* @param uri music uri
*/
public void setResource(String uri) {
LogUtil.info(TAG, "uri: " + uri);
try {
RawFileEntry rawFileEntry = context.getResourceManager().getRawFileEntry(uri);
BaseFileDescriptor baseFileDescriptor = rawFileEntry.openRawFileDescriptor();
if (!musicPlayer.setSource(baseFileDescriptor)) {
LogUtil.info(TAG, "uri is invalid");
return;
}
isPrepared = musicPlayer.prepare();
playerStateListener.onUriSet(
currentUri.substring(currentUri.lastIndexOf("/") + 1, currentUri.lastIndexOf(".")));
} catch (IOException e) {
LogUtil.error(TAG, "io exception");
}
}
/**
* play
*/
public void play() {
if (!isPrepared) {
LogUtil.error(TAG, "prepare fail");
return;
}
if (!musicPlayer.play()) {
LogUtil.error(TAG, "play fail");
return;
}
startTask();
handler.sendEvent(PLAY_STATE_PLAY);
}
/**
* pause
*/
public void pause() {
if (!musicPlayer.pause()) {
LogUtil.info(TAG, "pause fail");
return;
}
finishTask();
handler.sendEvent(PLAY_STATE_PAUSE);
}
private EventHandler handler = new EventHandler(EventRunner.current()) {
@Override
protected void processEvent(InnerEvent event) {
switch (event.eventId) {
case PLAY_STATE_PLAY: {
playerStateListener.onPlaySuccess(getTotalTime());
break;
}
case PLAY_STATE_PAUSE: {
playerStateListener.onPauseSuccess();
break;
}
case PLAY_STATE_FINISH: {
playerStateListener.onMusicFinished();
break;
}
case PLAY_STATE_PROGRESS: {
playerStateListener.onPositionChange(musicPlayer.getCurrentTime());
break;
}
default:
break;
}
}
};
private void startTask() {
finishTask();
timerTask = new TimerTask() {
@Override
public void run() {
handler.sendEvent(PLAY_STATE_PROGRESS);
}
};
timer = new Timer();
timer.schedule(timerTask, DELAY_TIME, PERIOD);
}
private void finishTask() {
if (timer != null && timerTask != null) {
timer.cancel();
timer = null;
timerTask = null;
}
}
/**
* get duration
*
* @return total time
*/
public int getTotalTime() {
return musicPlayer.getDuration();
}
/**
* switch music
*
* @param uri music uri
*/
public void switchMusic(String uri) {
currentUri = uri;
setResource(currentUri);
play();
}
/**
* changes the playback position
*
* @param currentTime current time
*/
public void rewindTo(int currentTime) {
musicPlayer.rewindTo(currentTime * 1000);
}
/**
* release
*/
public void releasePlayer() {
if (musicPlayer == null) {
return;
}
musicPlayer.stop();
musicPlayer.release();
}
/**
* play state
*
* @return true:playing , false:pause
*/
public boolean isPlaying() {
return musicPlayer.isNowPlaying();
}
private class PlayCallBack implements Player.IPlayerCallback {
@Override
public void onPrepared() {
LogUtil.info(TAG, "onPrepared");
}
@Override
public void onMessage(int type, int extra) {
LogUtil.info(TAG, "onMessage " + type + "-" + extra);
}
@Override
public void onError(int errorType, int errorCode) {
LogUtil.info(TAG, "onError " + errorType + "-" + errorCode);
}
@Override
public void onResolutionChanged(int width, int height) {
LogUtil.info(TAG, "onResolutionChanged " + width + "-" + height);
}
@Override
public void onPlayBackComplete() {
handler.sendEvent(PLAY_STATE_FINISH);
LogUtil.info(TAG, "onPlayBackComplete");
}
@Override
public void onRewindToComplete() {
LogUtil.info(TAG, "onRewindToComplete");
}
@Override
public void onBufferingChange(int percent) {
LogUtil.info(TAG, percent + "");
}
@Override
public void onNewTimedMetaData(Player.MediaTimedMetaData mediaTimedMetaData) {
LogUtil.info(TAG, "onNewTimedMetaData");
}
@Override
public void onMediaTimeIncontinuity(Player.MediaTimeInfo mediaTimeInfo) {
LogUtil.info(TAG, "onNewTimedMetaData");
}
}
/**
* player state listener
*
* @param playerStateListener listener
*/
public void setPlayerStateListener(PlayerStateListener playerStateListener) {
this.playerStateListener = playerStateListener;
}
}
2.开发闹钟界面
1.1 在clock>src>main>resources>base>element>string.json中添加新的文字资源。
{
"name": "timeup",
"value": "到点了"
},
{
"name": "close",
"value": "关闭"
}
1.2 在clock>src>main>resources>base>graphic下添加按钮背景资源文件。 background_button.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:shape="rectangle">
<corners
ohos:radius="40"/>
<solid
ohos:color="#007CFD"/>
</shape>
1.3 在clock>src>main>resources>base>layout下添加按钮闹钟页面资源文件。这个界面暂时简单实现,仅放置一个TEXT和一个Button控件。 ability_clock_alarm.xml
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_parent"
ohos:width="match_parent"
ohos:orientation="vertical">
<Text
ohos:id="$+id:text_helloworld"
ohos:height="match_content"
ohos:width="match_content"
ohos:background_element="$graphic:background_ability_clock_alarm"
ohos:layout_alignment="horizontal_center"
ohos:text="$string:timeup"
ohos:text_size="30vp"
ohos:top_margin="30fp"
/>
<Button
ohos:id="$+id:btn_close"
ohos:height="50vp"
ohos:width="match_parent"
ohos:text="$string:close"
ohos:text_size="30vp"
ohos:background_element="$graphic:background_button"
ohos:top_margin="30fp"/>
</DirectionalLayout>
1.4 修改ClockAlarmAbilitySlice,在onStart方法中通过intent获取闹铃名称,使用PlayerManager拉起音乐。点击关闭按钮后关闭当前ability。
package com.madixin.clock.clock.slice;
import com.madixin.clock.clock.ResourceTable;
import com.madixin.clock.clock.util.PlayerManager;
import com.madixin.clock.clock.util.PlayerStateListener;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.components.Button;
public class ClockAlarmAbilitySlice extends AbilitySlice {
private PlayerManager playerManager;
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_clock_alarm);
Button btnClose = (Button) findComponentById(ResourceTable.Id_btn_close);
btnClose.setClickedListener((button) -> {
if (playerManager.isPlaying()){
playerManager.releasePlayer();
}
this.terminate();//暂时直接关闭
});
String bell = "Canon";
if (intent != null) {
Object obj = intent.getStringParam("bell");
if (obj instanceof String) {
bell = (String) obj;
}
}
initMedia(bell);
}
@Override
public void onActive() {
super.onActive();
}
@Override
public void onForeground(Intent intent) {
super.onForeground(intent);
}
private void initMedia(String bell) {
playerManager = new PlayerManager(this, "resources/rawfile/" + bell + ".mp3");
playerManager.setPlayerStateListener(new PlayerStateListener() {
@Override
public void onPlaySuccess(int totalTime) {
}
@Override
public void onPauseSuccess() {
}
@Override
public void onPositionChange(int currentTime) {
}
@Override
public void onMusicFinished() {
}
@Override
public void onUriSet(String name) {
}
});
playerManager.init();
playerManager.play();
}
}
3.小结
本章完在闹钟FA里完成了闹钟界面的开发。
下一步我们将在闹钟设置FA钟增加一个定时调用的PA,拉起闹钟界面,并实现点击关闭后,自动关闭FA以及修改PA的状态。
4.代码地址:
github,提交记录:c90f87e2928993d1e197e00220f8bd708eaeacd6