on xenial help sign in
Reset topmostIsFullscreen to correctly rotate the shell when dismissing SIM PIN screen (LP: #1614070)
21d06b0Lukáš Tinkl
qml/Notifications/Notification.qml+5−2
@@ -37,7 +37,8 @@ StyledItem {
37 property var hints
37 property var hints
38 property var notification
38 property var notification
39 property color color: theme.palette.normal.background
39 property color color: theme.palette.normal.background
40− property bool fullscreen: false
40+ property bool fullscreen: notification.notification && typeof notification.notification.fullscreen != "undefined" ?
41+ notification.notification.fullscreen : false // fullscreen prop only exists in the mock
41 property int maxHeight
42 property int maxHeight
42 property int margins: units.gu(1)
43 property int margins: units.gu(1)
43
44
@@ -123,7 +124,9 @@ StyledItem {
123 if (fullscreen) {
124 if (fullscreen) {
124 notification.notification.urgency = Notification.Critical;
125 notification.notification.urgency = Notification.Critical;
125 }
126 }
127+ if (index == 0) {
126− ListView.view.topmostIsFullscreen = fullscreen;
128+ ListView.view.topmostIsFullscreen = fullscreen;
129+ }
127 }
130 }
128
131
129 Behavior on implicitHeight {
132 Behavior on implicitHeight {
qml/Notifications/Notifications.qml+5−1
@@ -69,7 +69,9 @@ ListView {
69
69
70 property int theIndex: index
70 property int theIndex: index
71 onTheIndexChanged: {
71 onTheIndexChanged: {
72+ if (theIndex == 0) {
72− ListView.view.topmostIsFullscreen = fullscreen; // when we get pushed down by e.g. volume notification
73+ ListView.view.topmostIsFullscreen = fullscreen; // when we get pushed down by e.g. volume notification
74+ }
73 }
75 }
74
76
75 // make sure there's no opacity-difference between the several
77 // make sure there's no opacity-difference between the several
@@ -78,6 +80,8 @@ ListView {
78 //layer.enabled: add.running || remove.running || populate.running
80 //layer.enabled: add.running || remove.running || populate.running
79 }
81 }
80
82
83+ onCountChanged: if (count == 0) topmostIsFullscreen = false; // reset
84+
81 // FIXME: disabled all transitions because of LP: #1354406 workaround
85 // FIXME: disabled all transitions because of LP: #1354406 workaround
82 /*populate: Transition {
86 /*populate: Transition {
83 UbuntuNumberAnimation {
87 UbuntuNumberAnimation {
tests/mocks/Unity/Notifications/MockNotification.cpp+15
@@ -32,6 +32,7 @@ struct MockNotificationPrivate {
32 QStringList actions;
32 QStringList actions;
33 ActionModel* actionsModel;
33 ActionModel* actionsModel;
34 QVariantMap hints;
34 QVariantMap hints;
35+ bool fullscreen = false;
35};
36};
36
37
37MockNotification::MockNotification(QObject *parent) : QObject(parent), p(new MockNotificationPrivate()) {
38MockNotification::MockNotification(QObject *parent) : QObject(parent), p(new MockNotificationPrivate()) {
@@ -181,3 +182,17 @@ void MockNotification::invokeAction(const QString &action) {
181void MockNotification::close() {
182void MockNotification::close() {
182 Q_EMIT completed(p->id);
183 Q_EMIT completed(p->id);
183}
184}
185+
186+bool MockNotification::fullscreen() const
187+{
188+ return p->fullscreen;
189+}
190+
191+void MockNotification::setFullscreen(bool fullscreen)
192+{
193+ if (p->fullscreen == fullscreen)
194+ return;
195+
196+ p->fullscreen = fullscreen;
197+ Q_EMIT fullscreenChanged(fullscreen);
198+}
tests/mocks/Unity/Notifications/MockNotification.h+5
@@ -41,6 +41,7 @@ class MockNotification : public QObject {
41 Q_PROPERTY(QStringList rawActions READ rawActions WRITE setActions)
41 Q_PROPERTY(QStringList rawActions READ rawActions WRITE setActions)
42 Q_PROPERTY(ActionModel* actions READ getActions NOTIFY actionsChanged)
42 Q_PROPERTY(ActionModel* actions READ getActions NOTIFY actionsChanged)
43 Q_PROPERTY(QVariantMap hints READ getHints WRITE setHints NOTIFY hintsChanged)
43 Q_PROPERTY(QVariantMap hints READ getHints WRITE setHints NOTIFY hintsChanged)
44+ Q_PROPERTY(bool fullscreen READ fullscreen WRITE setFullscreen NOTIFY fullscreenChanged) // only in mock
44
45
45private:
46private:
46 QScopedPointer<MockNotificationPrivate> p;
47 QScopedPointer<MockNotificationPrivate> p;
@@ -64,6 +65,8 @@ Q_SIGNALS:
64 void completed(int nid);
65 void completed(int nid);
65 void actionInvoked(const QString &action);
66 void actionInvoked(const QString &action);
66
67
68+ void fullscreenChanged(bool fullscreen);
69+
67public:
70public:
68 MockNotification(QObject *parent=nullptr);
71 MockNotification(QObject *parent=nullptr);
69 virtual ~MockNotification();
72 virtual ~MockNotification();
@@ -87,6 +90,8 @@ public:
87 void setActions(const QStringList &actions);
90 void setActions(const QStringList &actions);
88 QVariantMap getHints() const;
91 QVariantMap getHints() const;
89 void setHints(const QVariantMap& hints);
92 void setHints(const QVariantMap& hints);
93+ bool fullscreen() const;
94+ void setFullscreen(bool fullscreen);
90
95
91 Q_INVOKABLE void invokeAction(const QString &action);
96 Q_INVOKABLE void invokeAction(const QString &action);
92 Q_INVOKABLE void close();
97 Q_INVOKABLE void close();
tests/qmltests/Notifications/Notification.qml+1
@@ -28,4 +28,5 @@ Notification {
28 secondaryIcon: ""
28 secondaryIcon: ""
29 value: 0
29 value: 0
30 rawActions: []
30 rawActions: []
31+ fullscreen: false
31}
32}
tests/qmltests/Notifications/tst_Notifications.qml+73−6
@@ -141,6 +141,18 @@ Item {
141 mockModel.append(n)
141 mockModel.append(n)
142 }
142 }
143
143
144+ function addFullscreenNotification() {
145+ var component = Qt.createComponent("Notification.qml")
146+ var n = component.createObject("notification", {"nid": index++,
147+ "type": Notification.SnapDecision,
148+ "hints": {"x-canonical-private-affirmative-tint": "true"},
149+ "summary": "SIM PIN screen",
150+ "body": "Enter your PIN to unlock the SIM",
151+ "fullscreen": true})
152+ n.completed.connect(mockModel.onCompleted)
153+ mockModel.append(n)
154+ }
155+
144 function clearNotifications() {
156 function clearNotifications() {
145 while(mockModel.count > 0) {
157 while(mockModel.count > 0) {
146 remove1stNotification();
158 remove1stNotification();
@@ -228,6 +240,12 @@ Item {
228 onClicked: rootRow.add2ndConfirmationNotification()
240 onClicked: rootRow.add2ndConfirmationNotification()
229 }
241 }
230
242
243+ Button {
244+ width: parent.width
245+ text: "add a fullscreen notification"
246+ onClicked: rootRow.addFullscreenNotification()
247+ }
248+
231 Button {
249 Button {
232 width: parent.width
250 width: parent.width
233 text: "remove 1st notification"
251 text: "remove 1st notification"
@@ -371,6 +389,14 @@ Item {
371 rawActions: ["ok_id", "Ok",
389 rawActions: ["ok_id", "Ok",
372 "snooze_id", "Snooze",
390 "snooze_id", "Snooze",
373 "view_id", "View"]
391 "view_id", "View"]
392+ },
393+ Notification {
394+ nid: 10
395+ type: Notification.SnapDecision
396+ hints: {"x-canonical-private-affirmative-tint": "true"}
397+ summary: "SIM PIN screen"
398+ body: "Enter your PIN to unlock the SIM"
399+ fullscreen: true
374 }
400 }
375 ]
401 ]
376
402
@@ -538,15 +564,12 @@ Item {
538 signalName: "actionInvoked"
564 signalName: "actionInvoked"
539 }
565 }
540
566
541− function init() {
542− while (mockModel.count > 0) {
543− mockModel.remove(0);
544− }
545− }
546−
547 function cleanup() {
567 function cleanup() {
548 clickThroughSpy.clear()
568 clickThroughSpy.clear()
549 actionSpy.clear()
569 actionSpy.clear()
570+ while (mockModel.count > 0) {
571+ mockModel.removeFirst();
572+ }
550 }
573 }
551
574
552 function test_NotificationRenderer(data) {
575 function test_NotificationRenderer(data) {
@@ -797,6 +820,50 @@ Item {
797 tryCompareFunction(function() { return notification2.expanded; }, undefined);
820 tryCompareFunction(function() { return notification2.expanded; }, undefined);
798 }
821 }
799
822
823+ function topmostIsFullscreen_data() {
824+ return [{
825+ tag: "Confirmation notification with value",
826+ n: nlist[6]
827+ },
828+ {
829+ tag: "SIM PIN fullscreen notification",
830+ n: nlist[9]
831+ },
832+ {
833+ tag: "Snap Decision without secondary icon and no button-tint",
834+ n: nlist[3]
835+ }]
836+ }
837+
838+ function test_topmostIsFullscreen() {
839+ var data = topmostIsFullscreen_data();
840+
841+ // fill the model
842+ data.forEach(function(notification) {
843+ mockModel.append(notification.n);
844+ notification.n.completed.connect(mockModel.onCompleted);
845+ })
846+
847+ // make sure the view is properly updated before going on
848+ notifications.forceLayout();
849+ waitForRendering(notifications);
850+
851+ // initially, topmost is not fullscreen
852+ verify(!notifications.topmostIsFullscreen)
853+
854+ // close the 1st one, 2nd one should be fullscreen
855+ var notification0 = findChild(notifications, "notification0")
856+ notification0.closeNotification();
857+ waitForRendering(notifications);
858+ verify(notifications.topmostIsFullscreen)
859+
860+ // close the 1st one (SIM PIN) again, topmost should no longer be fullscreen
861+ notification0 = findChild(notifications, "notification0")
862+ notification0.closeNotification();
863+ waitForRendering(notifications);
864+ verify(!notifications.topmostIsFullscreen)
865+ }
866+
800 function cleanupTestCase() {
867 function cleanupTestCase() {
801 notifications.hasMouse = false;
868 notifications.hasMouse = false;
802 }
869 }