Merge lp:~mterry/unity8/shutdown-dialog-on-resume into lp:unity8

Proposed by Michael Terry
Status: Merged
Approved by: Michael Terry
Approved revision: 2009
Merged at revision: 2035
Proposed branch: lp:~mterry/unity8/shutdown-dialog-on-resume
Merge into: lp:unity8
Diff against target: 179 lines (+51/-36)
5 files modified
plugins/Utils/windowkeysfilter.cpp (+15/-1)
plugins/Utils/windowkeysfilter.h (+7/-0)
qml/Components/PhysicalKeysMapper.qml (+16/-23)
qml/Shell.qml (+2/-2)
tests/qmltests/Components/tst_PhysicalKeysMapper.qml (+11/-10)
To merge this branch: bzr merge lp:~mterry/unity8/shutdown-dialog-on-resume
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Needs Fixing
Albert Astals Cid (community) Approve
Michael Zanetti (community) Needs Information
Review via email: mp+275240@code.launchpad.net

Commit message

Avoid showing the shutdown dialog when turning on the screen if your device is under heavy load.

Specifically, we actually watch the timestamp of input events as they come in to determine how long it's been. This means that if for whatever reason, processing of events get delayed, we don't misinterpret user input.

To test this, try running the following command and then turning the screen on and off again:
sudo cpulimit -l 1 -c 1 -p `ps ax | grep dbus-daemon | head -n 1 | awk '{print $1;}'`

Without this branch, you'll notice that at some point, you see the shutdown dialog in error. Because unity8 couldn't keep up with events and thought 2s passed between power-pressed and power-released events.

But if we watch the timestamps, we can avoid that particular fate.

Description of the change

* Are there any related MPs required for this MP to build/function as expected? Please list.
 https://code.launchpad.net/~unity-team/qtmir/1510571.ms-timestamp-compression/+merge/276112

 * Did you perform an exploratory manual test run of your code change and any related functionality?
 Yes

 * Did you make sure that your branch does not contain spurious tags?
 Yes

 * If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
 NA

 * If you changed the UI, has there been a design review?
 NA

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:2005
http://jenkins.qa.ubuntu.com/job/unity8-ci/6507/
Executed test runs:
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-vivid-touch/4754
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-wily-touch/889
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity-phablet-qmluitests-vivid/1219
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity-phablet-qmluitests-wily/535
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-amd64-ci/1114
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-i386-ci/1115
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-wily-amd64-ci/746
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-wily-i386-ci/747
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-vivid-mako/3837
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/4751
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/4751/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/24444
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-wily-mako/526
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-wily-armhf/889
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-wily-armhf/889/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/24443

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/unity8-ci/6507/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Michael Terry (mterry) wrote :

Another option would be to expose the timestamp() value of the current event through to Qml and then use the timestamp of the autorepeated events to determine when two seconds have passed. If we don't trust the interval timing of the autorepeated events.

Revision history for this message
Albert Astals Cid (aacid) wrote :

property int powerKeyLongPressCount: 31 // about 2s
is something that depends on QStyleHints::keyboardAutoRepeatRate() and other things, those will probably won't change, but maybe we can add a test that actually checks that pressing and holidng the button triggers the dialog and takes between 1.5 and 2.5 seconds? just in case this varies wildly in the future with some update and we don't realize?

What do you think?

review: Needs Information
Revision history for this message
Michael Zanetti (mzanetti) wrote :

Very nice! This seems to work properly now.

 * Did you perform an exploratory manual test run of the code change and any related functionality?

yes

 * Did CI run pass? If not, please explain why.

The one AP failure seems not related to this.

 * Did you make sure that the branch does not contain spurious tags?

yes

review: Approve
Revision history for this message
Michael Zanetti (mzanetti) wrote :

Oh, missed alberts comment. Yes, fair point... I was also thinking if API wise it wouldn't make sense to still specify it in ms, and internally divide the time into repeat-counts...

Revision history for this message
Michael Terry (mterry) wrote :

Ah great! I didn't know about QStyleHints::keyboardAutoRepeatRate(). Will specify time in ms in "API" and internally count ticks then.

Revision history for this message
Albert Astals Cid (aacid) wrote :

Note that before QStyleHints::keyboardAutoRepeatRate() there's another timeout for the first autorepeat to trigger, i don't know if there's a value for it or is hardcoded, worth investigating.

Revision history for this message
Michael Terry (mterry) wrote :

Ugh. keyboardAutoRepeatRate gives 30. Which is how many events happen per second. So 1000ms/30=33.3ms per autorepeat event. But that's not what I'm seeing. I'm seeing more like 40ms to 50ms.

And keyboardInputInterval *might* be the value used before Qt starts sending autorepeat events. It's not entirely clear if they use it for that. Which is 400ms for me. But I'm seeing a delay of 500ms.

So... I can't trust those values. But knowing that they exist, I'm not comfortable ignoring the settings either, like this MP does. I might look at using exposing event timestamps to Qml and comparing those as a more reliable strategy.

Revision history for this message
Michael Zanetti (mzanetti) :
review: Needs Information
Revision history for this message
Michael Terry (mterry) wrote :

OK, I've reworked this to use timestamps. Seems to work for me.

2008. By Michael Terry

remove an obsolete code change

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:2008
http://jenkins.qa.ubuntu.com/job/unity8-ci/6521/
Executed test runs:
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-vivid-touch/4779
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-wily-touch/904
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity-phablet-qmluitests-vivid/1233
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity-phablet-qmluitests-wily/549
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-amd64-ci/1128
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-i386-ci/1129
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-wily-amd64-ci/760
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-wily-i386-ci/761
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-vivid-mako/3852
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/4776
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/4776/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/24485
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-wily-mako/533
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-wily-armhf/904
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-wily-armhf/904/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/24486

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/unity8-ci/6521/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Albert Astals Cid (aacid) wrote :

It's weird because in r1942 i fixed a problem with pressing the power off button while the screen was off in which the first event we got was already an autorepeat.

From reading the code this would not work here, we would not set d.powerButtonPressStart but then i tried it and it seems to work, not sure if it's becuase i'm trying the Meizu vs the bq (that i don't have at hand right now) or something else changed.

I'll try testing the bq this afternoon.

Revision history for this message
Albert Astals Cid (aacid) wrote :

Tried with the bq and it also works fine, no idea what changed but nothing against from my side.

Revision history for this message
Albert Astals Cid (aacid) wrote :

 * Did you perform an exploratory manual test run of the code change and any related functionality?
Yes

 * Did CI run pass? If not, please explain why.
enough

 * Did you make sure that the branch does not contain spurious tags?
Yes

review: Approve
2009. By Michael Terry

Merge from trunk

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Michael Terry (mterry) wrote :

Reports of this being unreliable seem true. Looks like Qt timestamps behave oddly. Am looking into it.

Revision history for this message
Michael Terry (mterry) wrote :

The unreliability was due to bug 1511076. Using branch https://code.launchpad.net/~mterry/qtmir/ms-compressed-timestamps/+merge/276048 fixes the problem in my testing. Will set this back to Approved, since no changes were required to this branch.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'plugins/Utils/windowkeysfilter.cpp'
--- plugins/Utils/windowkeysfilter.cpp 2014-09-08 15:07:24 +0000
+++ plugins/Utils/windowkeysfilter.cpp 2015-10-27 14:54:18 +0000
@@ -21,7 +21,8 @@
21#include <QQuickWindow>21#include <QQuickWindow>
2222
23WindowKeysFilter::WindowKeysFilter(QQuickItem *parent)23WindowKeysFilter::WindowKeysFilter(QQuickItem *parent)
24 : QQuickItem(parent)24 : QQuickItem(parent),
25 m_currentEventTimestamp(0)
25{26{
26 connect(this, &QQuickItem::windowChanged,27 connect(this, &QQuickItem::windowChanged,
27 this, &WindowKeysFilter::setupFilterOnWindow);28 this, &WindowKeysFilter::setupFilterOnWindow);
@@ -36,7 +37,15 @@
36 if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) {37 if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) {
37 // Let QML see this event and decide if it does not want it38 // Let QML see this event and decide if it does not want it
38 event->accept();39 event->accept();
40
41 m_currentEventTimestamp = static_cast<QInputEvent*>(event)->timestamp();
42 Q_EMIT currentEventTimestampChanged();
43
39 QCoreApplication::sendEvent(this, event);44 QCoreApplication::sendEvent(this, event);
45
46 m_currentEventTimestamp = 0;
47 Q_EMIT currentEventTimestampChanged();
48
40 return event->isAccepted();49 return event->isAccepted();
41 } else {50 } else {
42 // Not interested51 // Not interested
@@ -56,3 +65,8 @@
56 m_filteredWindow = window;65 m_filteredWindow = window;
57 }66 }
58}67}
68
69ulong WindowKeysFilter::currentEventTimestamp() const
70{
71 return m_currentEventTimestamp;
72}
5973
=== modified file 'plugins/Utils/windowkeysfilter.h'
--- plugins/Utils/windowkeysfilter.h 2015-04-30 09:31:51 +0000
+++ plugins/Utils/windowkeysfilter.h 2015-10-27 14:54:18 +0000
@@ -36,16 +36,23 @@
36class WindowKeysFilter : public QQuickItem36class WindowKeysFilter : public QQuickItem
37{37{
38 Q_OBJECT38 Q_OBJECT
39 Q_PROPERTY(ulong currentEventTimestamp READ currentEventTimestamp NOTIFY currentEventTimestampChanged)
39public:40public:
40 WindowKeysFilter(QQuickItem *parent = 0);41 WindowKeysFilter(QQuickItem *parent = 0);
4142
42 bool eventFilter(QObject *watched, QEvent *event) override;43 bool eventFilter(QObject *watched, QEvent *event) override;
4344
45 ulong currentEventTimestamp() const;
46
47Q_SIGNALS:
48 void currentEventTimestampChanged();
49
44private Q_SLOTS:50private Q_SLOTS:
45 void setupFilterOnWindow(QQuickWindow *window);51 void setupFilterOnWindow(QQuickWindow *window);
4652
47private:53private:
48 QPointer<QQuickWindow> m_filteredWindow;54 QPointer<QQuickWindow> m_filteredWindow;
55 ulong m_currentEventTimestamp;
49};56};
5057
51#endif // UNITY_WINDOWKEYSFILTER_H58#endif // UNITY_WINDOWKEYSFILTER_H
5259
=== modified file 'qml/Components/PhysicalKeysMapper.qml'
--- qml/Components/PhysicalKeysMapper.qml 2015-09-02 09:30:32 +0000
+++ qml/Components/PhysicalKeysMapper.qml 2015-10-27 14:54:18 +0000
@@ -57,27 +57,20 @@
5757
58 property bool altPressed: false58 property bool altPressed: false
59 property bool altTabPressed: false59 property bool altTabPressed: false
60 }60
6161 property var powerButtonPressStart: 0
62 Timer {62 }
63 id: powerKeyLongPressTimer63
64 interval: root.powerKeyLongPressTime64 function onKeyPressed(event, currentEventTimestamp) {
65 onTriggered: root.powerKeyLongPressed();65 if (event.key == Qt.Key_PowerDown || event.key == Qt.Key_PowerOff) {
66 }66 if (event.isAutoRepeat) {
6767 if (d.powerButtonPressStart > 0
68 function onKeyPressed(event) {68 && currentEventTimestamp - d.powerButtonPressStart >= powerKeyLongPressTime) {
69 if ((event.key == Qt.Key_PowerDown || event.key == Qt.Key_PowerOff)69 d.powerButtonPressStart = 0;
70 && (!event.isAutoRepeat || !powerKeyLongPressTimer.running)) {70 root.powerKeyLongPressed();
7171 }
72 // FIXME: We only consider power key presses if the screen is72 } else {
73 // on because of bugs 1410830/1409003. The theory is that when73 d.powerButtonPressStart = currentEventTimestamp;
74 // those bugs are encountered, there is a >2s delay between the
75 // power press event and the power release event, which causes
76 // the shutdown dialog to appear on resume. So to avoid that
77 // symptom while we investigate the root cause, we simply won't
78 // initiate any dialogs when the screen is off.
79 if (Powerd.status === Powerd.On) {
80 powerKeyLongPressTimer.restart();
81 }74 }
82 } else if ((event.key == Qt.Key_MediaTogglePlayPause || event.key == Qt.Key_MediaPlay) && !event.isAutoRepeat) {75 } else if ((event.key == Qt.Key_MediaTogglePlayPause || event.key == Qt.Key_MediaPlay) && !event.isAutoRepeat) {
83 event.accepted = callManager.handleMediaKey(false);76 event.accepted = callManager.handleMediaKey(false);
@@ -113,9 +106,9 @@
113 }106 }
114 }107 }
115108
116 function onKeyReleased(event) {109 function onKeyReleased(event, currentEventTimestamp) {
117 if (event.key == Qt.Key_PowerDown || event.key == Qt.Key_PowerOff) {110 if (event.key == Qt.Key_PowerDown || event.key == Qt.Key_PowerOff) {
118 powerKeyLongPressTimer.stop();111 d.powerButtonPressStart = 0;
119 event.accepted = true;112 event.accepted = true;
120 } else if (event.key == Qt.Key_VolumeDown) {113 } else if (event.key == Qt.Key_VolumeDown) {
121 if (!d.ignoreVolumeEvents) root.volumeDownTriggered();114 if (!d.ignoreVolumeEvents) root.volumeDownTriggered();
122115
=== modified file 'qml/Shell.qml'
--- qml/Shell.qml 2015-10-16 17:11:54 +0000
+++ qml/Shell.qml 2015-10-27 14:54:18 +0000
@@ -172,8 +172,8 @@
172 }172 }
173173
174 WindowKeysFilter {174 WindowKeysFilter {
175 Keys.onPressed: physicalKeysMapper.onKeyPressed(event);175 Keys.onPressed: physicalKeysMapper.onKeyPressed(event, currentEventTimestamp);
176 Keys.onReleased: physicalKeysMapper.onKeyReleased(event);176 Keys.onReleased: physicalKeysMapper.onKeyReleased(event, currentEventTimestamp);
177 }177 }
178178
179 HomeKeyWatcher {179 HomeKeyWatcher {
180180
=== modified file 'tests/qmltests/Components/tst_PhysicalKeysMapper.qml'
--- tests/qmltests/Components/tst_PhysicalKeysMapper.qml 2015-09-15 12:05:17 +0000
+++ tests/qmltests/Components/tst_PhysicalKeysMapper.qml 2015-10-27 14:54:18 +0000
@@ -67,25 +67,26 @@
67 Powerd.setStatus(data.status, Powerd.Unknown);67 Powerd.setStatus(data.status, Powerd.Unknown);
68 physicalKeysMapper.powerKeyLongPressTime = 500;68 physicalKeysMapper.powerKeyLongPressTime = 500;
6969
70 physicalKeysMapper.onKeyPressed({ key: Qt.Key_PowerDown, isAutoRepeat: false });70 physicalKeysMapper.onKeyPressed({ key: Qt.Key_PowerDown, isAutoRepeat: false }, 100);
7171
72 // After the first key press the screen is always on72 // After the first key press the screen is always on
73 // and the rest of keypresses are auto repeat73 // and the rest of keypresses are auto repeat
74 Powerd.setStatus(Powerd.On, Powerd.Unknown);74 Powerd.setStatus(Powerd.On, Powerd.Unknown);
7575
76 for (var i = 0; i < 3; ++i) {76 physicalKeysMapper.onKeyPressed({ key: Qt.Key_PowerDown, isAutoRepeat: true}, 300);
77 wait(10);77 physicalKeysMapper.onKeyPressed({ key: Qt.Key_PowerDown, isAutoRepeat: true}, 400);
78 physicalKeysMapper.onKeyPressed({ key: Qt.Key_PowerDown, isAutoRepeat: true});78 physicalKeysMapper.onKeyPressed({ key: Qt.Key_PowerDown, isAutoRepeat: true}, 500);
79 }79 physicalKeysMapper.onKeyPressed({ key: Qt.Key_PowerDown, isAutoRepeat: true}, 599);
8080
81 // powerKeyLongPressed should not have been emitted yet.81 // powerKeyLongPressed should not have been emitted yet.
82 compare(powerSpy.count, 0);82 compare(powerSpy.count, 0);
8383
84 for (var i = 0; i < 10; ++i) {84 physicalKeysMapper.onKeyPressed({ key: Qt.Key_PowerDown, isAutoRepeat: true}, 600);
85 wait(50);85
86 physicalKeysMapper.onKeyPressed({ key: Qt.Key_PowerDown, isAutoRepeat: true});86 compare(powerSpy.count, 1);
87 }87
8888 // Confirm we only emit once
89 physicalKeysMapper.onKeyPressed({ key: Qt.Key_PowerDown, isAutoRepeat: true}, 601);
89 compare(powerSpy.count, 1);90 compare(powerSpy.count, 1);
90 }91 }
9192

Subscribers

People subscribed via source and target branches