aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--debian/changelog8
-rw-r--r--include/datetime/clock-mock.h12
-rw-r--r--include/datetime/clock.h4
-rw-r--r--src/clock-live.cpp31
-rw-r--r--src/clock.cpp82
-rw-r--r--src/main.cpp14
-rw-r--r--src/planner-range.cpp7
-rw-r--r--src/snap.cpp11
-rw-r--r--tests/manual16
-rw-r--r--tests/test-clock.cpp92
10 files changed, 207 insertions, 70 deletions
diff --git a/debian/changelog b/debian/changelog
index 04fcc14..a27953d 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,11 @@
+indicator-datetime (13.10.0+14.10.20140915-0ubuntu1) utopic; urgency=low
+
+ [ Charles Kerr ]
+ * Update the time strings when a powerd Wakeup signal is detected.
+ (LP: #1359802)
+
+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Mon, 15 Sep 2014 21:03:00 +0000
+
indicator-datetime (13.10.0+14.10.20140908.1-0ubuntu1) utopic; urgency=low
[ Charles Kerr ]
diff --git a/include/datetime/clock-mock.h b/include/datetime/clock-mock.h
index fb9b52f..0e24377 100644
--- a/include/datetime/clock-mock.h
+++ b/include/datetime/clock-mock.h
@@ -41,15 +41,23 @@ public:
DateTime localtime() const { return m_localtime; }
- void set_localtime(const DateTime& dt) {
+ void set_localtime(const DateTime& dt)
+ {
const auto old = m_localtime;
- m_localtime = dt;
+
+ set_localtime_quietly(dt);
+
if (!DateTime::is_same_minute(old, m_localtime))
minute_changed();
if (!DateTime::is_same_day(old, m_localtime))
date_changed();
}
+ void set_localtime_quietly(const DateTime& dt)
+ {
+ m_localtime = dt;
+ }
+
private:
DateTime m_localtime;
};
diff --git a/include/datetime/clock.h b/include/datetime/clock.h
index 0445aab..8745d24 100644
--- a/include/datetime/clock.h
+++ b/include/datetime/clock.h
@@ -66,7 +66,7 @@ private:
****
***/
-class Timezones;
+class Timezone;
/**
* \brief A live #Clock that provides the actual system time.
@@ -74,7 +74,7 @@ class Timezones;
class LiveClock: public Clock
{
public:
- LiveClock (const std::shared_ptr<const Timezones>& zones);
+ LiveClock (const std::shared_ptr<const Timezone>& zones);
virtual ~LiveClock();
virtual DateTime localtime() const;
diff --git a/src/clock-live.cpp b/src/clock-live.cpp
index 21a18a3..68a8a8b 100644
--- a/src/clock-live.cpp
+++ b/src/clock-live.cpp
@@ -18,7 +18,7 @@
*/
#include <datetime/clock.h>
-#include <datetime/timezones.h>
+#include <datetime/timezone.h>
namespace unity {
namespace indicator {
@@ -59,14 +59,15 @@ class LiveClock::Impl
{
public:
- Impl(LiveClock& owner, const std::shared_ptr<const Timezones>& tzd):
+ Impl(LiveClock& owner, const std::shared_ptr<const Timezone>& timezone_):
m_owner(owner),
- m_timezones(tzd)
+ m_timezone(timezone_)
{
- if (m_timezones)
+ if (m_timezone)
{
- m_timezones->timezone.changed().connect([this](const std::string& z) {setTimezone(z);});
- setTimezone(m_timezones->timezone.get());
+ auto setter = [this](const std::string& z){setTimezone(z);};
+ m_timezone->timezone.changed().connect(setter);
+ setter(m_timezone->timezone.get());
}
restart_minute_timer();
@@ -76,14 +77,14 @@ public:
{
clearTimer(m_timer);
- g_clear_pointer(&m_timezone, g_time_zone_unref);
+ g_clear_pointer(&m_gtimezone, g_time_zone_unref);
}
DateTime localtime() const
{
- g_assert(m_timezone != nullptr);
+ g_assert(m_gtimezone != nullptr);
- auto gdt = g_date_time_new_now(m_timezone);
+ auto gdt = g_date_time_new_now(m_gtimezone);
DateTime ret(gdt);
g_date_time_unref(gdt);
return ret;
@@ -93,8 +94,8 @@ private:
void setTimezone(const std::string& str)
{
- g_clear_pointer(&m_timezone, g_time_zone_unref);
- m_timezone = g_time_zone_new(str.c_str());
+ g_clear_pointer(&m_gtimezone, g_time_zone_unref);
+ m_gtimezone = g_time_zone_new(str.c_str());
m_owner.minute_changed();
}
@@ -134,15 +135,15 @@ private:
protected:
LiveClock& m_owner;
- GTimeZone* m_timezone = nullptr;
- std::shared_ptr<const Timezones> m_timezones;
+ GTimeZone* m_gtimezone = nullptr;
+ std::shared_ptr<const Timezone> m_timezone;
DateTime m_prev_datetime;
unsigned int m_timer = 0;
};
-LiveClock::LiveClock(const std::shared_ptr<const Timezones>& tzd):
- p(new Impl(*this, tzd))
+LiveClock::LiveClock(const std::shared_ptr<const Timezone>& timezone_):
+ p(new Impl(*this, timezone_))
{
}
diff --git a/src/clock.cpp b/src/clock.cpp
index 6831732..a04e074 100644
--- a/src/clock.cpp
+++ b/src/clock.cpp
@@ -41,34 +41,61 @@ class Clock::Impl
public:
Impl(Clock& owner):
- m_owner(owner)
+ m_owner(owner),
+ m_cancellable(g_cancellable_new())
{
- auto tag = g_bus_watch_name(G_BUS_TYPE_SYSTEM,
- "org.freedesktop.login1",
- G_BUS_NAME_WATCHER_FLAGS_NONE,
- on_login1_appeared,
- on_login1_vanished,
- this, nullptr);
- m_watched_names.insert(tag);
-
- tag = g_bus_watch_name(G_BUS_TYPE_SYSTEM,
- BUS_POWERD_NAME,
- G_BUS_NAME_WATCHER_FLAGS_NONE,
- on_powerd_appeared,
- on_powerd_vanished,
- this, nullptr);
- m_watched_names.insert(tag);
+ g_bus_get(G_BUS_TYPE_SYSTEM, m_cancellable, on_bus_ready, this);
}
-
~Impl()
{
+ g_cancellable_cancel(m_cancellable);
+ g_object_unref(m_cancellable);
+
for(const auto& tag : m_watched_names)
g_bus_unwatch_name(tag);
}
private:
+ static void on_bus_ready(GObject * /*source_object*/,
+ GAsyncResult * res,
+ gpointer gself)
+ {
+ GError * error = NULL;
+ GDBusConnection * bus;
+
+ if ((bus = g_bus_get_finish(res, &error)))
+ {
+ auto self = static_cast<Impl*>(gself);
+
+ auto tag = g_bus_watch_name_on_connection(bus,
+ "org.freedesktop.login1",
+ G_BUS_NAME_WATCHER_FLAGS_NONE,
+ on_login1_appeared,
+ on_login1_vanished,
+ gself, nullptr);
+ self->m_watched_names.insert(tag);
+
+ tag = g_bus_watch_name_on_connection(bus,
+ BUS_POWERD_NAME,
+ G_BUS_NAME_WATCHER_FLAGS_NONE,
+ on_powerd_appeared,
+ on_powerd_vanished,
+ gself, nullptr);
+ self->m_watched_names.insert(tag);
+
+ g_object_unref(bus);
+ }
+ else if (error != nullptr)
+ {
+ if (!g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ g_warning("%s Couldn't get system bus: %s", G_STRLOC, error->message);
+
+ g_error_free(error);
+ }
+ }
+
void remember_subscription(const std::string & name,
GDBusConnection * bus,
guint tag)
@@ -142,11 +169,11 @@ private:
auto tag = g_dbus_connection_signal_subscribe(bus,
name_owner,
BUS_POWERD_INTERFACE,
- "Wakeup", // signal name
+ "SysPowerStateChange",
BUS_POWERD_PATH,
nullptr, // arg0
G_DBUS_SIGNAL_FLAGS_NONE,
- on_wakeup,
+ on_sys_power_state_change,
gself, // user_data
nullptr); // user_data closure
@@ -161,15 +188,15 @@ private:
static_cast<Impl*>(gself)->m_subscriptions[name].clear();
}
- static void on_wakeup(GDBusConnection* /*connection*/,
- const gchar* /*sender_name*/,
- const gchar* /*object_path*/,
- const gchar* /*interface_name*/,
- const gchar* /*signal_name*/,
- GVariant* /*parameters*/,
- gpointer gself)
+ static void on_sys_power_state_change(GDBusConnection* /*connection*/,
+ const gchar* /*sender_name*/,
+ const gchar* /*object_path*/,
+ const gchar* /*interface_name*/,
+ const gchar* /*signal_name*/,
+ GVariant* /*parameters*/,
+ gpointer gself)
{
- g_debug("firing clock.minute_changed() due to powerd.Wakeup");
+ g_debug("firing clock.minute_changed() due to state change");
static_cast<Impl*>(gself)->m_owner.minute_changed();
}
@@ -178,6 +205,7 @@ private:
***/
Clock& m_owner;
+ GCancellable * m_cancellable = nullptr;
std::set<guint> m_watched_names;
std::map<std::string,std::vector<std::shared_ptr<GDBusConnection>>> m_subscriptions;
};
diff --git a/src/main.cpp b/src/main.cpp
index 54517c9..aa8f829 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -63,20 +63,20 @@ namespace
}
std::shared_ptr<State> create_state(const std::shared_ptr<Engine>& engine,
- const std::shared_ptr<Timezone>& tz)
+ const std::shared_ptr<Timezone>& timezone_)
{
// create the live objects
auto live_settings = std::make_shared<LiveSettings>();
auto live_timezones = std::make_shared<LiveTimezones>(live_settings, TIMEZONE_FILE);
- auto live_clock = std::make_shared<LiveClock>(live_timezones);
+ auto live_clock = std::make_shared<LiveClock>(timezone_);
// create a full-month planner currently pointing to the current month
const auto now = live_clock->localtime();
- auto range_planner = std::make_shared<SimpleRangePlanner>(engine, tz);
+ auto range_planner = std::make_shared<SimpleRangePlanner>(engine, timezone_);
auto calendar_month = std::make_shared<MonthPlanner>(range_planner, now);
// create an upcoming-events planner currently pointing to the current date
- range_planner = std::make_shared<SimpleRangePlanner>(engine, tz);
+ range_planner = std::make_shared<SimpleRangePlanner>(engine, timezone_);
auto calendar_upcoming = std::make_shared<UpcomingPlanner>(range_planner, now);
// create the state
@@ -127,8 +127,8 @@ main(int /*argc*/, char** /*argv*/)
textdomain(GETTEXT_PACKAGE);
auto engine = create_engine();
- auto timezone = std::make_shared<FileTimezone>(TIMEZONE_FILE);
- auto state = create_state(engine, timezone);
+ auto timezone_ = std::make_shared<FileTimezone>(TIMEZONE_FILE);
+ auto state = create_state(engine, timezone_);
auto actions = std::make_shared<LiveActions>(state);
MenuFactory factory(actions, state);
@@ -136,7 +136,7 @@ main(int /*argc*/, char** /*argv*/)
auto snooze_planner = std::make_shared<SnoozePlanner>(state->settings, state->clock);
auto notification_engine = std::make_shared<uin::Engine>("indicator-datetime-service");
std::unique_ptr<Snap> snap (new Snap(notification_engine, state->settings));
- auto alarm_queue = create_simple_alarm_queue(state->clock, snooze_planner, engine, timezone);
+ auto alarm_queue = create_simple_alarm_queue(state->clock, snooze_planner, engine, timezone_);
auto on_snooze = [snooze_planner](const Appointment& a) {snooze_planner->add(a);};
auto on_ok = [](const Appointment&){};
auto on_alarm_reached = [&snap, &on_snooze, &on_ok](const Appointment& a) {(*snap)(a, on_snooze, on_ok);};
diff --git a/src/planner-range.cpp b/src/planner-range.cpp
index 41b0f56..c223665 100644
--- a/src/planner-range.cpp
+++ b/src/planner-range.cpp
@@ -28,7 +28,7 @@ namespace datetime {
***/
SimpleRangePlanner::SimpleRangePlanner(const std::shared_ptr<Engine>& engine,
- const std::shared_ptr<Timezone>& timezone):
+ const std::shared_ptr<Timezone>& timezone):
m_engine(engine),
m_timezone(timezone),
m_range(std::pair<DateTime,DateTime>(DateTime::NowLocal(), DateTime::NowLocal()))
@@ -38,6 +38,11 @@ SimpleRangePlanner::SimpleRangePlanner(const std::shared_ptr<Engine>& engine,
rebuild_soon();
});
+ m_timezone->timezone.changed().connect([this](const std::string& s){
+ g_debug("RangePlanner %p rebuilding soon because the timezone changed to '%s'", this, s.c_str());
+ rebuild_soon();
+ });
+
range().changed().connect([this](const std::pair<DateTime,DateTime>&){
g_debug("rebuilding because the date range changed");
rebuild_soon();
diff --git a/src/snap.cpp b/src/snap.cpp
index b3368a1..c2cbc0a 100644
--- a/src/snap.cpp
+++ b/src/snap.cpp
@@ -94,7 +94,16 @@ public:
b.add_hint (uin::Builder::HINT_TINT);
b.add_hint (uin::Builder::HINT_NONSHAPEDICON);
- const auto timefmt = is_locale_12h() ? _("%a, %l:%M %p") : _("%a, %H:%M");
+ const char * timefmt;
+ if (is_locale_12h()) {
+ /** strftime(3) format for abbreviated weekday,
+ hours, minutes in a 12h locale; e.g. Wed, 2:00 PM */
+ timefmt = _("%a, %l:%M %p");
+ } else {
+ /** A strftime(3) format for abbreviated weekday,
+ hours, minutes in a 24h locale; e.g. Wed, 14:00 */
+ timefmt = _("%a, %H:%M");
+ }
const auto timestr = appointment.begin.format(timefmt);
auto title = g_strdup_printf(_("Alarm %s"), timestr.c_str());
b.set_title (title);
diff --git a/tests/manual b/tests/manual
index e9f858e..87ad674 100644
--- a/tests/manual
+++ b/tests/manual
@@ -22,6 +22,13 @@ Test-case indicator-datetime/unity8-items-check
<dd>The menu is populated with items</dd>
</dl>
+Test-case indicator-datetime/timestamp-wakeup
+<dl>
+ <dt>Unplug the phone from any USB connection and put it to sleep</dt>
+ <dd>Reawaken the device.</dt>
+ <dd>The indicator should be showing the correct time.</dd>
+</dl>
+
Test-case indicator-datetime/new-alarm-wakeup
<dl>
<dt>Create and save an upcoming alarm in ubuntu-clock-app</dt>
@@ -33,6 +40,15 @@ Test-case indicator-datetime/new-alarm-wakeup
<dd>If the device supports haptic feedback, confirm the alarm vibrates.</dd>
</dl>
+Test-case indicator-datetime/alarm-timezone
+<dl>
+ <dt>In ubuntu-system-settings, change your timezone to a zone you're not in</dt>
+ <dt>In ubuntu-clock-app, create and save an upcoming alarm</dt>
+ <dd>The indicator's menu should show the alarm to click at the specified time</dd>
+ <dt>In ubuntu-system-settings, change back to your correct timezone</dt>
+ <dd>The indicator's menu should still show the alarm to click at the specified time</dd>
+</dl>
+
Test-case indicator-datetime/snooze
<dl>
<dt>Create and save an upcoming alarm in ubuntu-clock-app</dt>
diff --git a/tests/test-clock.cpp b/tests/test-clock.cpp
index 82f8cb0..5601d35 100644
--- a/tests/test-clock.cpp
+++ b/tests/test-clock.cpp
@@ -18,9 +18,13 @@
*/
#include <datetime/clock.h>
-#include <datetime/timezones.h>
+#include <datetime/clock-mock.h>
+#include <datetime/timezone.h>
+
+#include <notifications/dbus-shared.h>
#include "test-dbus-fixture.h"
+#include "timezone-mock.h"
/***
****
@@ -37,9 +41,9 @@ class ClockFixture: public TestDBusFixture
TEST_F(ClockFixture, MinuteChangedSignalShouldTriggerOncePerMinute)
{
// start up a live clock
- std::shared_ptr<Timezones> zones(new Timezones);
- zones->timezone.set("America/New_York");
- LiveClock clock(zones);
+ auto timezone_ = std::make_shared<MockTimezone>();
+ timezone_->timezone.set("America/New_York");
+ LiveClock clock(timezone_);
wait_msec(500); // wait for the bus to set up
// count how many times clock.minute_changed() is emitted over the next minute
@@ -62,17 +66,17 @@ TEST_F(ClockFixture, MinuteChangedSignalShouldTriggerOncePerMinute)
TEST_F(ClockFixture, HelloFixture)
{
- std::shared_ptr<Timezones> zones(new Timezones);
- zones->timezone.set("America/New_York");
- LiveClock clock(zones);
+ auto timezone_ = std::make_shared<MockTimezone>();
+ timezone_->timezone.set("America/New_York");
+ LiveClock clock(timezone_);
}
TEST_F(ClockFixture, TimezoneChangeTriggersSkew)
{
- std::shared_ptr<Timezones> zones(new Timezones);
- zones->timezone.set("America/New_York");
- LiveClock clock(zones);
+ auto timezone_ = std::make_shared<MockTimezone>();
+ timezone_->timezone.set("America/New_York");
+ LiveClock clock(timezone_);
auto tz_nyc = g_time_zone_new("America/New_York");
auto now_nyc = g_date_time_new_now(tz_nyc);
@@ -87,9 +91,9 @@ TEST_F(ClockFixture, TimezoneChangeTriggersSkew)
g_main_loop_quit(loop);
});
g_idle_add([](gpointer gs){
- static_cast<Timezones*>(gs)->timezone.set("America/Los_Angeles");
+ static_cast<Timezone*>(gs)->timezone.set("America/Los_Angeles");
return G_SOURCE_REMOVE;
- }, zones.get());
+ }, timezone_.get());
g_main_loop_run(loop);
auto tz_la = g_time_zone_new("America/Los_Angeles");
@@ -127,9 +131,9 @@ namespace
*/
TEST_F(ClockFixture, SleepTriggersSkew)
{
- std::shared_ptr<Timezones> zones(new Timezones);
- zones->timezone.set("America/New_York");
- LiveClock clock(zones);
+ auto timezone_ = std::make_shared<MockTimezone>();
+ timezone_->timezone.set("America/New_York");
+ LiveClock clock(timezone_);
wait_msec(250); // wait for the bus to set up
bool skewed = false;
@@ -152,3 +156,61 @@ TEST_F(ClockFixture, SleepTriggersSkew)
g_bus_unown_name(name_tag);
}
+
+namespace
+{
+ void on_powerd_name_acquired(GDBusConnection * /*connection*/,
+ const gchar * /*name*/,
+ gpointer is_owned)
+ {
+ *static_cast<bool*>(is_owned) = true;
+ }
+}
+
+/**
+ * Confirm that powerd's SysPowerStateChange triggers
+ * a timestamp change
+ */
+TEST_F(ClockFixture, SysPowerStateChange)
+{
+ // set up the mock clock
+ bool minute_changed = false;
+ auto clock = std::make_shared<MockClock>(DateTime::NowLocal());
+ clock->minute_changed.connect([&minute_changed]() {
+ minute_changed = true;
+ });
+
+ // control test -- minute_changed shouldn't get triggered
+ // when the clock is silently changed
+ gboolean is_owned = false;
+ auto tag = g_bus_own_name_on_connection(system_bus,
+ BUS_POWERD_NAME,
+ G_BUS_NAME_OWNER_FLAGS_NONE,
+ on_powerd_name_acquired,
+ nullptr,
+ &is_owned /* user_data */,
+ nullptr /* user_data closure */);
+ const DateTime not_now {DateTime::Local(1999, 12, 31, 23, 59, 59)};
+ clock->set_localtime_quietly(not_now);
+ wait_msec();
+ ASSERT_TRUE(is_owned);
+ ASSERT_FALSE(minute_changed);
+
+ // now for the actual test,
+ // confirm that SysPowerStateChange triggers a minute_changed() signal
+ GError * error = nullptr;
+ auto emitted = g_dbus_connection_emit_signal(system_bus,
+ nullptr,
+ BUS_POWERD_PATH,
+ BUS_POWERD_INTERFACE,
+ "SysPowerStateChange",
+ g_variant_new("(i)", 1),
+ &error);
+ wait_msec();
+ EXPECT_TRUE(emitted);
+ EXPECT_EQ(nullptr, error);
+ EXPECT_TRUE(minute_changed);
+
+ // cleanup
+ g_bus_unown_name(tag);
+}