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 
25 using OHOS::Media::Player;
26 using OHOS::Media::Source;
27 using namespace OHOS::Media;
28 
29 namespace OHOS {
30 REGISTER_AS(PlayerAbilitySlice)
31 
32 
~PlayerAbilitySlice()33 PlayerAbilitySlice::~PlayerAbilitySlice()
34 {
35     printf("################ ~PlayerAbilitySlice enter\n");
36 
37     /** released in DestoryPlayer(). */
38 
39     printf("################ ~PlayerAbilitySlice exit\n");
40 }
41 
CreatePlayer()42 std::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 
Clear()51 void 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 
ShowErrorTips()109 void 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 
SetUpRootView()124 void 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 
SetUpBackArea(const char* pathHeader)135 void 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 
SetUpVideoPlayer(const Want &want)165 void 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 
SetUpSurfaceView()194 bool 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 
SetUpProgress(int64_t duration)241 void 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 
SetUpAnimatorGroup(const char* pathHeader)262 void 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 
SetUpToggleButton(const char* pathHeader)307 void 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 
OnStart(const Want &want)336 void 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 
OnInactive()363 void PlayerAbilitySlice::OnInactive()
364 {
365     printf("PlayerAbilitySlice::OnInactive\n");
366     AbilitySlice::OnInactive();
367 }
368 
OnActive(const Want &want)369 void PlayerAbilitySlice::OnActive(const Want &want)
370 {
371     printf("PlayerAbilitySlice::OnActive\n");
372     AbilitySlice::OnActive(want);
373 }
374 
OnBackground()375 void PlayerAbilitySlice::OnBackground()
376 {
377     printf("PlayerAbilitySlice::OnBackground\n");
378     AbilitySlice::OnBackground();
379 }
380 
OnStop()381 void 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 
Callback(UIView* view)400 void 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 
OnClick(UIView &view, const ClickEvent& event)438 bool 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