Merge lp:~josharenson/unity8/physical_keys_filter into lp:unity8

Proposed by Josh Arenson on 2014-12-10
Status: Superseded
Proposed branch: lp:~josharenson/unity8/physical_keys_filter
Merge into: lp:unity8
Diff against target: 404 lines (+216/-120)
6 files modified
qml/Components/Dialogs.qml (+4/-24)
qml/Components/PhysicalKeysMapper.qml (+114/-0)
qml/Components/VolumeKeyFilter.qml (+0/-63)
qml/Shell.qml (+12/-33)
tests/qmltests/CMakeLists.txt (+1/-0)
tests/qmltests/Components/tst_PhysicalKeysMapper.qml (+85/-0)
To merge this branch: bzr merge lp:~josharenson/unity8/physical_keys_filter
Reviewer Review Type Date Requested Status
Albert Astals Cid (community) 2014-12-10 Needs Fixing on 2015-02-16
Daniel d'Andrada (community) codewise Approve on 2015-02-13
PS Jenkins bot continuous-integration Approve on 2015-02-12
kevin gunn (community) testing Approve on 2015-02-02
Michał Sawicz ux Needs Fixing on 2015-01-13
Review via email: mp+244244@code.launchpad.net

This proposal has been superseded by a proposal from 2015-02-16.

Commit Message

Create a PhysicalKeyMapper to handle all physical/hardware keys

In addition, change the key combination for taking a screenshot from (Volume Up + Volume Down) to (Power + Volume Down).

Description of the Change

* Are there any related MPs required for this MP to build/function as expected? Please list.

   Yes,

https://code.launchpad.net/~josharenson/unity-system-compositor/handle_screenshot_button

 * 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?

N/A

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

No, should there be?

Create a PhysicalKeyFilter to handle all physical/hardware keys on a mobile device. In addition, change the key combination for taking a screenshot from (Volume Up + Volume Down) to (Power + Volume Down).

--fixes lp:1390393

To post a comment you must log in.
Albert Astals Cid (aacid) wrote :

The else ifs need to be written in our style

} else if (volumeDownKeyPressed) {

instead of

}
else if (volumeDownKeyPressed) {

review: Needs Fixing
Albert Astals Cid (aacid) wrote :

Something is wrong with the power button, after i press it to bring the phone back from sleep i always end up getting the shutdown dialog.

review: Needs Fixing
Daniel d'Andrada (dandrader) wrote :

8 + * Authors:
9 + * Josh Arenson <email address hidden>

Better leave that out as this info gets quickly outdated overtime, as the code gets modified. bzr/git history does a better job at that.

Daniel d'Andrada (dandrader) wrote :

Please follow the MP submission checklist regarding the commit message:
https://wiki.ubuntu.com/Process/Merges/Checklists/Unity8

Daniel d'Andrada (dandrader) wrote :

> Please follow the MP submission checklist regarding the commit message:
> https://wiki.ubuntu.com/Process/Merges/Checklists/Unity8

Also the "--fixes lp:1390393" line is not necessary as CI will automatically add it when merging the branch.

Daniel d'Andrada (dandrader) wrote :

If you're really going to make PhysicalKeysFilter also handle higher level things such as key mappings as you're doing for the screenshot, you should also absorb the code from Dialogs.qml that handles long power key press detection.

review: Needs Fixing
Daniel d'Andrada (dandrader) wrote :

> If you're really going to make PhysicalKeysFilter also handle higher level
> things such as key mappings as you're doing for the screenshot, you should
> also absorb the code from Dialogs.qml that handles long power key press
> detection.

In that tone, I might be better to call it a key mapper instead of a key filter.

Josh Arenson (josharenson) wrote :

> Something is wrong with the power button, after i press it to bring the phone
> back from sleep i always end up getting the shutdown dialog.

I will look into this, but it sounds like lp:1383277

Daniel d'Andrada (dandrader) wrote :

In qml/Shell.qml

"""
    Dialogs {
        ...
        Connections {
            target: physicalKeysMapper
            onPowerKeyLongPress: dialogs.showPowerDialog();
        }
        ...
    }
"""

Why not put the onPowerKeyLongPress line directly into PhysicalKeysMapper, like it's done for all other connections?

-----------------

In qml/Components/Dialogs.qml

"""
    property bool dialogShown: false
"""

That should still be inside a QtObject { id: d } wrapper as it's still a private property (ie, not meant to be seem or used outside Dialogs.qml)

--------------------

In qml/Components/PhysicalKeysMapper.qml

"""
    property bool eventAccepted: false

    ...

    function onKeyPressed(key) {
        ...
            eventAccepted = true;
        ...
            eventAccepted = true;
        ...
            eventAccepted = true;
        ...
        return eventAccepted;
    }

    function onKeyReleased(key) {
        ...
            eventAccepted = true;
        ...
            eventAccepted = true;
        ...
            eventAccepted = true;
        ...
        return inadvertently;
    }

"""

You init eventAccepted to false but once it's been set to true it will never come back to false again.
Meaning that you're inadvertently telling WindowKeysFilter to filter out *all* key events, so no application will ever get a physical key event again. This is a bug.

eventAccepted should not be a property but a internal variable of those funtioncs, like this:

"""
    function onKeyPressed(key) {
        var eventAccepted = false;
        ...
            eventAccepted = true;
        ...
            eventAccepted = true;
        ...
            eventAccepted = true;
        ...
        return eventAccepted;
    }
"""

--------------------

In qml/Components/PhysicalKeysMapper.qml

"""
        } else if (key == Qt.Key_VolumeDown) {
            eventAccepted = true;
            volumeDownKeyPressed = true;
        } else if (key == Qt.Key_VolumeUp) {
            eventAccepted = true;
            volumeUpKeyPressed = true;
        }
"""

Volume keys should *not* be accepted. Check the original code in Shell.qml.
If you accept them you're telling WindowKeysFilter to filter them out, so they won't get dispatched to the focused item in the qml scene (eg: the MirSurfaceItem of the focused app), meaning that apps won't get volume key events anymore. Check the documentation in plugins/Utils/windowkeysfilter.h

Volume keys are special in which we want both unity8 and the focused app to process them, unlike the power key, which should be processed only by unity8.

--------------------

In qml/Components/PhysicalKeysMapper.qml

"""
    property bool aPowerKeyWasReleased: true
    property bool powerKeyPressed: false

    property bool aVolumeKeyWasReleased: true
    property bool volumeDownKeyPressed: false
    property bool volumeUpKeyPressed: false
"""

Could you please wrap those properties in a "property QtObject d: QtObject { id: d }" as they're private?

review: Needs Fixing
Albert Astals Cid (aacid) wrote :

Daniel's handling the review

review: Abstain
Daniel d'Andrada (dandrader) wrote :

In qml/Components/PhysicalKeysMapper.qml

"""
    signal bothVolumeKeysPressed();
"""

This signal is dead code as it's not being used in Shell.qml (since the screeshot is now power+volumeDown as has its own "virtual" key). Please remove it.

By the way, what's the rationale for changing the key combination of the screenshot? Which is all the more curious given that comment: https://bugs.launchpad.net/ubuntu/+source/unity8/+bug/1390393/comments/5

Daniel d'Andrada (dandrader) wrote :

Again on this eventAccepted thing: I was thinking we could remove it entirely from PhysicalKeysMapper and keep the accept/reject decision making in the WindowKeysFilter functions in Shell.qml, as they currently are. That way you clearly separate the mapping from the filtering logic and keep the filtering logic close to the item that actually does the filtering, which is WindowKeysFilter.

key mapping and event filtering are clearly two separate, independent tasks.

Daniel d'Andrada (dandrader) wrote :

The PhysicalKeysMapper test requires no GUI, so it should belong to qmlunittests, not qmluitests.

Tests that require no GUI are run by "make test" and are also run when building the debian packages.

This diff shows how to make it a GUI-less test:
http://paste.ubuntu.com/9474472/

review: Needs Fixing
Daniel d'Andrada (dandrader) wrote :

The convention we've been using for test names is test_fooBar, not test_foo_bar.

Josh Arenson (josharenson) wrote :

> In qml/Components/PhysicalKeysMapper.qml
>
> """
> signal bothVolumeKeysPressed();
> """
>
> This signal is dead code as it's not being used in Shell.qml (since the
> screeshot is now power+volumeDown as has its own "virtual" key). Please remove
> it.
>
> By the way, what's the rationale for changing the key combination of the
> screenshot? Which is all the more curious given that comment:
> https://bugs.launchpad.net/ubuntu/+source/unity8/+bug/1390393/comments/5

Had a lengthy discussion w/ mzanetti and AlbertA (and a bit w/ saviq) about this. Decided that this was the way to go. It _does_ resolve the bug, and I see no real architectural issues.

Daniel d'Andrada (dandrader) wrote :

PhysicalKeysMapper is still among the tests that require a GUI. The position where you put it in tests/qmltests/CMakeLists.txt matters. It should be right below this line:

"""
add_qml_test(utils/Unity/Test UnityTest)
"""

As it will get covered by this line:
"""
set(qmltest_DEFAULT_PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=minimal")
"""
which makes it use the minimal QPA plugin, which does not have display output.

-------------------

You still didn't make (or said anything about) the Dialog changes I asked here:
https://code.launchpad.net/~josharenson/unity8/physical_keys_filter/+merge/244244/comments/602555

review: Needs Fixing
Albert Astals Cid (aacid) wrote :

Text conflict in qml/Components/Dialogs.qml
1 conflicts encountered.

Daniel d'Andrada (dandrader) wrote :

Approving as the last couple of issues have been addressed.

review: Approve
Michał Sawicz (saviq) wrote :

This is not enough, now I'm just getting screenshots of the greeter unless I hold the power key long enough for the screenshot to be taken.

You'll need to suppress the suspend code in unity-system-compositor if volume down was pressed while power was pressed.

review: Needs Fixing (ux)
Josh Arenson (josharenson) wrote :

I think this introduces a circular dependency.

Case 1 - power key is pressed first:
USC suspends phone

Case 2 - volume key is pressed first:
Unity displays volume dialog which shows up in all screenshots

There is no way to satisfy everyone without introducing a delay

Michał Sawicz (saviq) wrote :

Sure there is, USC needs to suppress suspending the phone if voldown is pressed while power is pressed.

Michał Sawicz (saviq) wrote :

Don't get me wrong, the split in handling those keys between unity8 and usc is something we need to fix, but before we get there, USC needs to gain some knowledge on what unity8 does (as it already does have the knowledge for power long-press - it doesn't suspend, it wakes if suspended, even).

Josh Arenson (josharenson) wrote :

> Don't get me wrong, the split in handling those keys between unity8 and usc is
> something we need to fix, but before we get there, USC needs to gain some
> knowledge on what unity8 does (as it already does have the knowledge for power
> long-press - it doesn't suspend, it wakes if suspended, even).

Working on a USC change that handles the following state
if (power_down && volume_down)
   disable_suspend()
if (power_up)
   enable_suspend()

I suppose I was thinking that suspend happens on power key pressed, but it should happen on power key released.

Albert Astals Cid (aacid) wrote :

Text conflict in qml/Shell.qml
1 conflicts encountered.

kevin gunn (kgunn72) wrote :

meant to set "needs fixing"

review: Needs Fixing
kevin gunn (kgunn72) wrote :

forgot to mark this as approved per testing

review: Approve (testing)
Daniel d'Andrada (dandrader) wrote :

"""
8 + function onKeyPressed(key) {
119 + var eventAccepted = true;
120 +
121 + /* Determine what key was pressed */
122 + if (key == Qt.Key_PowerDown || key == Qt.Key_PowerOff) {
123 +
124 + // FIXME: We only consider power key presses if the screen is
125 + // on because of bugs 1410830/1409003. The theory is that when
126 + // those bugs are encountered, there is a >2s delay between the
127 + // power press event and the power release event, which causes
128 + // the shutdown dialog to appear on resume. So to avoid that
129 + // symptom while we investigate the root cause, we simply won't
130 + // initiate any dialogs when the screen is off.
131 + // This also prevents taking screenshots when the screen is off.
132 + if (Powerd.status === Powerd.On) {
133 + if (!powerKeyLongPressTimer.running) {
134 + powerKeyLongPressTimer.restart();
135 + }
136 + d.powerKeyPressed = true;
137 + }
138 + } else if (key == Qt.Key_MediaTogglePlayPause || key == Qt.Key_MediaPlay) {
139 + eventAccepted = callManager.handleMediaKey(false);
140 + } else if (key == Qt.Key_VolumeDown) {
141 + d.volumeDownKeyPressed = true;
142 + } else if (key == Qt.Key_VolumeUp) {
143 + d.volumeUpKeyPressed = true;
144 + } else {
145 + eventAccepted = false;
146 + }
"""

As I told before, volume keys should not be filtered out.

In this code, you're filtering them out (eventAccepted will be true for them).

You might consider renaming eventAccepted to something like filterOutEvent to make more explicit what the return value actually does.

review: Needs Fixing
Daniel d'Andrada (dandrader) wrote :

Having both aPowerKeyWasReleased and powerKeyPressed smelled fishy to me. So I had a go at making the code more declarative. It does seem to simplify and clarify PhysicalKeysMapper logic:

http://paste.ubuntu.com/10176638/

What do you think? It also has the benefit of making PhysicalKeysMapper interface more QMLish.
Eg: MouseArea has pressed property, not a pressed() signal.

Josh Arenson (josharenson) wrote :

Addressed issues that were discussed on IRC as per #1507 and #1508

Daniel d'Andrada (dandrader) wrote :

Looks good.

Non-blockers:

In test_LongPressPowerButton(), could you please check that powerKeyLongPress() only gets emited *after* the timeout?

like this:

"""
compare(onPowerKeyLongPressCount, 0);
wait(physicalKeysMapper.powerKeyLongPressTimeMs * 2);
compare(onPowerKeyLongPressCount, 1);
"""

review: Approve
review: Approve (codewise)
Daniel d'Andrada (dandrader) wrote :

* Did you perform an exploratory manual test run of the code change and any related functionality?
No, but kgunn did.

* Did CI run pass? If not, please explain why.
Yes! All green!

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

Albert Astals Cid (aacid) wrote :

Relaying Saviq's comment over mail

*****
Ugh, I just realized that we might have needlessly changed the screenshot shortcut and made
lives hard for ourselves.

We need not have involved u-s-c if we kept the screenshot combination to
be vol+-, and since we've switched to reacting onReleased instead of
onPressed, we could have done the same with volume buttons...
The other thing that came to mind is that we need to verify that
long-press behaviour is still fine. Albert just checked and long-press
is broken.

Josh, when you're around, could you have a look at going back to vol+-
as the screenshot shortcut, and fixing the above. Have a look at
.isAutoRepeat of a key event to enable that.
*****

review: Needs Fixing
Josh Arenson (josharenson) wrote :

Can you please clarify what actions should trigger a screenshot, and which actions should trigger a volume event?

This is the order that I would assume

1. PressDecrease + PressIncrease = ScreenShot
2. PressDecrease + Release Decrease = Volume Down
3. PressIncrease + Release Increase = Volume Up
4. PressAndHoldIncrease (exclusive) = VolumeUp @ KeyRepeat Interval
5. PressAndHoldDecrease (exclusive) = VolumeDown @ KeyRepeat Interval

I have an issue with 2 & 3 (not receiving instant feedback on a volume button press). Also, should there be a delay for step 1, or should the screenshot happen instantly?

Daniel d'Andrada (dandrader) wrote :

For what it's worth, my Android phone only reacts (ie, show the volume bar etc) when I release the volume key, not on press.

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'qml/Components/Dialogs.qml'
2--- qml/Components/Dialogs.qml 2014-12-08 13:39:01 +0000
3+++ qml/Components/Dialogs.qml 2015-02-12 21:08:19 +0000
4@@ -35,21 +35,12 @@
5 }
6 }
7
8- function onPowerKeyPressed() {
9- // FIXME: event.isAutoRepeat is always false on Nexus 4.
10- // So we use powerKeyTimer.running to avoid the PowerOff key repeat
11- // https://launchpad.net/bugs/1349416
12- if (!powerKeyTimer.running) {
13- powerKeyTimer.restart();
14- }
15- }
16-
17- function onPowerKeyReleased() {
18- powerKeyTimer.stop();
19- }
20-
21 signal powerOffClicked();
22
23+ function showPowerDialog() {
24+ d.showPowerDialog();
25+ }
26+
27 QtObject {
28 id: d // private stuff
29 objectName: "dialogsPrivate"
30@@ -68,17 +59,6 @@
31 active: false
32 }
33
34- Timer {
35- id: powerKeyTimer
36- interval: 2000
37- repeat: false
38- triggeredOnStart: false
39-
40- onTriggered: {
41- d.showPowerDialog();
42- }
43- }
44-
45 Component {
46 id: logoutDialogComponent
47 ShellDialog {
48
49=== added file 'qml/Components/PhysicalKeysMapper.qml'
50--- qml/Components/PhysicalKeysMapper.qml 1970-01-01 00:00:00 +0000
51+++ qml/Components/PhysicalKeysMapper.qml 2015-02-12 21:08:19 +0000
52@@ -0,0 +1,114 @@
53+/*
54+ * Copyright (C) 2014 Canonical, Ltd.
55+ *
56+ * This program is free software; you can redistribute it and/or modify
57+ * it under the terms of the GNU General Public License as published by
58+ * the Free Software Foundation; version 3.
59+ *
60+ * This program is distributed in the hope that it will be useful,
61+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
62+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
63+ * GNU General Public License for more details.
64+ *
65+ * You should have received a copy of the GNU General Public License
66+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
67+ */
68+
69+import QtQuick 2.0
70+import Powerd 0.1
71+
72+/*!
73+ \brief A mapper for the physical keys on the device
74+
75+ A mapper to handle events triggered by pressing physical keys on a device.
76+ Keys included are
77+ * Volume Decrease
78+ * Volume Increase
79+ * Power
80+
81+ This allows for handling the following events
82+ * Volume Decreases/Increases
83+ * Screenshots
84+
85+*/
86+
87+Item {
88+ id: root
89+
90+ signal powerKeyLongPress();
91+
92+ property bool screenshotPressed: d.powerKeyPressed && d.volumeDownKeyPressed
93+ property bool volumeDownPressed: d.volumeDownKeyPressed && !d.powerKeyPressed
94+ property bool volumeUpPressed: d.volumeUpKeyPressed
95+ property int powerKeyLongPressTimeMs: 2000 // Is writable for testing purposes
96+
97+ QtObject {
98+ id: d
99+
100+ property bool powerKeyPressed: false
101+
102+ property bool volumeDownKeyPressed: false
103+ property bool volumeUpKeyPressed: false
104+ }
105+
106+ // FIXME: event.isAutoRepeat is always false on Nexus 4.
107+ // So we use powerKeyTimer.running to avoid the PowerOff key repeat
108+ // https://launchpad.net/bugs/1349416
109+ Timer {
110+ id: powerKeyLongPressTimer
111+
112+ interval: powerKeyLongPressTimeMs
113+ repeat: false
114+ triggeredOnStart: false
115+ onTriggered: powerKeyLongPress();
116+ }
117+
118+
119+ function onKeyPressed(key) {
120+ var eventAccepted = false;
121+
122+ /* Determine what key was pressed */
123+ if (key == Qt.Key_PowerDown || key == Qt.Key_PowerOff) {
124+
125+ // FIXME: We only consider power key presses if the screen is
126+ // on because of bugs 1410830/1409003. The theory is that when
127+ // those bugs are encountered, there is a >2s delay between the
128+ // power press event and the power release event, which causes
129+ // the shutdown dialog to appear on resume. So to avoid that
130+ // symptom while we investigate the root cause, we simply won't
131+ // initiate any dialogs when the screen is off.
132+ // This also prevents taking screenshots when the screen is off.
133+ if (Powerd.status === Powerd.On) {
134+ if (!powerKeyLongPressTimer.running) {
135+ powerKeyLongPressTimer.restart();
136+ }
137+ d.powerKeyPressed = true;
138+ eventAccepted = true;
139+ }
140+ } else if (key == Qt.Key_MediaTogglePlayPause || key == Qt.Key_MediaPlay) {
141+ eventAccepted = callManager.handleMediaKey(false);
142+ } else if (key == Qt.Key_VolumeDown) {
143+ d.volumeDownKeyPressed = true;
144+ } else if (key == Qt.Key_VolumeUp) {
145+ d.volumeUpKeyPressed = true;
146+ }
147+
148+ return eventAccepted;
149+ }
150+
151+ function onKeyReleased(key) {
152+ var eventAccepted = false;
153+
154+ if (key == Qt.Key_PowerDown || key == Qt.Key_PowerOff) {
155+ powerKeyLongPressTimer.stop();
156+ d.powerKeyPressed = false;
157+ eventAccepted = true;
158+ } else if (key == Qt.Key_VolumeDown) {
159+ d.volumeDownKeyPressed = false;
160+ } else if (key == Qt.Key_VolumeUp) {
161+ d.volumeUpKeyPressed = false;
162+ }
163+
164+ return eventAccepted;
165+ }
166+}
167
168=== removed file 'qml/Components/VolumeKeyFilter.qml'
169--- qml/Components/VolumeKeyFilter.qml 2014-10-30 02:39:38 +0000
170+++ qml/Components/VolumeKeyFilter.qml 1970-01-01 00:00:00 +0000
171@@ -1,63 +0,0 @@
172-/*
173- * Copyright (C) 2014 Canonical, Ltd.
174- *
175- * This program is free software; you can redistribute it and/or modify
176- * it under the terms of the GNU General Public License as published by
177- * the Free Software Foundation; version 3.
178- *
179- * This program is distributed in the hope that it will be useful,
180- * but WITHOUT ANY WARRANTY; without even the implied warranty of
181- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
182- * GNU General Public License for more details.
183- *
184- * You should have received a copy of the GNU General Public License
185- * along with this program. If not, see <http://www.gnu.org/licenses/>.
186- */
187-
188-import QtQuick 2.0
189-/*!
190- \brief A filter for volume keys
191-
192-A filter which treats volume keys as single tri-state key with the states:
193-VolumeUp Pressed, VolumeDown Pressed or Volume Up+Down pressed
194-*/
195-QtObject {
196- id: root
197-
198- signal volumeUpPressed()
199- signal volumeDownPressed()
200- signal bothVolumeKeysPressed()
201-
202- property bool volumeUpKeyPressed: false
203- property bool volumeDownKeyPressed: false
204- property bool aVolumeKeyWasReleased: true
205-
206- function onKeyPressed(key) {
207- if (key == Qt.Key_VolumeUp)
208- volumeUpKeyPressed = true;
209- else if (key == Qt.Key_VolumeDown)
210- volumeDownKeyPressed = true;
211-
212- if (volumeDownKeyPressed && volumeUpKeyPressed) {
213- //avoids sending a signal repeatedly if both keys are held
214- //instead one of the keys must have been previously released
215- if (aVolumeKeyWasReleased)
216- bothVolumeKeysPressed();
217- aVolumeKeyWasReleased = false;
218- } else if (volumeDownKeyPressed) {
219- volumeDownPressed();
220- } else if (volumeUpKeyPressed) {
221- volumeUpPressed();
222- }
223- }
224-
225- function onKeyReleased(key) {
226- if (key == Qt.Key_VolumeUp) {
227- volumeUpKeyPressed = false;
228- aVolumeKeyWasReleased = true;
229- } else if (key == Qt.Key_VolumeDown) {
230- volumeDownKeyPressed = false;
231- aVolumeKeyWasReleased = true;
232- }
233- }
234-}
235
236=== modified file 'qml/Shell.qml'
237--- qml/Shell.qml 2015-02-11 17:12:49 +0000
238+++ qml/Shell.qml 2015-02-12 21:08:19 +0000
239@@ -160,6 +160,16 @@
240 objectName: "dashCommunicator"
241 }
242
243+ PhysicalKeysMapper {
244+ id: physicalKeysMapper
245+
246+ onPowerKeyLongPress: dialogs.showPowerDialog()
247+ onVolumeDownPressedChanged: if (volumeDownPressed) { volumeControl.volumeDown(); }
248+ onVolumeUpPressedChanged: if (volumeUpPressed) { volumeControl.volumeUp(); }
249+ onScreenshotPressedChanged: if (screenshotPressed) { screenGrabber.capture(); }
250+
251+ }
252+
253 ScreenGrabber {
254 id: screenGrabber
255 z: dialogs.z + 10
256@@ -172,44 +182,13 @@
257 value: launcher.shown || launcher.dashSwipe
258 }
259
260- VolumeKeyFilter {
261- id: volumeKeyFilter
262- onVolumeDownPressed: volumeControl.volumeDown()
263- onVolumeUpPressed: volumeControl.volumeUp()
264- onBothVolumeKeysPressed: screenGrabber.capture()
265- }
266-
267 WindowKeysFilter {
268 Keys.onPressed: {
269- // Nokia earpieces give TogglePlayPause, while the iPhone's earpiece gives Play
270- if (event.key == Qt.Key_MediaTogglePlayPause || event.key == Qt.Key_MediaPlay) {
271- event.accepted = callManager.handleMediaKey(false);
272- } else if (event.key == Qt.Key_PowerOff || event.key == Qt.Key_PowerDown) {
273- // FIXME: We only consider power key presses if the screen is
274- // on because of bugs 1410830/1409003. The theory is that when
275- // those bugs are encountered, there is a >2s delay between the
276- // power press event and the power release event, which causes
277- // the shutdown dialog to appear on resume. So to avoid that
278- // symptom while we investigate the root cause, we simply won't
279- // initiate any dialogs when the screen is off.
280- if (Powerd.status === Powerd.On) {
281- dialogs.onPowerKeyPressed();
282- }
283- event.accepted = true;
284- } else {
285- volumeKeyFilter.onKeyPressed(event.key);
286- event.accepted = false;
287- }
288+ event.accepted = physicalKeysMapper.onKeyPressed(event.key);
289 }
290
291 Keys.onReleased: {
292- if (event.key == Qt.Key_PowerOff || event.key == Qt.Key_PowerDown) {
293- dialogs.onPowerKeyReleased();
294- event.accepted = true;
295- } else {
296- volumeKeyFilter.onKeyReleased(event.key);
297- event.accepted = false;
298- }
299+ event.accepted = physicalKeysMapper.onKeyReleased(event.key);
300 }
301 }
302
303
304=== modified file 'tests/qmltests/CMakeLists.txt'
305--- tests/qmltests/CMakeLists.txt 2015-02-11 17:11:41 +0000
306+++ tests/qmltests/CMakeLists.txt 2015-02-12 21:08:19 +0000
307@@ -13,6 +13,7 @@
308 set(qmltest_DEFAULT_NO_ADD_TEST FALSE)
309 set(qmltest_DEFAULT_PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=minimal")
310 add_qml_test(utils/Unity/Test UnityTest)
311+add_qml_test(Components PhysicalKeysMapper)
312
313 set(qmltest_DEFAULT_TARGETS qmluitests)
314 set(qmltest_DEFAULT_NO_ADD_TEST TRUE)
315
316=== added file 'tests/qmltests/Components/tst_PhysicalKeysMapper.qml'
317--- tests/qmltests/Components/tst_PhysicalKeysMapper.qml 1970-01-01 00:00:00 +0000
318+++ tests/qmltests/Components/tst_PhysicalKeysMapper.qml 2015-02-12 21:08:19 +0000
319@@ -0,0 +1,85 @@
320+/*
321+ * Copyright (C) 2014 Canonical, Ltd.
322+ *
323+ * This program is free software; you can redistribute it and/or modify
324+ * it under the terms of the GNU General Public License as published by
325+ * the Free Software Foundation; version 3.
326+ *
327+ * This program is distributed in the hope that it will be useful,
328+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
329+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
330+ * GNU General Public License for more details.
331+ *
332+ * You should have received a copy of the GNU General Public License
333+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
334+ */
335+
336+import QtQuick 2.0
337+import QtTest 1.0
338+import "../../../qml/Components"
339+
340+TestCase {
341+ name: "PhysicalKeysMapper"
342+
343+ property int onPowerKeyLongPressCount: 0
344+ property int initialLongPressTimerValue
345+
346+ PhysicalKeysMapper {
347+ id: physicalKeysMapper
348+
349+ onPowerKeyLongPress: onPowerKeyLongPressCount += 1
350+ }
351+
352+ function initTestCase() {
353+ initialLongPressTimerValue = physicalKeysMapper.powerKeyLongPressTimeMs
354+ }
355+
356+ function cleanup() {
357+ physicalKeysMapper.onKeyReleased(Qt.Key_PowerDown);
358+ physicalKeysMapper.onKeyReleased(Qt.Key_PowerOff);
359+ physicalKeysMapper.onKeyReleased(Qt.Key_VolumeDown);
360+ physicalKeysMapper.onKeyReleased(Qt.Key_VolumeUp);
361+
362+ onPowerKeyLongPressCount = 0;
363+
364+ physicalKeysMapper.powerKeyLongPressTimeMs = initialLongPressTimerValue
365+ }
366+
367+ function test_LongPressPowerButton() {
368+ // Delays chosen are lowest reliable values
369+ physicalKeysMapper.powerKeyLongPressTimeMs = 2
370+ physicalKeysMapper.onKeyPressed(Qt.Key_PowerDown);
371+ wait(15);
372+
373+ compare(onPowerKeyLongPressCount, 1);
374+ }
375+
376+ function test_ScreenshotButtons() {
377+ /* Behavior when Power is pressed 1st */
378+ physicalKeysMapper.onKeyPressed(Qt.Key_PowerDown);
379+ physicalKeysMapper.onKeyPressed(Qt.Key_VolumeDown);
380+ compare(physicalKeysMapper.screenshotPressed, true);
381+ compare(physicalKeysMapper.volumeDownPressed, false);
382+
383+ physicalKeysMapper.onKeyReleased(Qt.Key_PowerDown);
384+ physicalKeysMapper.onKeyReleased(Qt.Key_VolumeDown);
385+
386+ /* Behavior when VolumeDown is pressed 1st */
387+ physicalKeysMapper.onKeyPressed(Qt.Key_VolumeDown);
388+ compare(physicalKeysMapper.volumeDownPressed, true);
389+ physicalKeysMapper.onKeyPressed(Qt.Key_PowerDown);
390+ compare(physicalKeysMapper.screenshotPressed, true);
391+ }
392+
393+ function test_VolumeDownButton() {
394+ compare(physicalKeysMapper.volumeDownPressed, false);
395+ physicalKeysMapper.onKeyPressed(Qt.Key_VolumeDown);
396+ compare(physicalKeysMapper.volumeDownPressed, true);
397+ }
398+
399+ function test_VolumeUpButton() {
400+ compare(physicalKeysMapper.volumeUpPressed, false);
401+ physicalKeysMapper.onKeyPressed(Qt.Key_VolumeUp);
402+ compare(physicalKeysMapper.volumeUpPressed, true);
403+ }
404+}

Subscribers

People subscribed via source and target branches