From: Lukasz Stanislawski Date: Thu, 15 Sep 2016 14:55:27 +0000 (+0200) Subject: EditAlarmView: enable choosing alarm's melodies. X-Git-Tag: submit/tizen/20161113.192141^2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=c71ec9bc2d47f11feafa9f1f643d69087f47d58c;p=profile%2Fmobile%2Fapps%2Fnative%2Fclock.git EditAlarmView: enable choosing alarm's melodies. 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 --- diff --git a/clock/inc/Common/Defines.h b/clock/inc/Common/Defines.h index e5bf3f7..40e57fb 100644 --- a/clock/inc/Common/Defines.h +++ b/clock/inc/Common/Defines.h @@ -21,6 +21,10 @@ #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 index 0000000..5b7742e --- /dev/null +++ b/clock/inc/Utils/RingtonePicker.h @@ -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 +#include + +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 cb); + private: + std::string ringtone_; + std::function update_cb_; + bool initialized_; + static void AppControlCb(app_control_h request, app_control_h reply, app_control_result_e result, void *priv); +}; + +} /* utils */ + +#endif diff --git a/clock/inc/View/EditAlarmView.h b/clock/inc/View/EditAlarmView.h index 7cd1bd4..0dcc506 100644 --- a/clock/inc/View/EditAlarmView.h +++ b/clock/inc/View/EditAlarmView.h @@ -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 */ diff --git a/clock/res/settings/ringtone_sdk.mp3 b/clock/res/settings/ringtone_sdk.mp3 deleted file mode 100644 index f159e35..0000000 Binary files a/clock/res/settings/ringtone_sdk.mp3 and /dev/null differ diff --git a/clock/shared/res/ringtones/alarm.mp3 b/clock/shared/res/ringtones/alarm.mp3 new file mode 100644 index 0000000..f159e35 Binary files /dev/null and b/clock/shared/res/ringtones/alarm.mp3 differ diff --git a/clock/src/Presenter/RingPresenter.cpp b/clock/src/Presenter/RingPresenter.cpp index 552f773..f742206 100644 --- a/clock/src/Presenter/RingPresenter.cpp +++ b/clock/src/Presenter/RingPresenter.cpp @@ -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 index 0000000..6fbbd9b --- /dev/null +++ b/clock/src/Utils/RingtonePicker.cpp @@ -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(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 cb) +{ + update_cb_ = cb; +} + +}; diff --git a/clock/src/View/EditAlarmView.cpp b/clock/src/View/EditAlarmView.cpp index d856380..32f5d5c 100644 --- a/clock/src/View/EditAlarmView.cpp +++ b/clock/src/View/EditAlarmView.cpp @@ -15,9 +15,10 @@ */ #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 #include @@ -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(event); + EditAlarmView *view = static_cast(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()); + } +}