TizenRefApp-8516 [Gallery] Implement VideoPlayerPage video functionality 63/129663/4
authorIgor Nazarov <i.nazarov@samsung.com>
Tue, 16 May 2017 18:26:00 +0000 (21:26 +0300)
committerIgor Nazarov <i.nazarov@samsung.com>
Thu, 18 May 2017 10:38:19 +0000 (13:38 +0300)
- Implemented VideoPlayerPage with video playback functionality (no sound
  control);
- Added MIME parsing to MediaItem;
- VideoPlayerPage integrated to view operation;
- src/helpers.h ranamed to src/internal.h;
- Other minir changes and fixes.

Change-Id: I8bc057d6a38cf89ca82a1c100c865af3b855ba7e

27 files changed:
inc/presenters/Instance.h
inc/presenters/Presenter.h
inc/presenters/VideoPlayerPage.h [new file with mode: 0644]
inc/presenters/types.h
src/common.h
src/helpers.h [deleted file]
src/helpers.hpp [deleted file]
src/internal.h [new file with mode: 0644]
src/internal.hpp [new file with mode: 0644]
src/model/MediaItem.cpp
src/model/common.h
src/model/helpers.cpp [deleted file]
src/model/helpers.h [deleted file]
src/model/helpers.hpp [deleted file]
src/model/internal.cpp [new file with mode: 0644]
src/model/internal.h [new file with mode: 0644]
src/model/internal.hpp [new file with mode: 0644]
src/presenters/AlertDialog.cpp
src/presenters/Instance.cpp
src/presenters/MoreOptionsPresenter.cpp
src/presenters/Presenter.cpp
src/presenters/VideoPlayerPage.cpp [new file with mode: 0644]
src/presenters/ViewerPage.cpp
src/presenters/common.h
src/presenters/internal.cpp [new file with mode: 0644]
src/presenters/internal.h [new file with mode: 0644]
tizen-manifest.xml

index 8c3267160dd3769a9cf46c8e7092af4cd9fb4747..a9c949acfebe3c48f9816061935451862f051a56 100644 (file)
@@ -60,9 +60,12 @@ namespace gallery {
                ucl::Result handleGroupMode(const std::string &operation,
                                app_control_h appControl);
 
+               ucl::Result ensureGalleryModel();
+
                void createNoContentPage();
                void createThumbnailPage();
-               void createViewerPage(std::string filePath);
+               void createViewerPage(const MediaItemSRef &media);
+               void createVideoPlayerPage(const MediaItemSRef &media);
 
                void onAlbumChanged();
                void onPageExitRequest(Page &page);
index 3400cff613c2a6974e1794768821f12259849dcd..2366f5b1a22c049150319208689a497930ec7f28 100644 (file)
@@ -19,7 +19,7 @@
 
 #include <unordered_set>
 
-#include "ucl/gui/ElmWidget.h"
+#include "ucl/gui/Window.h"
 
 #include "types.h"
 
@@ -45,6 +45,8 @@ namespace gallery {
 
                ucl::Result prepare(ucl::ElmWidget &widget);
 
+               ucl::Window &getWindow();
+
                void addDeactivatorSource(ucl::Widget &source);
                void addDeactivatorException(void *deactivator);
 
@@ -76,7 +78,7 @@ namespace gallery {
        private:
                std::unordered_set<void *> m_deactivatorExceptions;
                std::unordered_set<void *> m_deactivators;
-               ucl::WidgetWRef m_topWidget;
+               ucl::WindowSRef m_window;
                bool m_isPrepared;
        };
 }
diff --git a/inc/presenters/VideoPlayerPage.h b/inc/presenters/VideoPlayerPage.h
new file mode 100644 (file)
index 0000000..97ea5c7
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2017 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __GALLERY_PRESENTERS_VIDEO_PLAYER_PAGE_H__
+#define __GALLERY_PRESENTERS_VIDEO_PLAYER_PAGE_H__
+
+#include <player.h>
+
+#include "ucl/gui/Layout.h"
+
+#include "Page.h"
+
+namespace gallery {
+
+       class VideoPlayerPage final : public Page {
+       public:
+               class Builder {
+               public:
+                       Builder();
+                       ~Builder();
+                       Builder &setNaviframe(const ucl::NaviframeSRef &navi);
+                       Builder &setMedia(const MediaItemSRef &media);
+                       VideoPlayerPageWRef build(ExitRequestHandler onExitRequest) const;
+               private:
+                       ucl::NaviframeSRef m_navi;
+                       MediaItemSRef m_media;
+               };
+
+       private:
+               friend class ucl::RefCountObj<VideoPlayerPage>;
+               VideoPlayerPage(ucl::RefCountObjBase &rc,
+                               const ucl::NaviframeSRef &navi,
+                               ExitRequestHandler onExitRequest,
+                               const MediaItemSRef &media);
+               virtual ~VideoPlayerPage();
+
+               ucl::Result prepare();
+
+               void createImage();
+               ucl::Result preparePlayer();
+               ucl::Result seekToStart();
+
+               void createControls();
+               void createButton(ucl::ElmStyle style, ucl::EdjePart part,
+                               const ucl::WidgetEventHandler &handler);
+
+               bool resetTimer(Ecore_Timer *&timer, double timeout, Ecore_Task_Cb func);
+               void stopTimer(Ecore_Timer *&timer);
+
+               bool resetAutoStartTimer();
+               bool resetControlsHideTimer();
+               bool resetTickTimer();
+
+               void showControls();
+               void hideControls();
+
+               bool updatePlayTimeText();
+               void updatePlayTimeText(int timeMs);
+
+               player_state_e getPlayerState() const;
+               void startPlayback();
+               void pausePlayback();
+
+               void setScreenOlwaysOn(bool isAlwaysOn);
+
+               void onPlaybackComplete();
+               void onPlaybackInterrupted(player_interrupted_code_e code);
+               void onSeekComplete();
+
+               Eina_Bool onAutoStartTimer();
+               Eina_Bool onControlsHideTimer();
+               Eina_Bool onTickTimer();
+
+               void onVolumeOnBtnClick(ucl::Widget &sender, void *eventInfo);
+               void onVolumeMuteBtnClick(ucl::Widget &sender, void *eventInfo);
+               void onPlayBtnClick(ucl::Widget &sender, void *eventInfo);
+               void onPauseBtnClick(ucl::Widget &sender, void *eventInfo);
+               void onTap(int x, int y);
+               Eina_Bool onRotary(Eext_Rotary_Event_Info *info);
+
+               void onInstancePaused(ucl::Widget &sender, void *eventInfo);
+               void onInstanceResumed(ucl::Widget &sender, void *eventInfo);
+
+       private:
+               enum class State {
+                       PAUSED,
+                       PLAYING
+               };
+
+       private:
+               const MediaItemSRef m_media;
+               ucl::LayoutSRef m_content;
+               ucl::WidgetSRef m_image;
+               TouchParserSRef m_touchParser;
+               player_h m_player;
+               int m_videoDuration;
+               Ecore_Timer *m_autoStartTimer;
+               Ecore_Timer *m_controlsHideTimer;
+               Ecore_Timer *m_tickTimer;
+               State m_state;
+               bool m_isControlsVisible;
+               bool m_needAutoStart;
+               bool m_isPlaybackCompleted;
+       };
+}
+
+#endif // __GALLERY_PRESENTERS_VIDEO_PLAYER_PAGE_H__
index b7fdb1aeafadb876f8dfdd86863fb73b0ae7c8d6..2cc1e316869a210a16b1253d1583a73215b9edca 100644 (file)
@@ -52,6 +52,7 @@ namespace gallery {
        UCL_DECLARE_REF_ALIASES(ThumbnailPage);
        UCL_DECLARE_REF_ALIASES(PreviewPage);
        UCL_DECLARE_REF_ALIASES(ViewerPage);
+       UCL_DECLARE_REF_ALIASES(VideoPlayerPage);
 }
 
 #endif // __GALLERY_PRESENTERS_TYPES_H__
index 15485db3c4f6f40d1bf00d660549697450019161..696be603302d37444e700deafe636aafb81a12c8 100644 (file)
@@ -26,6 +26,6 @@
 #undef UCL_LOG_TAG
 #define UCL_LOG_TAG GALLERY_LOG_TAG
 
-#include "helpers.h"
+#include "internal.h"
 
 #endif // __GALLERY_COMMON_H__
diff --git a/src/helpers.h b/src/helpers.h
deleted file mode 100644 (file)
index 8cd1b3a..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2017 Samsung Electronics Co., Ltd
- *
- * Licensed under the Flora License, Version 1.1 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://floralicense.org/license/
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __GALLERY_HELPERS_H__
-#define __GALLERY_HELPERS_H__
-
-#include "types.h"
-
-namespace gallery { namespace util {
-
-       template <class GETTER, class V, class ...ARGS>
-       ucl::Result get(GETTER &&getter, V &result, ARGS &&...args);
-
-       template <class GETTER, class V, class ...ARGS>
-       ucl::Result getNz(GETTER &&getter, V &result, ARGS &&...args);
-}}
-
-#include "helpers.hpp"
-
-#endif // __GALLERY_HELPERS_H__
diff --git a/src/helpers.hpp b/src/helpers.hpp
deleted file mode 100644 (file)
index 6acb919..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright 2017 Samsung Electronics Co., Ltd
- *
- * Licensed under the Flora License, Version 1.1 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://floralicense.org/license/
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "ucl/util/logging.h"
-
-namespace gallery { namespace util { namespace himpl {
-
-       template <class GETTER, class ...ARGS>
-       inline ucl::Result get(GETTER &&getter, bool optional,
-                       std::string &result, ARGS &&...args)
-       {
-               char *value = nullptr;
-               const int ret = getter(std::forward<ARGS>(args)..., &value);
-               if ((ret != 0) || (!optional && !value)) {
-                       UCL_ELOG("get() failed: %d", ret);
-                       return ucl::RES_FAIL;
-               }
-
-               if (value) {
-                       result = value;
-                       free(value);
-               } else {
-                       result.clear();
-               }
-
-               return ucl::RES_OK;
-       }
-
-       template <class GETTER, class V, class ...ARGS>
-       inline ucl::Result get(GETTER &&getter, bool optional,
-                       V &result, ARGS &&...args)
-       {
-               V value = {};
-               const int ret = getter(std::forward<ARGS>(args)..., &value);
-               if ((ret != 0) || (!optional && !value)) {
-                       UCL_ELOG("get() failed: %d", ret);
-                       return ucl::RES_FAIL;
-               }
-
-               result = value;
-
-               return ucl::RES_OK;
-       }
-}}}
-
-namespace gallery { namespace util {
-
-       template <class GETTER, class V, class ...ARGS>
-       inline ucl::Result get(GETTER &&getter, V &result, ARGS &&...args)
-       {
-               return himpl::get(std::forward<GETTER>(getter), true,
-                               result, std::forward<ARGS>(args)...);
-       }
-
-       template <class GETTER, class V, class ...ARGS>
-       inline ucl::Result getNz(GETTER &&getter, V &result, ARGS &&...args)
-       {
-               return himpl::get(std::forward<GETTER>(getter), false,
-                               result, std::forward<ARGS>(args)...);
-       }
-}}
diff --git a/src/internal.h b/src/internal.h
new file mode 100644 (file)
index 0000000..504f985
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2017 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __GALLERY_INTERNAL_H__
+#define __GALLERY_INTERNAL_H__
+
+#include "types.h"
+
+namespace gallery { namespace util {
+
+       template <class GETTER, class V, class ...ARGS>
+       ucl::Result get(GETTER &&getter, V &result, ARGS &&...args);
+
+       template <class GETTER, class V, class ...ARGS>
+       ucl::Result getNz(GETTER &&getter, V &result, ARGS &&...args);
+
+       template <class FUNC, class ...ARGS>
+       ucl::Result call(FUNC &&func, ARGS &&...args);
+}}
+
+#include "internal.hpp"
+
+#endif // __GALLERY_INTERNAL_H__
diff --git a/src/internal.hpp b/src/internal.hpp
new file mode 100644 (file)
index 0000000..343f37c
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2017 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ucl/util/helpers.h"
+#include "ucl/util/logging.h"
+
+namespace gallery { namespace util { namespace himpl {
+
+       template <class GETTER, class ...ARGS>
+       inline ucl::Result get(GETTER &&getter, bool optional,
+                       std::string &result, ARGS &&...args)
+       {
+               char *value = nullptr;
+               const int ret = getter(std::forward<ARGS>(args)..., &value);
+               if ((ret != 0) || (!optional && ucl::isEmpty(value))) {
+                       UCL_ELOG("get() failed: %d", ret);
+                       return ucl::RES_FAIL;
+               }
+
+               if (value) {
+                       result = value;
+                       free(value);
+               } else {
+                       result.clear();
+               }
+
+               return ucl::RES_OK;
+       }
+
+       template <class GETTER, class V, class ...ARGS>
+       inline ucl::Result get(GETTER &&getter, bool optional,
+                       V &result, ARGS &&...args)
+       {
+               V value = {};
+               const int ret = getter(std::forward<ARGS>(args)..., &value);
+               if ((ret != 0) || (!optional && !value)) {
+                       UCL_ELOG("get() failed: %d", ret);
+                       return ucl::RES_FAIL;
+               }
+
+               result = value;
+
+               return ucl::RES_OK;
+       }
+}}}
+
+namespace gallery { namespace util {
+
+       template <class GETTER, class V, class ...ARGS>
+       inline ucl::Result get(GETTER &&getter, V &result, ARGS &&...args)
+       {
+               return himpl::get(std::forward<GETTER>(getter), true,
+                               result, std::forward<ARGS>(args)...);
+       }
+
+       template <class GETTER, class V, class ...ARGS>
+       inline ucl::Result getNz(GETTER &&getter, V &result, ARGS &&...args)
+       {
+               return himpl::get(std::forward<GETTER>(getter), false,
+                               result, std::forward<ARGS>(args)...);
+       }
+
+       template <class FUNC, class ...ARGS>
+       inline ucl::Result call(FUNC &&func, ARGS &&...args)
+       {
+               const int ret = func(std::forward<ARGS>(args)...);
+               if (ret != 0) {
+                       UCL_ELOG("func() failed: %d", ret);
+                       return ucl::RES_FAIL;
+               }
+               return ucl::RES_OK;
+       }
+}}
index b87ba318a8b19b069b1a1f4dc3a22852b469c063..4c42d844534a02fccd313da9e1231e624d1d540b 100644 (file)
 
 #include <Ecore_File.h>
 #include <storage.h>
+#include <mime_type.h>
 
 #include "BaseJob.h"
 
 #include "common.h"
 
+namespace gallery { namespace { namespace impl {
+
+       const std::string MIME_PREFIX_IMAGE {"image/"};
+       const std::string MIME_PREFIX_VIDEO {"video/"};
+
+       MediaType getFileMediaType(const std::string &filePath)
+       {
+               const auto ext = util::extractFileExtension(filePath);
+
+               std::string mime;
+               FAIL_RETURN_VALUE(util::get(mime_type_get_mime_type, mime, ext.c_str()),
+                               MediaType::OTHERS,
+                               "mime_type_get_mime_type() failed!");
+
+               if (util::beginsWith(mime, MIME_PREFIX_IMAGE)) {
+                       return MediaType::IMAGE;
+               }
+               if (util::beginsWith(mime, MIME_PREFIX_VIDEO)) {
+                       return MediaType::VIDEO;
+               }
+
+               return MediaType::OTHERS;
+       }
+}}}
+
 namespace gallery {
 
        using namespace ucl;
@@ -175,7 +201,7 @@ namespace gallery {
        MediaItemSRef MediaItem::newInstance(std::string filePath)
        {
                auto result = makeShared<MediaItem>(FLAGS_SIMPLE_FILE,
-                               MediaType::IMAGE);
+                               impl::getFileMediaType(filePath));
 
                FAIL_RETURN_VALUE(result->prepare(std::move(filePath)), {},
                                "result->prepare() failed!");
index 7581a14041f081e8002e349ae1c499b54d9060ce..c1e6306274f6b15552035e521d1b774be09f78f2 100644 (file)
@@ -17,7 +17,7 @@
 #ifndef __GALLERY_MODEL_COMMON_H__
 #define __GALLERY_MODEL_COMMON_H__
 
-#include "helpers.h"
+#include "internal.h"
 
 #include "../common.h"
 
diff --git a/src/model/helpers.cpp b/src/model/helpers.cpp
deleted file mode 100644 (file)
index 4057ff5..0000000
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright 2017 Samsung Electronics Co., Ltd
- *
- * Licensed under the Flora License, Version 1.1 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://floralicense.org/license/
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "helpers.h"
-
-#include <Ecore_File.h>
-#include <storage.h>
-
-#include "common.h"
-
-namespace gallery { namespace { namespace impl {
-
-       constexpr auto UNIQUE_PATH_RESERVE = 10;
-}}}
-
-namespace gallery {
-
-       using namespace ucl;
-
-       Mutex &getMediaMutex()
-       {
-               static Mutex mutex{true};
-               return mutex;
-       }
-
-       Result getInternalStorageId(int &result)
-       {
-               struct StorageIdRec {
-                       int id;
-                       bool valid;
-               } storageIdRec {0, false};
-
-               const int ret = storage_foreach_device_supported(
-                       [](int storageId, storage_type_e type,
-                                       storage_state_e state, const char *path, void *userData)
-                       {
-                               if ((type != STORAGE_TYPE_INTERNAL) ||
-                                               (state != STORAGE_STATE_MOUNTED)) {
-                                       return true;
-                               }
-                               auto &storageIdRec = *static_cast<StorageIdRec *>(userData);
-                               storageIdRec.id = storageId;
-                               storageIdRec.valid = true;
-                               return false;
-                       },
-                       &storageIdRec);
-               if (ret != 0) {
-                       LOG_RETURN(RES_FAIL,
-                                       "storage_foreach_device_supported() failed: %d", ret);
-               }
-
-               if (!storageIdRec.valid) {
-                       LOG_RETURN(RES_FAIL, "Writable internal storage not found!");
-               }
-
-               result = storageIdRec.id;
-
-               return RES_OK;
-       }
-}
-
-namespace gallery { namespace util {
-
-       std::string extractFileName(const std::string &path)
-       {
-               const auto bsPos = path.rfind('/');
-               if (bsPos == (path.size() - 1)) {
-                       return {};
-               }
-               return path.substr(bsPos + 1);
-       }
-
-       std::string extractExtension(const std::string &name)
-       {
-               const auto dotPos = name.rfind('.');
-               if ((dotPos == std::string::npos) ||
-                               (dotPos == 0) || (dotPos == (name.size() - 1))) {
-                       return {};
-               }
-               return name.substr(dotPos + 1);
-       }
-
-       void splitFilePath(const std::string &path, std::string &directory,
-                       std::string &baseName, std::string &extension)
-       {
-               splitFileName(path, baseName, extension);
-               if (isNotEmpty(baseName)) {
-                       directory = path.substr(0, (path.size() - baseName.size() -
-                                       (isNotEmpty(extension) ? (extension.size() - 1) : 0)));
-               } else {
-                       directory = path;
-               }
-       }
-
-       void splitFileName(const std::string &path,
-                       std::string &baseName, std::string &extension)
-       {
-               baseName = extractFileName(path);
-               if (isNotEmpty(baseName)) {
-                       extension = extractExtension(baseName);
-                       if (isNotEmpty(extension)) {
-                               baseName.resize(baseName.size() - extension.size() - 1);
-                       }
-               } else {
-                       extension.clear();
-               }
-       }
-
-       std::string makeUniqueFilePath(const std::string &srcPath,
-                       const std::string &dstDir)
-       {
-               std::string baseName;
-               std::string extension;
-               splitFileName(srcPath, baseName, extension);
-
-               std::string result;
-               result.reserve(dstDir.size() + baseName.size() +
-                               extension.size() + impl::UNIQUE_PATH_RESERVE);
-
-               result = dstDir;
-               if (isNotEmpty(result) && (result.back() != '/')) {
-                       result += '/';
-               }
-               result += baseName;
-
-               const auto baseSize = result.size();
-
-               for (int counter = 2; ; ++counter) {
-                       if (isNotEmpty(extension)) {
-                               result += '.';
-                               result += extension;
-                       }
-                       if (!ecore_file_exists(result.c_str())) {
-                               break;
-                       }
-                       result.resize(baseSize);
-                       result += " (";
-                       result += std::to_string(counter);
-                       result += ')';
-               }
-
-               return result;
-       }
-}}
diff --git a/src/model/helpers.h b/src/model/helpers.h
deleted file mode 100644 (file)
index 29da4d8..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright 2017 Samsung Electronics Co., Ltd
- *
- * Licensed under the Flora License, Version 1.1 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://floralicense.org/license/
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __GALLERY_MODEL_HELPERS_H__
-#define __GALLERY_MODEL_HELPERS_H__
-
-#include "ucl/util/threading.h"
-
-#include "model/types.h"
-
-namespace gallery {
-
-       MediaType toMediaType(media_content_type_e contentType);
-
-       ucl::Mutex &getMediaMutex();
-
-       ucl::Result getInternalStorageId(int &result);
-}
-
-namespace gallery { namespace util {
-
-       std::string extractFileName(const std::string &path);
-
-       std::string extractFileExtension(const std::string &name);
-
-       void splitFilePath(const std::string &path, std::string &directory,
-                       std::string &baseName, std::string &extension);
-
-       void splitFileName(const std::string &path,
-                       std::string &baseName, std::string &extension);
-
-       std::string makeUniqueFilePath(const std::string &srcPath,
-                       const std::string &dstDir);
-}}
-
-#include "helpers.hpp"
-
-#endif // __GALLERY_MODEL_HELPERS_H__
diff --git a/src/model/helpers.hpp b/src/model/helpers.hpp
deleted file mode 100644 (file)
index be253bf..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright 2017 Samsung Electronics Co., Ltd
- *
- * Licensed under the Flora License, Version 1.1 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://floralicense.org/license/
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-namespace gallery {
-
-       inline MediaType toMediaType(const media_content_type_e contentType)
-       {
-               switch (contentType) {
-               case MEDIA_CONTENT_TYPE_IMAGE: return MediaType::IMAGE;
-               case MEDIA_CONTENT_TYPE_VIDEO: return MediaType::VIDEO;
-               case MEDIA_CONTENT_TYPE_SOUND: return MediaType::SOUND;
-               case MEDIA_CONTENT_TYPE_MUSIC: return MediaType::MUSIC;
-               default:
-                       break;
-               }
-               return MediaType::OTHERS;
-       }
-}
diff --git a/src/model/internal.cpp b/src/model/internal.cpp
new file mode 100644 (file)
index 0000000..de6f9a2
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2017 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal.h"
+
+#include <Ecore_File.h>
+#include <storage.h>
+
+#include "common.h"
+
+namespace gallery { namespace { namespace impl {
+
+       constexpr auto UNIQUE_PATH_RESERVE = 10;
+}}}
+
+namespace gallery {
+
+       using namespace ucl;
+
+       Mutex &getMediaMutex()
+       {
+               static Mutex mutex{true};
+               return mutex;
+       }
+
+       Result getInternalStorageId(int &result)
+       {
+               struct StorageIdRec {
+                       int id;
+                       bool valid;
+               } storageIdRec {0, false};
+
+               const int ret = storage_foreach_device_supported(
+                       [](int storageId, storage_type_e type,
+                                       storage_state_e state, const char *path, void *userData)
+                       {
+                               if ((type != STORAGE_TYPE_INTERNAL) ||
+                                               (state != STORAGE_STATE_MOUNTED)) {
+                                       return true;
+                               }
+                               auto &storageIdRec = *static_cast<StorageIdRec *>(userData);
+                               storageIdRec.id = storageId;
+                               storageIdRec.valid = true;
+                               return false;
+                       },
+                       &storageIdRec);
+               if (ret != 0) {
+                       LOG_RETURN(RES_FAIL,
+                                       "storage_foreach_device_supported() failed: %d", ret);
+               }
+
+               if (!storageIdRec.valid) {
+                       LOG_RETURN(RES_FAIL, "Writable internal storage not found!");
+               }
+
+               result = storageIdRec.id;
+
+               return RES_OK;
+       }
+}
+
+namespace gallery { namespace util {
+
+       std::string extractFileName(const std::string &path)
+       {
+               const auto bsPos = path.rfind('/');
+               if (bsPos == (path.size() - 1)) {
+                       return {};
+               }
+               return path.substr(bsPos + 1);
+       }
+
+       std::string extractFileExtension(const std::string &name)
+       {
+               const auto dotPos = name.rfind('.');
+               if ((dotPos == std::string::npos) ||
+                               (dotPos == 0) || (dotPos == (name.size() - 1))) {
+                       return {};
+               }
+               return name.substr(dotPos + 1);
+       }
+
+       void splitFilePath(const std::string &path, std::string &directory,
+                       std::string &baseName, std::string &extension)
+       {
+               splitFileName(path, baseName, extension);
+               if (isNotEmpty(baseName)) {
+                       directory = path.substr(0, (path.size() - baseName.size() -
+                                       (isNotEmpty(extension) ? (extension.size() - 1) : 0)));
+               } else {
+                       directory = path;
+               }
+       }
+
+       void splitFileName(const std::string &path,
+                       std::string &baseName, std::string &extension)
+       {
+               baseName = extractFileName(path);
+               if (isNotEmpty(baseName)) {
+                       extension = extractFileExtension(baseName);
+                       if (isNotEmpty(extension)) {
+                               baseName.resize(baseName.size() - extension.size() - 1);
+                       }
+               } else {
+                       extension.clear();
+               }
+       }
+
+       std::string makeUniqueFilePath(const std::string &srcPath,
+                       const std::string &dstDir)
+       {
+               std::string baseName;
+               std::string extension;
+               splitFileName(srcPath, baseName, extension);
+
+               std::string result;
+               result.reserve(dstDir.size() + baseName.size() +
+                               extension.size() + impl::UNIQUE_PATH_RESERVE);
+
+               result = dstDir;
+               if (isNotEmpty(result) && (result.back() != '/')) {
+                       result += '/';
+               }
+               result += baseName;
+
+               const auto baseSize = result.size();
+
+               for (int counter = 2; ; ++counter) {
+                       if (isNotEmpty(extension)) {
+                               result += '.';
+                               result += extension;
+                       }
+                       if (!ecore_file_exists(result.c_str())) {
+                               break;
+                       }
+                       result.resize(baseSize);
+                       result += " (";
+                       result += std::to_string(counter);
+                       result += ')';
+               }
+
+               return result;
+       }
+}}
diff --git a/src/model/internal.h b/src/model/internal.h
new file mode 100644 (file)
index 0000000..415a58c
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2017 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __GALLERY_MODEL_INTERNAL_H__
+#define __GALLERY_MODEL_INTERNAL_H__
+
+#include "ucl/util/threading.h"
+
+#include "model/types.h"
+
+namespace gallery {
+
+       MediaType toMediaType(media_content_type_e contentType);
+
+       ucl::Mutex &getMediaMutex();
+
+       ucl::Result getInternalStorageId(int &result);
+}
+
+namespace gallery { namespace util {
+
+       std::string extractFileName(const std::string &path);
+
+       std::string extractFileExtension(const std::string &name);
+
+       void splitFilePath(const std::string &path, std::string &directory,
+                       std::string &baseName, std::string &extension);
+
+       void splitFileName(const std::string &path,
+                       std::string &baseName, std::string &extension);
+
+       std::string makeUniqueFilePath(const std::string &srcPath,
+                       const std::string &dstDir);
+
+       bool beginsWith(const std::string &container, const std::string &str);
+}}
+
+#include "internal.hpp"
+
+#endif // __GALLERY_MODEL_INTERNAL_H__
diff --git a/src/model/internal.hpp b/src/model/internal.hpp
new file mode 100644 (file)
index 0000000..90b8751
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2017 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace gallery {
+
+       inline MediaType toMediaType(const media_content_type_e contentType)
+       {
+               switch (contentType) {
+               case MEDIA_CONTENT_TYPE_IMAGE: return MediaType::IMAGE;
+               case MEDIA_CONTENT_TYPE_VIDEO: return MediaType::VIDEO;
+               case MEDIA_CONTENT_TYPE_SOUND: return MediaType::SOUND;
+               case MEDIA_CONTENT_TYPE_MUSIC: return MediaType::MUSIC;
+               default:
+                       break;
+               }
+               return MediaType::OTHERS;
+       }
+}
+
+namespace gallery { namespace util {
+
+       inline bool beginsWith(const std::string &container, const std::string &str)
+       {
+               return (container.compare(0, str.size(), str) == 0);
+       }
+}}
index fac680f5c0f1c5917cb726e1577fcfc34c0c9400..0a23f4855cb8dce7b8430e71be0cc4bbf3be5c36 100644 (file)
@@ -241,10 +241,9 @@ namespace gallery {
                        eext_object_event_callback_del(*m_popup, EEXT_CALLBACK_BACK,
                                        CALLBACK_A(AlertDialog::onPopupHWBackKey));
 
-                       m_popup.reset();
-
                        deactivateBy(m_popup.get());
                        broadcastActivateBy(this);
+                       m_popup.reset();
                        m_rc->unref();
                }
        }
index 3e8a104f247d2d097d4a09ce004d8768b2114458..f4c7ce91a58c548794273c191b318fdd8b7de671 100644 (file)
@@ -28,6 +28,7 @@
 #include "presenters/NoContentPage.h"
 #include "presenters/ThumbnailPage.h"
 #include "presenters/ViewerPage.h"
+#include "presenters/VideoPlayerPage.h"
 
 #include "resources.h"
 #include "common.h"
@@ -63,11 +64,6 @@ namespace gallery {
        {
                m_context = context;
 
-               m_gallery = Gallery::newInstance();
-               if (!m_gallery) {
-                       LOG_RETURN(RES_FAIL, "Gallery::newInstance() failed!");
-               }
-
                m_win = m_context->getWindow();
 
                FAIL_RETURN(setupTheme(), "setupTheme() failed!");
@@ -86,9 +82,6 @@ namespace gallery {
                m_sysEventProvider.addEventHandler(
                                DELEGATE(Instance::onSysEvent, this));
 
-               m_gallery->getAlbum()->addChangeHandler(WEAK_DELEGATE(
-                               Instance::onAlbumChanged, asWeak(*this)));
-
                return RES_OK;
        }
 
@@ -109,12 +102,16 @@ namespace gallery {
        void Instance::onPause()
        {
                DLOG("PAUSE");
+
+               setInstancePaused(*m_win, true);
        }
 
        void Instance::onResume()
        {
                DLOG("RESUME");
 
+               setInstancePaused(*m_win, false);
+
                if (SCAN_MEDIA_ON_RESUME) {
                        rescanMediaContent();
                }
@@ -206,6 +203,8 @@ namespace gallery {
        Result Instance::handleSingleMode(const std::string &operation,
                                app_control_h appControl)
        {
+               FAIL_RETURN(ensureGalleryModel(), "ensureGalleryModel() failed!");
+
                if (!m_page) {
                        if (isEmpty(m_gallery->getAlbum())) {
                                createNoContentPage();
@@ -231,7 +230,24 @@ namespace gallery {
                        std::string uri;
                        FAIL_RETURN(util::getNz(app_control_get_uri, uri, appControl),
                                "app_control_get_uri() failed!");
-                       createViewerPage(uri);
+
+                       const auto media = MediaItem::newInstance(std::move(uri));
+                       if (!media) {
+                               LOG_RETURN(RES_FAIL, "MediaItem::newInstance() failed!");
+                       }
+
+                       switch (media->getType()) {
+                       case MediaType::IMAGE:
+                               createViewerPage(media);
+                               break;
+                       case MediaType::VIDEO:
+                               createVideoPlayerPage(media);
+                               break;
+                       default:
+                               LOG_RETURN(RES_NOT_SUPPORTED,
+                                               "Media type is not supported: %d;", media->getType());
+                       }
+
                } else {
                        WLOG("Operation not supported for current mode!");
                        return RES_NOT_SUPPORTED;
@@ -242,6 +258,23 @@ namespace gallery {
                return RES_OK;
        }
 
+       Result Instance::ensureGalleryModel()
+       {
+               if (m_gallery) {
+                       return RES_FALSE;
+               }
+
+               m_gallery = Gallery::newInstance();
+               if (!m_gallery) {
+                       LOG_RETURN(RES_FAIL, "Gallery::newInstance() failed!");
+               }
+
+               m_gallery->getAlbum()->addChangeHandler(WEAK_DELEGATE(
+                               Instance::onAlbumChanged, asWeak(*this)));
+
+               return RES_OK;
+       }
+
        void Instance::createNoContentPage()
        {
                DLOG("Creating NoContentPage.");
@@ -252,20 +285,30 @@ namespace gallery {
        void Instance::createThumbnailPage()
        {
                DLOG("Creating ThumbnailPage.");
+               FAIL_RETURN_VOID(ensureGalleryModel(), "ensureGalleryModel() failed!");
+
                m_page = ThumbnailPage::Builder().setNaviframe(m_navi).
                                setAlbum(m_gallery->getAlbum()).
                                build(DELEGATE(Instance::onPageExitRequest, this));
        }
 
-       void Instance::createViewerPage(std::string filePath)
+       void Instance::createViewerPage(const MediaItemSRef &media)
        {
                DLOG("Creating ViewerPage.");
                m_page = ViewerPage::Builder().setNaviframe(m_navi).
-                               setMedia(MediaItem::newInstance(std::move(filePath))).
+                               setMedia(media).
                                setExitOnZoomOut(false).
                                build(DELEGATE(Instance::onPageExitRequest, this));
        }
 
+       void Instance::createVideoPlayerPage(const MediaItemSRef &media)
+       {
+               DLOG("Creating VideoPlayerPage.");
+               m_page = VideoPlayerPage::Builder().setNaviframe(m_navi).
+                               setMedia(media).
+                               build(DELEGATE(Instance::onPageExitRequest, this));
+       }
+
        void Instance::onAlbumChanged()
        {
                if (isEmpty(m_gallery->getAlbum())) {
index fa2d0597b0047accc3222248cc28c5d625b2461e..ad0f74d57ababac733cd895ea7ca008b4933168e 100644 (file)
@@ -143,6 +143,8 @@ namespace gallery {
                m_widget->addEventHandler(impl::MORE_ITEM_SELECTED, WEAK_DELEGATE(
                                MoreOptionsPresenter::onItemSelected, asWeak(*this)));
 
+               deactivateBy(m_widget.get());
+
                return RES_OK;
        }
 
index e461cda038b269f3f59486225ac8b06fe4dcac1f..dd29ddb8c073b505c2a1b4fd6280474ce0541abd 100644 (file)
@@ -42,18 +42,23 @@ namespace gallery {
 
        Result Presenter::prepare(ElmWidget &widget)
        {
-               m_topWidget = asWeak(asWidget(widget.getTopWidget()));
-               if (!m_topWidget) {
-                       LOG_RETURN(RES_FAIL, "m_topWidget is NULL!");
+               m_window = asShared(widget.getWindow());
+               if (!m_window) {
+                       LOG_RETURN(RES_FAIL, "m_window is NULL!");
                }
 
-               addDeactivatorSource(*m_topWidget);
+               addDeactivatorSource(*m_window);
 
                m_isPrepared = true;
 
                return RES_OK;
        }
 
+       Window &Presenter::getWindow()
+       {
+               return *m_window;
+       }
+
        void Presenter::addDeactivatorSource(Widget &source)
        {
                source.addEventHandler(impl::ACTIVATE_BY,
@@ -99,11 +104,7 @@ namespace gallery {
        void Presenter::broadcastDeactivator(const SmartEvent event,
                        void *const deactivator)
        {
-               if (m_topWidget) {
-                       sendDeactivatorInfo(*m_topWidget, event, {deactivator, true});
-               } else {
-                       ELOG("m_topWidget is NULL!");
-               }
+               sendDeactivatorInfo(*m_window, event, {deactivator, true});
        }
 
        void Presenter::sendDeactivatorInfo(Widget &sender,
diff --git a/src/presenters/VideoPlayerPage.cpp b/src/presenters/VideoPlayerPage.cpp
new file mode 100644 (file)
index 0000000..b286ec9
--- /dev/null
@@ -0,0 +1,589 @@
+/*
+ * Copyright 2017 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "presenters/VideoPlayerPage.h"
+
+#include <efl_util.h>
+
+#include "model/MediaItem.h"
+
+#include "view/TouchParser.h"
+
+#include "resources.h"
+#include "common.h"
+
+namespace gallery { namespace { namespace impl {
+
+       using namespace ucl;
+
+       constexpr auto AUTO_START_TIMEOUT_SEC = 0.3;
+       constexpr auto CONTROLS_PLAYBACK_HIDE_TIMEOUT_SEC = 3.0;
+       constexpr auto CONTROLS_PAUSE_HIDE_TIMEOUT_SEC = 6.0;
+
+       constexpr auto TICK_TIMER_INTERVAL_SEC = 0.1;
+
+       constexpr auto TIME_SEC_MS = 1000;
+       constexpr auto TIME_MIN_SEC = 60;
+       constexpr auto TIME_HOUR_MIN = 60;
+
+       const TString TIME_SHORT_FORMAT {"%02d:%02d / %02d:%02d"};
+       const TString TIME_LONG_FORMAT {"%02d:%02d:%02d / %02d:%02d:%02d"};
+
+       constexpr LayoutTheme LAYOUT_VIDEO_PLAYER
+                       {"layout", "gallery", "video_player"};
+
+       constexpr ElmStyle STYLE_VOLUME_ON_BTN {"gallery_video_volume_on"};
+       constexpr ElmStyle STYLE_VOLUME_MUTE_BTN {"gallery_video_volume_mute"};
+       constexpr ElmStyle STYLE_PLAY_BTN {"gallery_video_play"};
+       constexpr ElmStyle STYLE_PAUSE_BTN {"gallery_video_pause"};
+
+       constexpr EdjePart PART_VOLUME_ON_BTN {"gallery.swallow.volume_on"};
+       constexpr EdjePart PART_VOLUME_MUTE_BTN {"gallery.swallow.volume_mute"};
+       constexpr EdjePart PART_PLAY_BTN {"gallery.swallow.play"};
+       constexpr EdjePart PART_PAUSE_BTN {"gallery.swallow.pause"};
+
+       constexpr EdjeSignal SHOW_VOLUME_ON_BTN {"show,volume_on,btn"};
+       constexpr EdjeSignal SHOW_VOLUME_MUTE_BTN {"show,volume_mute,btn"};
+       constexpr EdjeSignal HIDE_VOLUME_BTN {"hide,volume,btn"};
+
+       constexpr EdjeSignal SHOW_PLAY_BTN {"show,play,btn"};
+       constexpr EdjeSignal SHOW_PAUSE_BTN {"show,pause,btn"};
+       constexpr EdjeSignal HIDE_PLAY_PAUSE_BTN {"hide,play_pause,btn"};
+
+       constexpr EdjeSignal SHOW_TEXT {"show,text"};
+       constexpr EdjeSignal HIDE_TEXT {"hide,text"};
+
+       void timeMsToHMS(int timeMs, int &h, int &m, int &s)
+       {
+               int t = (timeMs / TIME_SEC_MS);
+               s = (t % TIME_MIN_SEC);
+               t /= TIME_MIN_SEC;
+               m = (t % TIME_HOUR_MIN);
+               h = (t / TIME_HOUR_MIN);
+       }
+}}}
+
+namespace gallery {
+
+       using namespace ucl;
+
+       // VideoPlayerPage::Builder //
+
+       VideoPlayerPage::Builder::Builder()
+       {
+       }
+
+       VideoPlayerPage::Builder::~Builder()
+       {
+       }
+
+       VideoPlayerPage::Builder &VideoPlayerPage::Builder::setNaviframe(
+                       const NaviframeSRef &navi)
+       {
+               m_navi = navi;
+               return *this;
+       }
+
+       VideoPlayerPage::Builder &VideoPlayerPage::Builder::setMedia(
+                       const MediaItemSRef &media)
+       {
+               m_media = media;
+               return *this;
+       }
+
+       VideoPlayerPageWRef VideoPlayerPage::Builder::build(
+                       const ExitRequestHandler onExitRequest) const
+       {
+               if (!onExitRequest) {
+                       LOG_RETURN_VALUE(RES_INVALID_ARGUMENTS, {},
+                                       "onExitRequest is NULL");
+               }
+               if (!m_navi) {
+                       LOG_RETURN_VALUE(RES_INVALID_ARGUMENTS, {}, "m_navi is NULL");
+               }
+               if (!m_media) {
+                       LOG_RETURN_VALUE(RES_INVALID_ARGUMENTS, {}, "m_media is NULL");
+               }
+               if (m_media->getType() != MediaType::VIDEO) {
+                       LOG_RETURN_VALUE(RES_INVALID_ARGUMENTS, {}, "Wrong media type");
+               }
+
+               auto result = makeShared<VideoPlayerPage>(
+                               m_navi, onExitRequest, m_media);
+
+               FAIL_RETURN_VALUE(result->prepare(), {}, "result->prepare() failed!");
+
+               return result;
+       }
+
+       // VideoPlayerPage //
+
+       VideoPlayerPage::VideoPlayerPage(RefCountObjBase &rc,
+                       const NaviframeSRef &navi,
+                       const ExitRequestHandler onExitRequest,
+                       const MediaItemSRef &media) :
+               Page(rc, navi, onExitRequest),
+               m_media(media),
+               m_player(),
+               m_videoDuration(0),
+               m_autoStartTimer(nullptr),
+               m_controlsHideTimer(nullptr),
+               m_tickTimer(nullptr),
+               m_state(State::PAUSED),
+               m_isControlsVisible(false),
+               m_needAutoStart(true)
+       {
+       }
+
+       VideoPlayerPage::~VideoPlayerPage()
+       {
+               setScreenOlwaysOn(false);
+
+               delRotaryEventHandler(CALLBACK_A(VideoPlayerPage::onRotary), this);
+
+               stopTimer(m_autoStartTimer);
+               stopTimer(m_controlsHideTimer);
+               stopTimer(m_tickTimer);
+
+               if (m_player) {
+                       if (getPlayerState() != PLAYER_STATE_IDLE) {
+                               FAIL_LOG(util::call(player_unprepare, m_player),
+                                               "player_unprepare() failed!");
+                       }
+                       FAIL_LOG(util::call(player_destroy, m_player),
+                                       "player_destroy() failed!");
+               }
+       }
+
+       Result VideoPlayerPage::prepare()
+       {
+               m_content = Layout::Builder().
+                               setTheme(impl::LAYOUT_VIDEO_PLAYER).
+                               setIsOwner(true).
+                               build(getNaviframe());
+               if (!m_content) {
+                       LOG_RETURN(RES_FAIL, "m_content is NULL");
+               }
+
+               FAIL_RETURN(Page::prepare(
+                       [this]()
+                       {
+                               return getNaviframe().push(*m_content, NAVIFRAME_EMPTY);
+                       }),
+                       "Page::prepare() failed!");
+
+               createImage();
+               FAIL_RETURN(preparePlayer(), "preparePlayer() failed!");
+
+               createControls();
+               updatePlayTimeText();
+
+               m_touchParser = makeShared<TouchParser>(*m_image);
+               m_touchParser->setTapHandler(
+                               DELEGATE(VideoPlayerPage::onTap, this));
+
+               getWindow().addEventHandler(INSTANCE_PAUSED, WEAK_DELEGATE(
+                               VideoPlayerPage::onInstancePaused, asWeak(*this)));
+               getWindow().addEventHandler(INSTANCE_RESUMED, WEAK_DELEGATE(
+                               VideoPlayerPage::onInstanceResumed, asWeak(*this)));
+
+               addRotaryEventHandler(CALLBACK_A(VideoPlayerPage::onRotary), this);
+
+               if (!isInstancePaused(getWindow())) {
+                       resetAutoStartTimer();
+               }
+
+               return RES_OK;
+       }
+
+       void VideoPlayerPage::createImage()
+       {
+               m_image = makeShared<Widget>(
+                               evas_object_image_filled_add(m_content->getEvas()));
+               show(*m_image);
+
+               m_content->setContent(*m_image);
+       }
+
+       Result VideoPlayerPage::preparePlayer()
+       {
+               FAIL_RETURN(util::getNz(player_create, m_player),
+                               "player_create() failed!");
+
+               FAIL_RETURN(util::call(player_set_display_mode, m_player,
+                               PLAYER_DISPLAY_MODE_CROPPED_FULL),
+                               "player_set_display_mode() failed!");
+
+               FAIL_RETURN(util::call(player_set_display, m_player,
+                               PLAYER_DISPLAY_TYPE_EVAS, GET_DISPLAY(m_image->getEo())),
+                               "player_set_display() failed!");
+
+               FAIL_RETURN(util::call(player_set_uri, m_player,
+                               m_media->getFilePath().c_str()),
+                               "player_set_uri() failed!");
+
+               FAIL_RETURN(util::call(player_prepare, m_player),
+                               "player_prepare() failed!");
+
+               FAIL_RETURN(util::getNz(player_get_duration, m_videoDuration, m_player),
+                               "player_get_duration() failed!");
+
+               FAIL_RETURN(seekToStart(), "seekToStart() failed!");
+
+               FAIL_RETURN(util::call(player_set_completed_cb, m_player,
+                               CALLBACK_B(VideoPlayerPage::onPlaybackComplete), this),
+                               "player_set_completed_cb() failed!");
+
+               FAIL_RETURN(util::call(player_set_interrupted_cb, m_player,
+                               CALLBACK_B(VideoPlayerPage::onPlaybackInterrupted),
+                               this), "player_set_interrupted_cb() failed!");
+
+               return RES_OK;
+       }
+
+       Result VideoPlayerPage::seekToStart()
+       {
+               FAIL_RETURN(util::call(player_set_play_position, m_player, true, 0,
+                               CALLBACK_B(VideoPlayerPage::onSeekComplete), this),
+                               "player_set_play_position() failed!");
+               return RES_OK;
+       }
+
+       void VideoPlayerPage::createControls()
+       {
+               createButton(impl::STYLE_VOLUME_ON_BTN, impl::PART_VOLUME_ON_BTN,
+                               WEAK_DELEGATE(VideoPlayerPage::onVolumeOnBtnClick,
+                               asWeak(*this)));
+
+               createButton(impl::STYLE_VOLUME_MUTE_BTN, impl::PART_VOLUME_MUTE_BTN,
+                               WEAK_DELEGATE(VideoPlayerPage::onVolumeMuteBtnClick,
+                               asWeak(*this)));
+
+               createButton(impl::STYLE_PLAY_BTN, impl::PART_PLAY_BTN,
+                               WEAK_DELEGATE(VideoPlayerPage::onPlayBtnClick,
+                               asWeak(*this)));
+
+               createButton(impl::STYLE_PAUSE_BTN, impl::PART_PAUSE_BTN,
+                               WEAK_DELEGATE(VideoPlayerPage::onPauseBtnClick,
+                               asWeak(*this)));
+       }
+
+       void VideoPlayerPage::createButton(const ElmStyle style,
+                       const EdjePart part, const WidgetEventHandler &handler)
+       {
+               const auto btn = makeShared<StyledWidget>(elm_button_add(*m_content));
+               btn->setStyle(style);
+               show(*btn);
+
+               m_content->setContent(*btn, part);
+
+               btn->addEventHandler(BTN_CLICKED, handler);
+       }
+
+       bool VideoPlayerPage::resetTimer(Ecore_Timer *&timer,
+                       const double timeout, Ecore_Task_Cb func)
+       {
+               stopTimer(timer);
+
+               timer = ecore_timer_add(timeout, func, this);
+               if (!timer) {
+                       LOG_RETURN_VALUE(RES_FAIL, false, "ecore_timer_add() failed!");
+               }
+
+               return true;
+       }
+
+       void VideoPlayerPage::stopTimer(Ecore_Timer *&timer)
+       {
+               if (timer) {
+                       ecore_timer_del(timer);
+                       timer = nullptr;
+               }
+       }
+
+       bool VideoPlayerPage::resetAutoStartTimer()
+       {
+               return resetTimer(m_autoStartTimer, impl::AUTO_START_TIMEOUT_SEC,
+                               CALLBACK_A(VideoPlayerPage::onAutoStartTimer));
+       }
+
+       bool VideoPlayerPage::resetControlsHideTimer()
+       {
+               if (m_isPlaybackCompleted) {
+                       stopTimer(m_controlsHideTimer);
+                       return true;
+               }
+               return resetTimer(m_controlsHideTimer,
+                               ((m_state == State::PLAYING) ?
+                                       impl::CONTROLS_PLAYBACK_HIDE_TIMEOUT_SEC :
+                                       impl::CONTROLS_PAUSE_HIDE_TIMEOUT_SEC
+                               ),
+                               CALLBACK_A(VideoPlayerPage::onControlsHideTimer));
+       }
+
+       bool VideoPlayerPage::resetTickTimer()
+       {
+               return resetTimer(m_tickTimer, impl::TICK_TIMER_INTERVAL_SEC,
+                               CALLBACK_A(VideoPlayerPage::onTickTimer));
+       }
+
+       void VideoPlayerPage::showControls()
+       {
+               if (!m_isControlsVisible) {
+                       m_isControlsVisible = true;
+
+                       if (m_state == State::PLAYING) {
+                               m_content->emit(impl::SHOW_PAUSE_BTN);
+                               resetTickTimer();
+                               updatePlayTimeText();
+                       } else {
+                               m_content->emit(impl::SHOW_PLAY_BTN);
+                       }
+
+                       m_content->emit(impl::SHOW_TEXT);
+               }
+
+               resetControlsHideTimer();
+       }
+
+       void VideoPlayerPage::hideControls()
+       {
+               if (m_isControlsVisible) {
+                       m_isControlsVisible = false;
+
+                       m_content->emit(impl::HIDE_VOLUME_BTN);
+                       m_content->emit(impl::HIDE_PLAY_PAUSE_BTN);
+                       m_content->emit(impl::HIDE_TEXT);
+
+                       stopTimer(m_tickTimer);
+                       stopTimer(m_controlsHideTimer);
+               }
+       }
+
+       bool VideoPlayerPage::updatePlayTimeText()
+       {
+               int playPosition = 0;
+
+               if (isBad(util::get(player_get_play_position,
+                               playPosition, m_player))) {
+                       ELOG("player_get_play_position() failed!");
+                       return false;
+               }
+
+               updatePlayTimeText(std::min(playPosition, m_videoDuration));
+
+               return true;
+       }
+
+       void VideoPlayerPage::updatePlayTimeText(const int timeMs)
+       {
+               int posH = 0;
+               int posM = 0;
+               int posS = 0;
+               impl::timeMsToHMS(timeMs, posH, posM, posS);
+
+               int durH = 0;
+               int durM = 0;
+               int durS = 0;
+               impl::timeMsToHMS(m_videoDuration, durH, durM, durS);
+
+               if (durH == 0) {
+                       m_content->setText(impl::TIME_SHORT_FORMAT.format(
+                                       posM, posS, durM, durS));
+               } else {
+                       m_content->setText(impl::TIME_LONG_FORMAT.format(
+                                       posH, posM, posS, durH, durM, durS));
+               }
+       }
+
+       player_state_e VideoPlayerPage::getPlayerState() const
+       {
+               player_state_e result = PLAYER_STATE_NONE;
+               FAIL_LOG(util::getNz(player_get_state, result, m_player),
+                               "player_get_state() failed!");
+               return result;
+       }
+
+       void VideoPlayerPage::startPlayback()
+       {
+               if (m_state != State::PAUSED) {
+                       return;
+               }
+               m_state = State::PLAYING;
+
+               const auto playerState = getPlayerState();
+               switch (playerState) {
+               case PLAYER_STATE_READY:
+               case PLAYER_STATE_PAUSED:
+                       if (m_isPlaybackCompleted) {
+                               m_isPlaybackCompleted = false;
+                               FAIL_LOG(seekToStart(), "seekToStart() failed!");
+                       } else {
+                               FAIL_LOG(util::call(player_start, m_player),
+                                               "player_start() failed!");
+                       }
+                       break;
+               default:
+                       WLOG("Unexpected player state: %d;", playerState);
+                       break;
+               }
+
+               setScreenOlwaysOn(true);
+               resetTickTimer();
+               stopTimer(m_autoStartTimer);
+               m_needAutoStart = false;
+
+               if (m_isControlsVisible) {
+                       m_content->emit(impl::SHOW_PAUSE_BTN);
+               }
+       }
+
+       void VideoPlayerPage::pausePlayback()
+       {
+               if (m_state != State::PLAYING) {
+                       return;
+               }
+               m_state = State::PAUSED;
+
+               const auto playerState = getPlayerState();
+               switch (playerState) {
+               case PLAYER_STATE_PLAYING:
+                       FAIL_LOG(util::call(player_pause, m_player),
+                                       "player_pause() failed!");
+                       break;
+               default:
+                       WLOG("Unexpected player state: %d;", playerState);
+                       break;
+               }
+
+               setScreenOlwaysOn(false);
+               stopTimer(m_tickTimer);
+               updatePlayTimeText();
+
+               if (m_isControlsVisible) {
+                       m_content->emit(impl::SHOW_PLAY_BTN);
+               }
+       }
+
+       void VideoPlayerPage::setScreenOlwaysOn(bool isAlwaysOn)
+       {
+               efl_util_set_window_screen_mode(getWindow(),
+                               (isAlwaysOn ? EFL_UTIL_SCREEN_MODE_ALWAYS_ON :
+                                       EFL_UTIL_SCREEN_MODE_DEFAULT));
+       }
+
+       void VideoPlayerPage::onPlaybackComplete()
+       {
+               m_isPlaybackCompleted = true;
+               pausePlayback();
+               showControls();
+       }
+
+       void VideoPlayerPage::onPlaybackInterrupted(player_interrupted_code_e code)
+       {
+               if (code != PLAYER_INTERRUPTED_COMPLETED) {
+                       pausePlayback();
+                       showControls();
+               }
+       }
+
+       void VideoPlayerPage::onSeekComplete()
+       {
+               if ((m_state == State::PLAYING) &&
+                               (getPlayerState() != PLAYER_STATE_PLAYING)) {
+                       FAIL_LOG(util::call(player_start, m_player),
+                                       "player_start() failed!");
+               }
+       }
+
+       Eina_Bool VideoPlayerPage::onAutoStartTimer()
+       {
+               m_autoStartTimer = nullptr;
+
+               startPlayback();
+
+               return ECORE_CALLBACK_CANCEL;
+       }
+
+       Eina_Bool VideoPlayerPage::onControlsHideTimer()
+       {
+               m_controlsHideTimer = nullptr;
+
+               hideControls();
+
+               return ECORE_CALLBACK_CANCEL;
+       }
+
+       Eina_Bool VideoPlayerPage::onTickTimer()
+       {
+               if (!updatePlayTimeText()) {
+                       m_tickTimer = nullptr;
+                       return ECORE_CALLBACK_CANCEL;
+               }
+               return ECORE_CALLBACK_RENEW;
+       }
+
+       void VideoPlayerPage::onVolumeOnBtnClick(Widget &sender, void *eventInfo)
+       {
+       }
+
+       void VideoPlayerPage::onVolumeMuteBtnClick(Widget &sender, void *eventInfo)
+       {
+       }
+
+       void VideoPlayerPage::onPlayBtnClick(Widget &sender, void *eventInfo)
+       {
+               startPlayback();
+               resetControlsHideTimer();
+       }
+
+       void VideoPlayerPage::onPauseBtnClick(Widget &sender, void *eventInfo)
+       {
+               pausePlayback();
+               resetControlsHideTimer();
+       }
+
+       void VideoPlayerPage::onTap(int x, int y)
+       {
+               if (m_isControlsVisible) {
+                       hideControls();
+               } else {
+                       showControls();
+               }
+       }
+
+       Eina_Bool VideoPlayerPage::onRotary(Eext_Rotary_Event_Info *info)
+       {
+               showControls();
+               return EINA_TRUE;
+       }
+
+       void VideoPlayerPage::onInstancePaused(Widget &sender, void *eventInfo)
+       {
+               pausePlayback();
+               stopTimer(m_autoStartTimer);
+               stopTimer(m_controlsHideTimer);
+       }
+
+       void VideoPlayerPage::onInstanceResumed(Widget &sender, void *eventInfo)
+       {
+               if (m_needAutoStart) {
+                       resetAutoStartTimer();
+               } else {
+                       showControls();
+               }
+       }
+}
index c736755b90862a07048b0e6e1dfb21225d0ad863..ffa378425368c680818df02623f73e682a5f2d0a 100644 (file)
@@ -94,6 +94,9 @@ namespace gallery {
                if (!m_media) {
                        LOG_RETURN_VALUE(RES_INVALID_ARGUMENTS, {}, "m_media is NULL");
                }
+               if (m_media->getType() != MediaType::IMAGE) {
+                       LOG_RETURN_VALUE(RES_INVALID_ARGUMENTS, {}, "Wrong media type");
+               }
 
                auto result = makeShared<ViewerPage>(
                                m_navi, onExitRequest, m_media, m_exitOnZoomOut);
index a171f480034f3b862f4404ec324a3cb874b8171f..8a5ab5cf2bd453280291db326feb2b378564a16f 100644 (file)
@@ -17,6 +17,8 @@
 #ifndef __GALLERY_PRESENTERS_COMMON_H__
 #define __GALLERY_PRESENTERS_COMMON_H__
 
+#include "internal.h"
+
 #include "../view/common.h"
 
 #endif // __GALLERY_PRESENTERS_COMMON_H__
diff --git a/src/presenters/internal.cpp b/src/presenters/internal.cpp
new file mode 100644 (file)
index 0000000..33cf63f
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2017 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal.h"
+
+#include "common.h"
+
+namespace gallery { namespace { namespace impl {
+
+       using namespace ucl;
+
+       constexpr EoDataKey INSTANCE_PTR {"gallery,instance,data,ptr"};
+}}}
+
+namespace gallery {
+
+       using namespace ucl;
+
+       void setInstancePaused(ucl::Window &win, const bool value)
+       {
+               win.setData(impl::INSTANCE_PTR, reinterpret_cast<void *>(value));
+               win.callEvent((value ? INSTANCE_PAUSED : INSTANCE_RESUMED), nullptr);
+       }
+
+       bool isInstancePaused(const ucl::Window &win)
+       {
+               return (reinterpret_cast<intptr_t>(
+                               win.getData(impl::INSTANCE_PTR)) != 0);
+       }
+}
diff --git a/src/presenters/internal.h b/src/presenters/internal.h
new file mode 100644 (file)
index 0000000..a0f7ecb
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2017 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __GALLERY_PRESENTERS_INTERNAL_H__
+#define __GALLERY_PRESENTERS_INTERNAL_H__
+
+#include "ucl/gui/Window.h"
+
+namespace gallery {
+
+       constexpr ucl::SmartEvent INSTANCE_PAUSED {"gallery,instance,paused"};
+       constexpr ucl::SmartEvent INSTANCE_RESUMED {"gallery,instance,resumed"};
+
+       void setInstancePaused(ucl::Window &win, bool value);
+       bool isInstancePaused(const ucl::Window &win);
+}
+
+#endif // __GALLERY_PRESENTERS_INTERNAL_H__
index daf60fd9e98d717ad92a3249e6b9cb1801fe03eb..f0f7f5e2228e9627ae5fb05af19a970e327453c9 100644 (file)
@@ -7,6 +7,7 @@
                <app-control>
                        <operation name="http://tizen.org/appcontrol/operation/view"/>
                        <mime name="image/*"/>
+                       <mime name="video/*"/>
                </app-control>
        </ui-application>
        <privileges>