Hongmeng App: Multi-device Alarm Clock Development Tutorial (7)

Alarm clock FA develops alarm clock interface

Before this section, we have completed the development of the alarm clock setting FA. In this section, we will develop an interface in the alarm clock FA to display the alarm clock and a close button, and play the alarm clock sound.

 

1. Add an encapsulation class that plays the alarm clock sound

1.1 The code comes from the codelab distributed "HarmonyOS Distributed Video Playback", and PlayerStateListener.java and PlayerManager.java are added to encapsulate music playback. 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. Develop alarm clock interface

1.1 Add a new text resource in clock>src>main>resources>base>element>string.json.

    {
      "name": "timeup",
      "value": "到点了"
    },
    {
      "name": "close",
      "value": "关闭"
    }

1.2 Add button background resource files under 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 Add button alarm clock page resource files under clock>src>main>resources>base>layout. This interface is temporarily implemented simply, only placing a TEXT and a Button control. 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 Modify ClockAlarmAbilitySlice, get the alarm name through intent in the onStart method, and use PlayerManager to pull up the music. Close the current ability after clicking the close button.

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. Summary

At the end of this chapter, the development of the alarm clock interface is completed in the alarm clock FA.

In the next step, we will add a regularly called PA to the FA clock in the alarm clock setting, pull up the alarm clock interface, and realize that after clicking Close, the FA will be automatically closed and the status of the PA will be modified.

4. Code address:

github , commit record: c90f87e2928993d1e197e00220f8bd708eaeacd6

Guess you like

Origin blog.csdn.net/sd2131512/article/details/117572356