EditAlarmView: enable choosing alarm's melodies. 50/90350/8
authorLukasz Stanislawski <l.stanislaws@samsung.com>
Thu, 15 Sep 2016 14:55:27 +0000 (16:55 +0200)
committerLukasz Stanislawski <l.stanislaws@samsung.com>
Fri, 4 Nov 2016 11:57:01 +0000 (12:57 +0100)
Add RingtonePicker utility class that will handle external
application commounication in order to provide rigtone path.

By default RingtonePicker is using app_control request to
launch external application and settings ringtone dir:
/opt/share/settings/Ringtones

Move resource to shared/res directory to enable external
apps to access application files in read-only mode.

Change-Id: Ia8690180eb366f98635a57018b7c21ca2dea4e45

clock/inc/Common/Defines.h
clock/inc/Utils/RingtonePicker.h [new file with mode: 0644]
clock/inc/View/EditAlarmView.h
clock/shared/res/ringtones/alarm.mp3 [moved from clock/res/settings/ringtone_sdk.mp3 with 100% similarity]
clock/src/Presenter/RingPresenter.cpp
clock/src/Utils/RingtonePicker.cpp [new file with mode: 0644]
clock/src/View/EditAlarmView.cpp

index e5bf3f7..40e57fb 100644 (file)
 
 #define APP_CONTROL_OPERATION_TIMEOUT "http://tizen.org/appcontrol/operation/timeout"
 #define APP_CONTROL_OPERATION_ALARM "http://tizen.org/appcontrol/operation/alarm"
+#define RINGTONE_APP_PACKAGE_ID "org.tizen.setting-ringtone"
+
+#define ARRAY_SIZE(x) sizeof(x)/sizeof(x[0])
+#define DEFAULT_RINGTONE_PATH "ringtones/alarm.mp3"
 
 #define SOUND_DEFAULT "settings/ringtone_sdk.mp3"
 
diff --git a/clock/inc/Utils/RingtonePicker.h b/clock/inc/Utils/RingtonePicker.h
new file mode 100644 (file)
index 0000000..5b7742e
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+* Copyright 2016  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 _CLOCK_UTILS_RINGTONE_PICKER_H_
+#define _CLOCK_UTILS_RINGTONE_PICKER_H_
+
+#include <app_control.h>
+#include <functional>
+
+namespace utils {
+
+class RingtonePicker {
+       public:
+               /**
+                * @brief Default constructor.
+                */
+               RingtonePicker();
+
+               /**
+                * @brief Shows rigntone picker view.
+                *
+                * @return true on success, false if unable to show view.
+                */
+               bool ShowDialog();
+
+               /**
+                * @brief Gets chosen ringtone file path.
+                *
+                * @return return absolute file path to ringtone. Value remains valid
+                * until class is destructed or function subscribed with
+                * RegisterPathUpdateSignalHandler is called.
+                */
+               const std::string& GetRingtonePath() const { return ringtone_; }
+
+               /**
+                * @brief Register callback called when ringtone path changes.
+                * New path will be returned by GetRingtonePath method.
+                */
+               void RegisterPathUpdateSignalHandler(std::function<void(void)> cb);
+       private:
+               std::string ringtone_;
+               std::function<void(void)> update_cb_;
+               bool initialized_;
+               static void AppControlCb(app_control_h request, app_control_h reply, app_control_result_e result, void *priv);
+};
+
+} /* utils */
+
+#endif
index 7cd1bd4..0dcc506 100644 (file)
@@ -24,6 +24,7 @@
 #include "Model/WeekFlags.h"
 #include "Model/Alarm.h"
 #include "View/WeekFlagsView.h"
+#include "Utils/RingtonePicker.h"
 
 namespace view {
        class EditAlarmView : public PageView {
@@ -70,6 +71,7 @@ namespace view {
                        Elm_Object_Item *type_it_;
                        Elm_Object_Item *repeat_it_;
                        Elm_Object_Item *volume_it_;
+                       Elm_Object_Item *tone_it_;
 
                        AlarmViewInfo data_;
                        bool is_muted_;
@@ -87,12 +89,15 @@ namespace view {
                        static void PopupListItemSelectedCallback(void *data, Evas_Object *obj, void *event);
                        static void PopupHide(void *data, Evas_Object *obj, void *event);
                        static void SnoozeItemSelectedCallback(void *data, Evas_Object *obj, void *event);
+                       static void ChooseAlarmToneItemSelectedCallback(void *data, Evas_Object *obj, void *event);
 
                        void CreateGenlistItems();
                        void ShowSetTypePopup();
                        void OnWeekFlagsPagePopped();
 
                        void UpdateVolumeIcon(bool mute);
+                       utils::RingtonePicker picker_;
+                       void RingtonePathUpdateCallback();
        };
 } /* view */
 
index 552f773..f742206 100644 (file)
@@ -40,7 +40,7 @@ RingPresenter::RingPresenter(view::RingView *view, model::Ring *model)
        model_->Run();
        animator_.Start();
        view_->EnableSnooze(false);
-       view_->PlayMusic(utils::Utils::GetAppResourcePath(utils::Utils::APP_DIR_RESOURCE, SOUND_DEFAULT), 1.0);
+       view_->PlayMusic(utils::Utils::GetAppResourcePath(utils::Utils::APP_DIR_SHARED_RESOURCE, SOUND_DEFAULT), 1.0);
        view_->StartVibration();
 }
 
@@ -68,7 +68,7 @@ RingPresenter::RingPresenter(view::RingView *view, model::Alarm *alarm)
        else {
                DBG("Invalid alarm's sound path. Playing default.");
                view_->PlayMusic(utils::Utils::GetAppResourcePath(
-                                       utils::Utils::APP_DIR_RESOURCE, SOUND_DEFAULT),
+                                       utils::Utils::APP_DIR_SHARED_RESOURCE, SOUND_DEFAULT),
                                alarm_->GetVolume());
        }
 
diff --git a/clock/src/Utils/RingtonePicker.cpp b/clock/src/Utils/RingtonePicker.cpp
new file mode 100644 (file)
index 0000000..6fbbd9b
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+* Copyright 2016  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 "Common/Defines.h"
+#include "Utils/Log.h"
+#include "Utils/RingtonePicker.h"
+#include "Utils/Utils.h"
+
+namespace utils {
+
+RingtonePicker::RingtonePicker() :
+       initialized_(false)
+{
+}
+
+void RingtonePicker::AppControlCb(app_control_h request, app_control_h reply,
+               app_control_result_e result, void *priv)
+{
+       char **ringtone_path;
+       int len;
+
+       RingtonePicker *instance = static_cast<RingtonePicker*>(priv);
+       instance->initialized_ = false;
+
+       if (result != APP_CONTROL_RESULT_SUCCEEDED) {
+               ERR("app_control '%s' operation failed", APP_CONTROL_OPERATION_PICK);
+               return;
+       }
+
+       int err = app_control_get_extra_data_array(reply, APP_CONTROL_DATA_SELECTED,
+                       &ringtone_path, &len);
+       if (err != APP_CONTROL_ERROR_NONE) {
+               ERR("app_control_get_extra_data_array failed: %s", get_error_message(err));
+               return;
+       }
+
+       if (len != 1) {
+               ERR("Invalid ringtones paths count, expected 1, got %d", len);
+               free(ringtone_path);
+               return;
+       }
+
+       // when replay contains extra data -> pick operation was successfull
+       DBG("Recieved ringthone path: %s", ringtone_path[0]);
+       instance->ringtone_ = ringtone_path[0];
+       free(ringtone_path);
+       if (instance->update_cb_)
+               instance->update_cb_();
+}
+
+bool RingtonePicker::ShowDialog()
+{
+       app_control_h handle;
+       const char *arr[2];
+
+       if (initialized_)
+               return true;
+
+       // Request remote RINGTONE_APP_PACKAGE_ID app to choose ringtone for us
+       int err = app_control_create(&handle);
+       if (err != APP_CONTROL_ERROR_NONE) {
+               ERR("app_control_create failed: %s", get_error_message(err));
+               return false;
+       }
+
+       err = app_control_set_app_id(handle, RINGTONE_APP_PACKAGE_ID);
+       if (err != APP_CONTROL_ERROR_NONE) {
+               ERR("app_control_set_app_id failed: %s", get_error_message(err));
+               app_control_destroy(handle);
+               return false;
+       }
+
+       err = app_control_set_operation(handle, APP_CONTROL_OPERATION_PICK);
+       if (err != APP_CONTROL_ERROR_NONE) {
+               ERR("app_control_set_operation failed: %s", get_error_message(err));
+               app_control_destroy(handle);
+               return false;
+       }
+
+       // allow RINGTONE_APP_PACKAGE_ID app to select only one item
+       err = app_control_add_extra_data(handle, APP_CONTROL_DATA_SELECTION_MODE, "single");
+       if (err != APP_CONTROL_ERROR_NONE) {
+               ERR("app_control_add_extra_data failed: %s", get_error_message(err));
+               app_control_destroy(handle);
+               return false;
+       }
+
+       // pass default ringtone to settings-ringtone (will be included on list)
+       arr[0] = Utils::GetAppResourcePath(Utils::APP_DIR_SHARED_RESOURCE, DEFAULT_RINGTONE_PATH);
+       // FIXME pass directory information, since settings are not interpreting
+       // APP_CONTROL_DATA_PATH values correctly (scans dir for files)
+       arr[1] = Utils::GetAppResourcePath(Utils::APP_DIR_SHARED_RESOURCE, "ringtones");
+       err = app_control_add_extra_data_array(handle, APP_CONTROL_DATA_PATH, arr,
+                       ARRAY_SIZE(arr));
+       if (err != APP_CONTROL_ERROR_NONE) {
+               ERR("app_control_add_extra_data_array failed: %s", get_error_message(err));
+               app_control_destroy(handle);
+               return false;
+       }
+
+       err = app_control_set_launch_mode(handle, APP_CONTROL_LAUNCH_MODE_GROUP);
+       if (err != APP_CONTROL_ERROR_NONE) {
+               ERR("app_control_set_launch_mode failed: %s", get_error_message(err));
+               app_control_destroy(handle);
+               return false;
+       }
+
+       err = app_control_send_launch_request(handle, AppControlCb, this);
+       if (err != APP_CONTROL_ERROR_NONE) {
+               ERR("app_control_send_launch_request failed: %s", get_error_message(err));
+               app_control_destroy(handle);
+               return false;
+       }
+
+       app_control_destroy(handle);
+       initialized_ = true;
+       return true;
+}
+
+void RingtonePicker::RegisterPathUpdateSignalHandler(std::function<void(void)> cb)
+{
+       update_cb_ = cb;
+}
+
+};
index d856380..32f5d5c 100644 (file)
 */
 
 #include "Utils/Log.h"
-#include "View/EditAlarmView.h"
+#include "Utils/RingtonePicker.h"
 #include "Utils/Utils.h"
 #include "Utils/ThemeExtension.h"
+#include "View/EditAlarmView.h"
 
 #include <efl_extension.h>
 #include <Elementary.h>
@@ -37,6 +38,8 @@ EditAlarmView::EditAlarmView(ui::IView &main)
 {
        week_flags_view_.RegisterPoppedCallback(
                        std::bind(&EditAlarmView::OnWeekFlagsPagePopped, this));
+       picker_.RegisterPathUpdateSignalHandler(
+                       std::bind(&EditAlarmView::RingtonePathUpdateCallback, this));
 }
 
 EditAlarmView::~EditAlarmView()
@@ -290,6 +293,16 @@ void EditAlarmView::SnoozeItemSelectedCallback(void *data, Evas_Object *obj, voi
        elm_genlist_item_selected_set(it, EINA_FALSE);
 }
 
+void EditAlarmView::ChooseAlarmToneItemSelectedCallback(void *data, Evas_Object *obj, void *event)
+{
+       Elm_Object_Item *it = static_cast<Elm_Object_Item*>(event);
+       EditAlarmView *view = static_cast<EditAlarmView*>(data);
+
+       if (!view->picker_.ShowDialog())
+               ERR("RingtonePicker::ShowDialog failed");
+       elm_genlist_item_selected_set(it, EINA_FALSE);
+}
+
 void EditAlarmView::CreateGenlistItems()
 {
        Elm_Genlist_Item_Class *itc;
@@ -383,11 +396,13 @@ void EditAlarmView::CreateGenlistItems()
                if (!strcmp(part, "elm.text")) {
                        return strdup("Alarm tone");
                } else if (!strcmp(part, "elm.text.sub")) {
-                       return strdup(view->data_.melody.c_str());
+                       const char *basename = ecore_file_file_get(view->data_.melody.c_str());
+                       return strdup(basename ? basename : view->data_.melody.c_str());
                }
                return NULL;
        };
-       elm_genlist_item_append(content_, itc, this, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL);
+       tone_it_ = elm_genlist_item_append(content_, itc, this, NULL, ELM_GENLIST_ITEM_NONE,
+                       EditAlarmView::ChooseAlarmToneItemSelectedCallback, this);
        elm_genlist_item_class_unref(itc);
 
        // snooze configuration
@@ -522,3 +537,13 @@ void EditAlarmView::SetData(const AlarmViewInfo &info)
        is_muted_ = data_.volume <= 0.0 ? true : false;
        elm_genlist_realized_items_update(content_);
 }
+
+void EditAlarmView::RingtonePathUpdateCallback()
+{
+       if (ecore_file_can_read(picker_.GetRingtonePath().c_str())) {
+               data_.melody = picker_.GetRingtonePath();
+               elm_genlist_item_update(tone_it_);
+       } else {
+               ERR("Selected path cannot be read: %s", picker_.GetRingtonePath().c_str());
+       }
+}