1/*
2 * Copyright (c) 2020 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
16#include "player_ability_slice.h"
17#include <algorithm>
18#include <vector>
19
20#include "ability_env.h"
21#include "ability_manager.h"
22#include "components/ui_image_view.h"
23#include "gfx_utils/file.h"
24
25using OHOS::Media::Player;
26using OHOS::Media::Source;
27using namespace OHOS::Media;
28
29namespace OHOS {
30REGISTER_AS(PlayerAbilitySlice)
31
32
33PlayerAbilitySlice::~PlayerAbilitySlice()
34{
35    printf("################ ~PlayerAbilitySlice enter\n");
36
37    /** released in DestoryPlayer(). */
38
39    printf("################ ~PlayerAbilitySlice exit\n");
40}
41
42std::shared_ptr<Player> PlayerAbilitySlice::CreatePlayer()
43{
44    static std::shared_ptr<Player> instance_ = nullptr;
45    if (instance_ == nullptr) {
46        instance_ = std::make_shared<Player>();
47    }
48    return instance_;
49}
50
51void PlayerAbilitySlice::Clear()
52{
53    printf("PlayerAbilitySlice::Clear | enter\n");
54    if (backIconListener_ != nullptr) {
55        delete backIconListener_;
56        backIconListener_ = nullptr;
57    }
58    if (onClickListener_ != nullptr) {
59        delete onClickListener_;
60        onClickListener_ = nullptr;
61    }
62    if (surfaceView_ != nullptr) {
63        delete surfaceView_;
64        surfaceView_ = nullptr;
65    }
66    if (animatorGroup_ != nullptr) {
67        delete animatorGroup_;
68        animatorGroup_ = nullptr;
69    }
70    if (backIcon_ != nullptr) {
71        delete backIcon_;
72        backIcon_ = nullptr;
73    }
74    if (backArea_ != nullptr) {
75        delete backArea_;
76        backArea_ = nullptr;
77    }
78    if (errorTips_ != nullptr) {
79        delete errorTips_;
80        errorTips_ = nullptr;
81    }
82    if (totalTimeLabel_ != nullptr) {
83        delete totalTimeLabel_;
84        totalTimeLabel_ = nullptr;
85    }
86    if (currentTimeLabel_ != nullptr) {
87        delete currentTimeLabel_;
88        currentTimeLabel_ = nullptr;
89    }
90    if (slider_ != nullptr) {
91        delete slider_;
92        slider_ = nullptr;
93    }
94    if (toggleButton_ != nullptr) {
95        delete toggleButton_;
96        toggleButton_ = nullptr;
97    }
98    if (toggleButtonArea_ != nullptr) {
99        delete toggleButtonArea_;
100        toggleButtonArea_ = nullptr;
101    }
102    if (rootView_ != nullptr) {
103        RootView::DestroyWindowRootView(rootView_);
104        rootView_ = nullptr;
105    }
106    printf("PlayerAbilitySlice::Clear() | end\n");
107}
108
109void PlayerAbilitySlice::ShowErrorTips()
110{
111    errorTips_ = new UILabel();
112    errorTips_->SetPosition(ROOT_VIEW_POSITION_X, ROOT_VIEW_POSITION_Y, ROOT_VIEW_WIDTH, ROOT_VIEW_HEIGHT);
113    errorTips_->SetAlign(UITextLanguageAlignment::TEXT_ALIGNMENT_CENTER,
114        UITextLanguageAlignment::TEXT_ALIGNMENT_CENTER);
115    errorTips_->SetFont(FONT_NAME, GALLERY_FONT_SIZE);
116    errorTips_->SetText("视频播放错误");
117
118    rootView_->Add(backArea_);
119    rootView_->Add(errorTips_);
120    rootView_->Add(backIcon_);
121    SetUIContent(rootView_);
122}
123
124void PlayerAbilitySlice::SetUpRootView()
125{
126    if (rootView_ != nullptr) {
127        return;
128    }
129    rootView_ = RootView::GetWindowRootView();
130    rootView_->SetPosition(ROOT_VIEW_POSITION_X, ROOT_VIEW_POSITION_Y);
131    rootView_->Resize(ROOT_VIEW_WIDTH, ROOT_VIEW_HEIGHT);
132    rootView_->SetStyle(STYLE_BACKGROUND_COLOR, Color::Black().full);
133}
134
135void PlayerAbilitySlice::SetUpBackArea(const char* pathHeader)
136{
137    auto onClick = [this] (UIView &view, const Event &event) -> bool {
138        printf("############  PlayerAbilitySlice terminate AS enter   #############\n");
139        Terminate();
140        printf("############  PlayerAbilitySlice terminate AS exit   #############\n");
141        return true;
142    };
143    backIcon_ = new UIImageView();
144    backIcon_->SetPosition(BACK_ICON_POSITION_X, BACK_ICON_POSITION_Y);
145
146    if (sprintf_s(backIconAbsolutePath, MAX_PATH_LENGTH, "%s%s", pathHeader, BACK_ICON_PATH) < 0) {
147        printf("PlayerAbilitySlice::OnStart | backIconAbsolutePath | %s\n", pathHeader);
148        return;
149    }
150    backIcon_->SetSrc(backIconAbsolutePath);
151    backIcon_->SetTouchable(true);
152    backIconListener_ = new EventListener(onClick, nullptr);
153    backIcon_->SetOnClickListener(backIconListener_);
154
155    backArea_ = new UIViewGroup();
156    backArea_->SetPosition(0, 0, LABEL_POSITION_X, LABEL_HEIGHT);
157    backArea_->SetStyle(STYLE_BACKGROUND_OPA, 0);
158    backArea_->SetTouchable(true);
159    backArea_->SetOnClickListener(backIconListener_);
160
161    rootView_->Add(backArea_);
162    rootView_->Add(backIcon_);
163}
164
165void PlayerAbilitySlice::SetUpVideoPlayer(const Want &want)
166{
167    if (videoPlayer_ == nullptr) {
168        videoPlayer_ = new PlayerAdapter();
169    }
170    videoPlayer_->sourceType = 1;
171
172    uint16_t videoPathLen = strlen(VIDEO_SOURCE_DIRECTORY) + strlen(reinterpret_cast<char*>(want.data)) + 1;
173    int8_t ret = sprintf_s(videoPlayer_->filePath, videoPathLen + 1, "%s/%s", VIDEO_SOURCE_DIRECTORY,
174        reinterpret_cast<char*>(want.data));
175    if (ret < 0) {
176        printf("PlayerAbilitySlice::OnStart | videoPlayer_->filePath | %s\n", reinterpret_cast<char*>(want.data));
177        return;
178    }
179    ret = sprintf_s(&videoPlayer_->filePath[videoPathLen - strlen(AVAILABEL_SOURCE_TYPE)],
180                    strlen(AVAILABEL_SOURCE_TYPE) + 1, "%s", AVAILABEL_SOURCE_TYPE);
181    if (ret < 0) {
182        printf("PlayerAbilitySlice::OnStart | videoPlayer_->filePath \n");
183        return;
184    }
185    printf("------########### mp4 file path | %s\n", videoPlayer_->filePath);
186
187    videoPlayer_->adapter = PlayerAbilitySlice::CreatePlayer();
188    std::string uri(videoPlayer_->filePath);
189    std::map<std::string, std::string> header;
190    Source source(uri, header);
191    videoPlayer_->adapter->SetSource(source);
192}
193
194bool PlayerAbilitySlice::SetUpSurfaceView()
195{
196    if (surfaceView_ != nullptr) {
197        return true;
198    }
199    int32_t width = 0;
200    int32_t height = 0;
201    videoPlayer_->adapter->GetVideoWidth(width);
202    printf("[%s,%d] width:%d\n", __func__, __LINE__, width);
203    videoPlayer_->adapter->GetVideoHeight(height);
204    printf("[%s,%d] height:%d\n", __func__, __LINE__, height);
205
206    if (width <= 0 || height <= 0) {
207        videoPlayer_->adapter->Release();
208        delete videoPlayer_;
209        videoPlayer_ = nullptr;
210        printf("******** width <= 0 || height <= 0 | return \n");
211        ShowErrorTips();
212        return false;
213    }
214    float ratio_x = static_cast<float>(width) / ROOT_VIEW_WIDTH;
215    float ratio_y = static_cast<float>(height) / ROOT_VIEW_HEIGHT;
216    uint16_t surfaceViewWidth;
217    uint16_t surfaceViewHeight;
218    uint16_t surfaceViewPositionX = 0;
219    uint16_t surfaceViewPositionY = 0;
220    if (ratio_x > ratio_y) {
221        surfaceViewWidth = ROOT_VIEW_WIDTH;
222        surfaceViewHeight = height / ratio_x;
223        surfaceViewPositionY = (ROOT_VIEW_HEIGHT - surfaceViewHeight) / 2; // 2: half
224    } else {
225        surfaceViewWidth = width / ratio_y;
226        surfaceViewHeight = ROOT_VIEW_HEIGHT;
227        surfaceViewPositionX = (ROOT_VIEW_WIDTH - surfaceViewWidth) / 2; // 2: half
228    }
229
230    surfaceView_ = new UISurfaceView();
231    surfaceView_->SetPosition(surfaceViewPositionX, surfaceViewPositionY);
232    surfaceView_->SetWidth(surfaceViewWidth - 1);
233    surfaceView_->SetHeight(surfaceViewHeight);
234    videoPlayer_->adapter->SetVideoSurface(surfaceView_->GetSurface());
235
236    rootView_->Add(surfaceView_);
237
238    return true;
239}
240
241void PlayerAbilitySlice::SetUpProgress(int64_t duration)
242{
243    slider_ = new UISlider();
244    slider_->SetPosition(SLIDER_X, SLIDER_Y, SLIDER_WIDTH, STATUS_BAR_GROUP_HEIGHT);
245    slider_->SetValidHeight(SLIDER_HEIGHT);
246    slider_->SetValidWidth(SLIDER_WIDTH - KNOB_WIDTH);
247    slider_->SetRange(SLIDER_WIDTH, 0);
248    slider_->SetValue(0);
249    slider_->SetKnobWidth(KNOB_WIDTH);
250    slider_->SetSliderRadius(SLIDER_HEIGHT, SLIDER_HEIGHT);
251    slider_->SetKnobRadius(KNOB_WIDTH / 2); // 2: half
252    slider_->SetKnobStyle(STYLE_BACKGROUND_COLOR, Color::White().full);
253    slider_->SetBackgroundStyle(STYLE_BACKGROUND_COLOR, 0x1A888888);
254    slider_->SetBackgroundStyle(STYLE_BACKGROUND_OPA, 90); // 90: opacity is 90
255    slider_->SetDirection(UISlider::Direction::DIR_LEFT_TO_RIGHT);
256    slider_->SetTouchable(false);
257    animatorGroup_->Add(slider_);
258
259    animator_ = new SliderAnimator(videoPlayer_, slider_, currentTimeLabel_, duration, surfaceView_);
260}
261
262void PlayerAbilitySlice::SetUpAnimatorGroup(const char* pathHeader)
263{
264    int64_t duration = 0;
265    videoPlayer_->adapter->GetDuration(duration);
266    printf("[%s,%d] GetDuration:%lld\n", __func__, __LINE__, duration);
267
268    animatorGroup_ = new UIViewGroup();
269    animatorGroup_->SetPosition(0, ROOT_VIEW_HEIGHT - STATUS_BAR_GROUP_HEIGHT,
270                                ROOT_VIEW_WIDTH, STATUS_BAR_GROUP_HEIGHT);
271    animatorGroup_->SetStyle(STYLE_BACKGROUND_OPA, 0);
272
273    totalTimeLabel_ = new UILabel();
274    totalTimeLabel_->SetPosition(TOTAL_TIME_LABEL_X, TOTAL_TIME_LABEL_Y,
275        TOTAL_TIME_LABEL_WIDTH, TOTAL_TIME_LABEL_HEIGHT);
276    totalTimeLabel_->SetAlign(UITextLanguageAlignment::TEXT_ALIGNMENT_LEFT,
277        UITextLanguageAlignment::TEXT_ALIGNMENT_CENTER);
278    totalTimeLabel_->SetFont(FONT_NAME, PLAYER_FONT_SIZE);
279    int64_t second = duration / 1000; // 1000: 1s = 1000ms
280    char timer[6]; // 6: length of time label
281    if (sprintf_s(timer, sizeof(timer), "%02lld:%02lld", second / 60, second % 60) < 0) { // 60: 1minute = 60s
282        return;
283    }
284
285    totalTimeLabel_->SetText(timer);
286    totalTimeLabel_->SetTextColor(Color::White());
287    animatorGroup_->Add(totalTimeLabel_);
288
289    currentTimeLabel_ = new UILabel();
290    currentTimeLabel_->SetPosition(CURRENT_TIME_LABEL_X, CURRENT_TIME_LABEL_Y,
291        CURRENT_TIME_LABEL_WIDTH, CURRENT_TIME_LABEL_HEIGHT);
292    currentTimeLabel_->SetStyle(STYLE_BACKGROUND_COLOR, Color::Red().full);
293    currentTimeLabel_->SetFont(FONT_NAME, PLAYER_FONT_SIZE);
294    currentTimeLabel_->SetText("00:00");
295    currentTimeLabel_->SetTextColor(Color::White());
296    currentTimeLabel_->SetAlign(UITextLanguageAlignment::TEXT_ALIGNMENT_LEFT,
297        UITextLanguageAlignment::TEXT_ALIGNMENT_CENTER);
298    animatorGroup_->Add(currentTimeLabel_);
299
300    SetUpProgress(duration);
301
302    SetUpToggleButton(pathHeader);
303
304    rootView_->Add(animatorGroup_);
305}
306
307void PlayerAbilitySlice::SetUpToggleButton(const char* pathHeader)
308{
309    toggleButton_ = new UIToggleButton();
310    toggleButton_->SetTouchable(false);
311    toggleButton_->SetPosition(TOGGLE_BUTTON_OFFSET_X, TOGGLE_BUTTON_OFFSET_Y,
312        TOGGLE_BUTTON_WIDTH, TOGGLE_BUTTON_HEIGHT);
313    toggleButton_->SetState(true);
314
315    if (sprintf_s(videoPlayAbsolutePath, MAX_PATH_LENGTH, "%s%s", pathHeader, VIDEO_PALY_PATH) < 0) {
316        printf("PlayerAbilitySlice::OnStart | videoPlayAbsolutePath\n");
317        return;
318    }
319
320    if (sprintf_s(videoPauseAbsolutePath, MAX_PATH_LENGTH, "%s%s", pathHeader, VIDEO_PAUSE_PATH) < 0) {
321        printf("PlayerAbilitySlice::OnStart | videoPauseAbsolutePath\n");
322        return;
323    }
324    toggleButton_->SetImages(videoPauseAbsolutePath, videoPlayAbsolutePath);
325    onClickListener_ = new ToggleBtnListener(toggleButton_, videoPlayer_, animator_, surfaceView_);
326
327    toggleButtonArea_ = new UIViewGroup();
328    toggleButtonArea_->SetPosition(0, 0, TOGGLE_BUTTON_OFFSET_X + TOGGLE_BUTTON_WIDTH, STATUS_BAR_GROUP_HEIGHT);
329    toggleButtonArea_->SetTouchable(true);
330    toggleButtonArea_->SetOnClickListener(onClickListener_);
331    toggleButtonArea_->Add(toggleButton_);
332
333    animatorGroup_->Add(toggleButtonArea_);
334}
335
336void PlayerAbilitySlice::OnStart(const Want &want)
337{
338    printf("@@@@@ PlayerAbilitySlice::OnStart\n");
339    AbilitySlice::OnStart(want);
340
341    SetUpRootView();
342    const char* pathHeader = GetSrcPath();
343    SetUpVideoPlayer(want);
344
345    videoPlayer_->adapter->Prepare();
346
347    if (!SetUpSurfaceView()) {
348        return;
349    }
350    SetUpBackArea(pathHeader);
351    SetUpAnimatorGroup(pathHeader);
352
353    SetUIContent(rootView_);
354
355    videoPlayer_->adapter->Play();
356    animator_->SetToggleButton(toggleButton_);
357    animator_->SetToggleBtnListener(onClickListener_);
358    animator_->Start();
359
360    printf("## @@@@@ PlayerAbilitySlice::OnStart | end \n");
361}
362
363void PlayerAbilitySlice::OnInactive()
364{
365    printf("PlayerAbilitySlice::OnInactive\n");
366    AbilitySlice::OnInactive();
367}
368
369void PlayerAbilitySlice::OnActive(const Want &want)
370{
371    printf("PlayerAbilitySlice::OnActive\n");
372    AbilitySlice::OnActive(want);
373}
374
375void PlayerAbilitySlice::OnBackground()
376{
377    printf("PlayerAbilitySlice::OnBackground\n");
378    AbilitySlice::OnBackground();
379}
380
381void PlayerAbilitySlice::OnStop()
382{
383    if (animator_ != nullptr) {
384        animator_->Stop();
385        delete animator_;
386        animator_ = nullptr;
387    }
388
389    if (videoPlayer_ != nullptr && videoPlayer_->adapter.get() != nullptr) {
390        videoPlayer_->adapter->Stop();
391        videoPlayer_->adapter->Reset();
392        delete videoPlayer_;
393        videoPlayer_ = nullptr;
394    }
395    Clear();
396    printf("PlayerAbilitySlice::OnStop\n");
397    AbilitySlice::OnStop();
398}
399
400void SliderAnimator::Callback(UIView* view)
401{
402    if (needRefreshPlayer_) {
403        videoPlayer_->adapter->Stop();
404        videoPlayer_->adapter->Reset();
405
406        videoPlayer_->adapter = PlayerAbilitySlice::CreatePlayer();
407        std::string uri(videoPlayer_->filePath);
408        std::map<std::string, std::string> header;
409        Source source(uri, header);
410        videoPlayer_->adapter->SetSource(source);
411        videoPlayer_->adapter->Prepare();
412        videoPlayer_->adapter->SetVideoSurface(surfaceView_->GetSurface());
413        videoPlayer_->adapter->Play();
414        needRefreshPlayer_ = false;
415    }
416
417    int64_t currentTime = 0;
418    videoPlayer_->adapter->GetCurrentTime(currentTime);
419    int64_t currentSecond = currentTime / 1000; // 1000: 1s = 1000ms
420
421    char time[6]; // 6: length of time label
422    sprintf_s(time, sizeof(time), "%02lld:%02lld", currentSecond / 60, currentSecond % 60); // 60: 1minute = 60s
423    timeLabel_->SetText(time);
424    timeLabel_->Invalidate();
425
426    int64_t curPosition = currentTime * slider_->GetRangeMax() / duration_;
427    slider_->SetValue(curPosition);
428    slider_->Invalidate();
429
430    if (currentTime >= duration_) {
431        listener_->SetCompleteFlag(true);
432        toggleButton_->SetState(false);
433        needRefreshPlayer_ = true;
434        Stop();
435    }
436}
437
438bool ToggleBtnListener::OnClick(UIView &view, const ClickEvent& event)
439{
440    button_->OnClickEvent(event);
441    if (completeFlag_) {
442        animator_->Start();
443        button_->Invalidate();
444        completeFlag_ = false;
445        return true;
446    }
447
448    if (button_->GetState()) {
449        videoPlayer_->adapter->Play();
450        animator_->Resume();
451        printf("ToggleBtnListener::OnClick | play\n");
452    } else {
453        videoPlayer_->adapter->Pause();
454        animator_->Pause();
455        printf("ToggleBtnListener::OnClick | pause\n");
456    }
457    button_->Invalidate();
458    return true;
459}
460}
461