Merge lp:~ken-vandine/ubuntu-system-settings/rtm-1388044 into lp:ubuntu-system-settings/rtm-14.09

Proposed by Ken VanDine
Status: Merged
Approved by: Jonas G. Drange
Approved revision: 951
Merged at revision: 967
Proposed branch: lp:~ken-vandine/ubuntu-system-settings/rtm-1388044
Merge into: lp:ubuntu-system-settings/rtm-14.09
Diff against target: 987 lines (+495/-272)
9 files modified
plugins/cellular/CMakeLists.txt (+3/-1)
plugins/cellular/Components/MultiSim.qml (+3/-2)
plugins/cellular/Components/RadioSingleSim.qml (+5/-5)
plugins/cellular/Components/SingleSim.qml (+18/-24)
plugins/cellular/PageCarrierAndApn.qml (+67/-0)
plugins/cellular/PageCarriersAndApns.qml (+41/-20)
plugins/cellular/PageChooseCarrier.qml (+201/-179)
plugins/cellular/carriers.js (+106/-0)
tests/autopilot/ubuntu_system_settings/__init__.py (+51/-41)
To merge this branch: bzr merge lp:~ken-vandine/ubuntu-system-settings/rtm-1388044
Reviewer Review Type Date Requested Status
Jonas G. Drange (community) Approve
PS Jenkins bot continuous-integration Approve
Review via email: mp+244878@code.launchpad.net

Commit message

[cellular/carriers] new Carrier & APN entry, as well as a major refactor of carrier selection code warranted by the design change.

Description of the change

[cellular/carriers] new Carrier & APN entry, as well as a major refactor of carrier selection code warranted by the design change.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Jonas G. Drange (jonas-drange) wrote :

Thanks, Ken!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'plugins/cellular/CMakeLists.txt'
2--- plugins/cellular/CMakeLists.txt 2014-08-27 09:17:50 +0000
3+++ plugins/cellular/CMakeLists.txt 2014-12-16 16:24:38 +0000
4@@ -4,10 +4,12 @@
5 install(FILES settings-cellular.svg DESTINATION ${PLUGIN_MANIFEST_DIR}/icons)
6
7 set(QML_SOURCES
8+ carriers.js
9 CustomApnEditor.qml
10 PageChooseApn.qml
11 PageChooseCarrier.qml
12- PageChooseCarriers.qml
13+ PageCarrierAndApn.qml
14+ PageCarriersAndApns.qml
15 PageComponent.qml
16 Hotspot.qml
17 HotspotSetup.qml
18
19=== modified file 'plugins/cellular/Components/MultiSim.qml'
20--- plugins/cellular/Components/MultiSim.qml 2014-12-08 16:01:29 +0000
21+++ plugins/cellular/Components/MultiSim.qml 2014-12-16 16:24:38 +0000
22@@ -43,6 +43,7 @@
23 anchors { left: parent.left; right: parent.right }
24 }
25
26+
27 ListItem.SingleValue {
28 text : i18n.tr("Hotspot disabled because Wi-Fi is off.")
29 visible: showAllUI && !hotspotItem.visible
30@@ -70,11 +71,11 @@
31 ListItem.SingleValue {
32 text: i18n.tr("Carriers")
33 id: chooseCarrier
34- objectName: "carriers"
35+ objectName: "carrierApnEntry"
36 progression: enabled
37 showDivider: false
38 onClicked: {
39- pageStack.push(Qt.resolvedUrl("../PageChooseCarriers.qml"), {
40+ pageStack.push(Qt.resolvedUrl("../PageCarriersAndApns.qml"), {
41 sims: sims
42 });
43 }
44
45=== modified file 'plugins/cellular/Components/RadioSingleSim.qml'
46--- plugins/cellular/Components/RadioSingleSim.qml 2014-11-18 20:13:35 +0000
47+++ plugins/cellular/Components/RadioSingleSim.qml 2014-12-16 16:24:38 +0000
48@@ -24,7 +24,7 @@
49 Column {
50 height: childrenRect.height
51
52- property alias selector: selector
53+ property bool enabled: sim.radioSettings.technologyPreference !== ""
54
55 ListItem.ItemSelector {
56 id: selector
57@@ -34,8 +34,8 @@
58
59 // an empty string is not a valid preference, which means
60 // we disregard the interace and disable the selector
61- enabled: sim.radioSettings.technologyPreference !== ""
62- model: sim.radioSettings.modemTechnologies
63+ enabled: parent.enabled
64+ model: sim.radioSettings.modemTechnologies || []
65
66 delegate: OptionSelectorDelegate {
67 objectName: sim.path + "_radio_" + modelData
68@@ -48,10 +48,10 @@
69 }
70 showDivider: false
71 }
72- selectedIndex: model.indexOf(sim.radioSettings.technologyPreference)
73+ selectedIndex: model.length ?
74+ model.indexOf(sim.radioSettings.technologyPreference) : -1
75 onDelegateClicked: {
76 sim.radioSettings.technologyPreference = model[index];
77 }
78 }
79-
80 }
81
82=== modified file 'plugins/cellular/Components/SingleSim.qml'
83--- plugins/cellular/Components/SingleSim.qml 2014-11-18 20:13:35 +0000
84+++ plugins/cellular/Components/SingleSim.qml 2014-12-16 16:24:38 +0000
85@@ -18,6 +18,7 @@
86 *
87 */
88 import QtQuick 2.0
89+import SystemSettings 1.0
90 import Ubuntu.Components 0.1
91 import Ubuntu.Components.ListItems 0.1 as ListItem
92
93@@ -33,8 +34,10 @@
94 control: Switch {
95 id: dataControl
96 objectName: 'data'
97- checked: sim.connMan.powered
98- onClicked: sim.connMan.powered = checked
99+ property bool serverChecked: sim.connMan.powered
100+ onServerCheckedChanged: checked = serverChecked
101+ Component.onCompleted: checked = serverChecked
102+ onTriggered: sim.connMan.powered = checked
103 }
104 }
105
106@@ -46,8 +49,10 @@
107 control: Switch {
108 id: dataRoamingControl
109 objectName: "roaming"
110- checked: sim.connMan.roamingAllowed
111- onClicked: sim.connMan.roamingAllowed = checked
112+ property bool serverChecked: sim.connMan.roamingAllowed
113+ onServerCheckedChanged: checked = serverChecked
114+ Component.onCompleted: checked = serverChecked
115+ onTriggered: sim.connMan.roamingAllowed = checked
116 }
117 }
118
119@@ -72,36 +77,25 @@
120 visible: showAllUI
121 }
122
123- ListItem.Divider {
124- visible: radio.selector.model.length
125+ ListItem.Divider {
126+ visible: radio.visible
127 }
128
129 RadioSingleSim {
130 id: radio
131- anchors { left: parent.left; right: parent.right }
132- visible: radio.selector.model.length
133+ anchors { left: parent.left; right: parent.right }
134+ visible: radio.enabled
135 }
136
137- ListItem.Divider {}
138+ ListItem.Divider {}
139
140 ListItem.SingleValue {
141 text: i18n.tr("Carrier");
142 id: chooseCarrier
143- objectName: "carrier"
144+ objectName: "carrierApnEntry"
145 progression: enabled
146- value: sim.netReg.name || i18n.tr("N/A")
147- enabled: sim.netReg.status !== ""
148- onClicked: {
149- pageStack.push(Qt.resolvedUrl("../PageChooseCarrier.qml"), {
150- sim: sim,
151- title: i18n.tr("Carrier")
152- })
153- }
154- }
155-
156- ListItem.Standard {
157- text: i18n.tr("APN")
158- progression: true
159- visible: showAllUI
160+ onClicked: pageStack.push(Qt.resolvedUrl("../PageCarrierAndApn.qml"), {
161+ sim: sim
162+ })
163 }
164 }
165
166=== added file 'plugins/cellular/PageCarrierAndApn.qml'
167--- plugins/cellular/PageCarrierAndApn.qml 1970-01-01 00:00:00 +0000
168+++ plugins/cellular/PageCarrierAndApn.qml 2014-12-16 16:24:38 +0000
169@@ -0,0 +1,67 @@
170+/*
171+ * Copyright (C) 2014 Canonical Ltd
172+ *
173+ * This program is free software: you can redistribute it and/or modify
174+ * it under the terms of the GNU General Public License version 3 as
175+ * published by the Free Software Foundation.
176+ *
177+ * This program is distributed in the hope that it will be useful,
178+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
179+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
180+ * GNU General Public License for more details.
181+ *
182+ * You should have received a copy of the GNU General Public License
183+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
184+ *
185+ * Authors:
186+ * Jonas G. Drange <jonas.drange@canonical.com>
187+ *
188+*/
189+import QtQuick 2.0
190+import SystemSettings 1.0
191+import Ubuntu.Components 0.1
192+import Ubuntu.Components.ListItems 0.1 as ListItem
193+
194+ItemPage {
195+ id: root
196+ title: i18n.tr("Carrier")
197+ objectName: "carrierApnPage"
198+ flickable: null
199+
200+ property var sim
201+
202+ Flickable {
203+ anchors.fill: parent
204+ contentWidth: parent.width
205+ contentHeight: contentItem.childrenRect.height
206+ boundsBehavior: (contentHeight > root.height) ? Flickable.DragAndOvershootBounds : Flickable.StopAtBounds
207+
208+ Column {
209+ anchors.left: parent.left
210+ anchors.right: parent.right
211+
212+ ListItem.SingleValue {
213+ text: i18n.tr("Carrier")
214+ objectName: "carrier"
215+ value: sim.netReg.name ? sim.netReg.name : i18n.tr("None")
216+ enabled: (sim.netReg.status !== "") &&
217+ (sim.netReg.mode !== "auto-only")
218+ progression: enabled
219+ onClicked: pageStack.push(Qt.resolvedUrl("PageChooseCarrier.qml"), {
220+ sim: sim,
221+ title: i18n.tr("Carrier")
222+ })
223+ }
224+
225+ ListItem.Standard {
226+ text: i18n.tr("APN")
227+ objectName: "apn"
228+ progression: enabled
229+ enabled: sim.connMan.powered
230+ onClicked: pageStack.push(Qt.resolvedUrl("PageChooseApn.qml"), {
231+ sim: sim
232+ })
233+ }
234+ }
235+ }
236+}
237
238=== renamed file 'plugins/cellular/PageChooseCarriers.qml' => 'plugins/cellular/PageCarriersAndApns.qml'
239--- plugins/cellular/PageChooseCarriers.qml 2014-11-18 20:13:35 +0000
240+++ plugins/cellular/PageCarriersAndApns.qml 2014-12-16 16:24:38 +0000
241@@ -25,7 +25,8 @@
242 ItemPage {
243 id: root
244 title: i18n.tr("Carriers")
245- objectName: "chooseCarriersPage"
246+ objectName: "carrierApnPage"
247+ flickable: null
248
249 property var sims
250
251@@ -39,38 +40,58 @@
252 anchors.left: parent.left
253 anchors.right: parent.right
254
255- ListItem.Standard {
256+ SettingsItemTitle {
257 text: sims[0].title
258 }
259
260 ListItem.SingleValue {
261+ text: i18n.tr("Carrier")
262 objectName: sims[0].path + "_carriers"
263- value: sims[0].netReg.name ? sims[0].netReg.name : i18n.tr("N/A")
264- enabled: sims[0].netReg.status !== ""
265- progression: true
266- onClicked: {
267- pageStack.push(Qt.resolvedUrl("PageChooseCarrier.qml"), {
268- sim: sims[0],
269- title: sims[0].title
270- })
271- }
272+ value: sims[0].netReg.name ? sims[0].netReg.name :
273+ i18n.tr("None")
274+ enabled: (sims[0].netReg.status !== "") &&
275+ (sims[0].netReg.mode !== "auto-only")
276+ progression: enabled
277+ onClicked: pageStack.push(Qt.resolvedUrl("PageChooseCarrier.qml"), {
278+ sim: sims[0],
279+ title: sims[0].title
280+ })
281 }
282
283 ListItem.Standard {
284+ text: i18n.tr("APN")
285+ progression: enabled
286+ enabled: sims[0].connMan.powered
287+ onClicked: pageStack.push(Qt.resolvedUrl("PageChooseApn.qml"), {
288+ sim: sims[0]
289+ })
290+ }
291+
292+ SettingsItemTitle {
293 text: sims[1].title
294 }
295
296 ListItem.SingleValue {
297+ text: i18n.tr("Carrier")
298 objectName: sims[1].path + "_carriers"
299- value: sims[1].netReg.name ? sims[1].netReg.name : i18n.tr("N/A")
300- enabled: sims[1].netReg.status !== ""
301- progression: true
302- onClicked: {
303- pageStack.push(Qt.resolvedUrl("PageChooseCarrier.qml"), {
304- sim: sims[1],
305- title: sims[1].title
306- })
307- }
308+ value: sims[1].netReg.name ? sims[1].netReg.name :
309+ i18n.tr("None")
310+ enabled: (sims[1].netReg.status !== "") &&
311+ (sims[1].netReg.mode !== "auto-only")
312+ progression: enabled
313+ onClicked: pageStack.push(Qt.resolvedUrl("PageChooseCarrier.qml"), {
314+ sim: sims[1],
315+ title: sims[1].title
316+ })
317+ }
318+
319+ ListItem.Standard {
320+ text: i18n.tr("APN")
321+ progression: enabled
322+ enabled: sims[1].connMan.powered
323+ onClicked: pageStack.push(Qt.resolvedUrl("PageChooseApn.qml"), {
324+ sim: sims[1]
325+ })
326 }
327 }
328 }
329
330=== modified file 'plugins/cellular/PageChooseCarrier.qml'
331--- plugins/cellular/PageChooseCarrier.qml 2014-11-18 20:13:35 +0000
332+++ plugins/cellular/PageChooseCarrier.qml 2014-12-16 16:24:38 +0000
333@@ -4,6 +4,7 @@
334 * Copyright (C) 2013 Canonical Ltd.
335 *
336 * Contact: Iain Lane <iain.lane@canonical.com>
337+ * Jonas G. Drange <jonas.drange@canonical.com>
338 *
339 * This program is free software: you can redistribute it and/or modify it
340 * under the terms of the GNU General Public License version 3, as published
341@@ -24,214 +25,235 @@
342 import Ubuntu.Components 1.1
343 import Ubuntu.Components.ListItems 1.0 as ListItem
344 import MeeGo.QOfono 0.2
345+import "carriers.js" as CHelper
346
347 ItemPage {
348 id: root
349 title: i18n.tr("Carrier")
350-
351 objectName: "chooseCarrierPage"
352+ flickable: null
353
354 property var sim
355-
356- property variant operatorNames
357- property int mode
358-
359- QtObject {
360- id: d
361- property bool __suppressActivation : true;
362- }
363-
364- Component.onCompleted: {
365- updateNetworkOperators();
366- }
367-
368- Connections {
369- target: sim.netReg
370- onNetworkOperatorsChanged: updateNetworkOperators();
371- onCurrentOperatorPathChanged: buildLists();
372- }
373-
374- // map of operatorPath : netOp
375- property var operators: ({})
376- function updateNetworkOperators()
377- {
378- var tmp = sim.netReg.networkOperators;
379- var added = tmp.filter(function(i) {
380- return operators[i] === undefined;
381- });
382- var removed = Object.keys(operators).filter(function(i) {
383- return tmp.indexOf(i) === -1;
384- })
385-
386- removed.forEach(function(currentValue, index, array) {
387- // just asserting to verify the logic
388- // remove once proven functional
389- if (operators[currentValue] === undefined) {
390- throw "updateNetworkOperators: removed is broken";
391- }
392-
393- operators[currentValue].destroy();
394- delete operators[currentValue];
395- });
396-
397- added.forEach(function(currentValue, index, array) {
398- // just asserting to verify the logic
399- // remove once proven functional
400- if (operators[currentValue] !== undefined) {
401- throw "updateNetworkOperators: added is broken";
402- }
403-
404- operators[currentValue] = netOp.createObject(parent,
405- {
406- "operatorPath": currentValue
407- });
408- });
409-
410- // just asserting to verify the logic
411- // remove once proven functional
412- if (Object.keys(operators).length !== tmp.length) {
413- throw "Object.keys(operators).length !== tmp.length";
414- }
415- tmp.forEach(function(currentValue, index, array) {
416- if (operators[currentValue] === undefined)
417- throw "operators[currentValue] === undefined";
418- });
419-
420- buildLists();
421- }
422-
423- function buildLists()
424- {
425- d.__suppressActivation = true;
426- var oN = new Array();
427-
428- for (var i in operators) {
429- var tempOp = operators[i];
430- if (tempOp.status === "forbidden")
431- continue
432- oN.push(tempOp.name);
433- }
434- operatorNames = oN;
435-
436- var cur = operators[sim.netReg.currentOperatorPath];
437- carrierSelector.selectedIndex = cur === undefined ? -1 : operatorNames.indexOf(cur.name);
438- d.__suppressActivation = false;
439- }
440+ property bool scanning: true
441+ property bool working: false
442+
443+ states: [
444+ State {
445+ name: "auto"
446+ when: sim.netReg.mode === "auto"
447+ PropertyChanges {
448+ target: otherOperators
449+ selectedIndex: -1
450+ }
451+ PropertyChanges {
452+ target: allOperators
453+ height: 0
454+ opacity: 0
455+ }
456+ },
457+ State {
458+ name: "manual"
459+ when: sim.netReg.mode === "manual"
460+ PropertyChanges {
461+ target: otherOperators
462+ height: 0
463+ opacity: 0
464+ }
465+ }
466+ /* Note that we do not consider auto-only since this page is not
467+ reachable in that case (see Carrier & APN page). */
468+ ]
469
470 Component {
471 id: netOp
472 OfonoNetworkOperator {
473 onRegisterComplete: {
474- if (error === OfonoNetworkOperator.InProgressError) {
475- console.warn("registerComplete failed with error: " + errorString);
476- } else if (error !== OfonoNetworkOperator.NoError) {
477- console.warn("registerComplete failed with error: " + errorString + " Falling back to default");
478+ if (error !== OfonoNetworkOperator.NoError) {
479+ console.warn("Register complete:", errorString);
480+ console.warn("Falling back to default operator.");
481 sim.netReg.registration();
482 }
483- }
484- onNameChanged: buildLists();
485- onStatusChanged: buildLists();
486- }
487- }
488+ working = false;
489+ }
490+ }
491+ }
492+
493+ Connections {
494+ /* The following is a hack: If a scan is in progress and we call
495+ scan() on netReg, it emits a scanError _and_ scanFinished.
496+ We look at the scanError message, set this property to true if
497+ it says a scan is in progress. This way we can ignore the bad
498+ scanFinished signal. Filed bug against libqofono[1].
499+ [1] https://github.com/nemomobile/libqofono/issues/52
500+ */
501+ property bool __scanInProgress: false
502+
503+ target: sim.netReg
504+ onScanFinished: {
505+ if (scanning && !__scanInProgress) {
506+ scanning = false;
507+ }
508+ __scanInProgress = false;
509+ }
510+ onScanError: {
511+ if (message === "Operation already in progress") {
512+ console.warn('A scan was already in progress.');
513+ __scanInProgress = true;
514+ } else {
515+ scanning = false;
516+ __scanInProgress = false;
517+ console.warn("onScanError: " + message);
518+ }
519+ }
520+ onModeChanged: modeSelector.selectedIndex = (mode === "auto") ? 0 : -1
521+ }
522+
523+ Component.onCompleted: sim.netReg.scan()
524
525 Flickable {
526 id: scrollWidget
527 anchors.fill: parent
528 contentWidth: parent.width
529- contentHeight: parent.height
530- boundsBehavior: (contentHeight > parent.height) ? Flickable.DragAndOvershootBounds : Flickable.StopAtBounds
531+ contentHeight: contentItem.childrenRect.height
532+ boundsBehavior: (contentHeight > root.height) ?
533+ Flickable.DragAndOvershootBounds : Flickable.StopAtBounds
534
535- ColumnLayout {
536+ Column {
537 anchors {
538 left: parent.left
539 right: parent.right
540 }
541+ spacing: 0
542+
543+ SettingsItemTitle {
544+ text: i18n.tr("Carrier")
545+
546+ ActivityIndicator {
547+ anchors {
548+ right: parent.right
549+ top: parent.top
550+ margins: units.gu(1.5)
551+ }
552+ running: true
553+ opacity: scanning || working ? 1 : 0
554+ Behavior on opacity {
555+ NumberAnimation {
556+ duration: UbuntuAnimation.SnapDuration
557+ }
558+ }
559+ }
560+ }
561
562 ListItem.ItemSelector {
563- id: chooseCarrier
564+ id: modeSelector
565 objectName: "mode"
566 expanded: true
567- enabled: sim.netReg.mode !== "auto-only"
568- text: i18n.tr("Choose carrier:")
569- model: [i18n.tr("Automatically"), i18n.tr("Manually")]
570-
571- delegate: OptionSelectorDelegate { showDivider: false }
572- selectedIndex: sim.netReg.mode === "manual" ? 1 : 0
573-
574- // we only want to do this per user input
575+ enabled: !scanning && !working
576+ opacity: enabled ? 1 : 0.5
577+ model: [i18n.tr("Automatically")]
578+ delegate: OptionSelectorDelegate {
579+ text: {
580+ // modelData is "Automatically"
581+ if (sim.netReg.mode === "auto") {
582+ return sim.netReg.name ?
583+ modelData + " [ " + sim.netReg.name + " ]" :
584+ modelData
585+ } else {
586+ return modelData;
587+ }
588+ }
589+ showDivider: false
590+ }
591+ selectedIndex: sim.netReg.mode === "auto" ? 0 : -1
592+
593+ /* When registration() fails, the UI state may end up in an
594+ undefined state. Issue[1] has been filed against libqofono.
595+ [1] https://github.com/nemomobile/libqofono/issues/54
596+ */
597+ onDelegateClicked: sim.netReg.registration()
598+ }
599+
600+ // In manual mode, all non-forbidden operators are shown.
601+ ListItem.ItemSelector {
602+ id: allOperators
603+ objectName: "allOperators"
604+ expanded: true
605+ enabled: !scanning && !working
606+ opacity: enabled ? 1 : 0.5
607+ model: CHelper.getOps(sim.netReg.networkOperators)
608+ delegate: OptionSelectorDelegate {
609+ objectName: "carrier"
610+ showDivider: false
611+ text: modelData.name
612+ }
613+ onDelegateClicked: {
614+ CHelper.setOp(model[index].operatorPath);
615+ working = true;
616+ }
617+ selectedIndex: {
618+ var curop = sim.netReg.currentOperatorPath;
619+ return model.indexOf(CHelper.getOrCreateOpQml(curop));
620+ }
621+
622+ Behavior on height {
623+ NumberAnimation {
624+ duration: UbuntuAnimation.SnapDuration
625+ }
626+ }
627+
628+ Behavior on opacity {
629+ NumberAnimation {
630+ duration: UbuntuAnimation.SnapDuration
631+ }
632+ }
633+ }
634+
635+ /* When registration mode is "Automatic", this list contains all
636+ the non-forbidden operators except the current one. When the user
637+ taps one of the elements in this selector, it will be hidden,
638+ and the mode will switch to "Manual". */
639+ ListItem.ItemSelector {
640+ id: otherOperators
641+ objectName: "otherOperators"
642+ expanded: true
643+ enabled: !scanning && !working
644+ opacity: enabled ? 1 : 0.5
645+ model: CHelper.getOps(sim.netReg.networkOperators,
646+ [sim.netReg.currentOperatorPath])
647+ delegate: OptionSelectorDelegate {
648+ objectName: "carrier"
649+ showDivider: false
650+ text: modelData.name
651+ }
652+ onDelegateClicked: {
653+ var clickedOp = model[index].operatorPath;
654+ CHelper.setOp(clickedOp);
655+
656+ // Update immediately and do not wait for netReg
657+ allOperators.selectedIndex = allOperators.model.indexOf(
658+ CHelper.getOrCreateOpQml(clickedOp));
659+ working = true;
660+ }
661 onSelectedIndexChanged: {
662- if (selectedIndex === -1 || d.__suppressActivation)
663- return;
664-
665- if (selectedIndex === 0) {
666- sim.netReg.registration();
667- } else if (selectedIndex === 1) {
668- if (sim.netReg.status !== "searching")
669- sim.netReg.scan();
670- }
671- }
672- }
673-
674- ListItem.SingleControl {
675- enabled: chooseCarrier.selectedIndex === 1
676- anchors {
677- left: parent.left
678- leftMargin: units.gu(0)
679- }
680- control: ColumnLayout {
681- id: child
682- width: parent.width - units.gu(4)
683- anchors.left: parent.left
684- RowLayout {
685- id: searchingRow
686- spacing: units.gu(1)
687-
688- visible: sim.netReg.status === "searching"
689- ActivityIndicator {
690- id: activityIndicator
691- anchors.verticalCenter: parent.verticalCenter
692- running: parent.visible
693- }
694- Label {
695- anchors.verticalCenter: parent.verticalCenter
696- text: i18n.tr("Searching for carriers…")
697- }
698- }
699- ListItem.ItemSelector {
700- id: carrierSelector
701- objectName: "carriers"
702- expanded: true
703- enabled: sim.netReg.status !== "searching" && chooseCarrier.selectedIndex === 1
704- // work around ItemSelector not having a visual change depending on being disabled
705- opacity: enabled ? 1.0 : 0.5
706- width: parent.width
707- model: operatorNames
708- delegate: OptionSelectorDelegate { enabled: carrierSelector.enabled; showDivider: false }
709- onSelectedIndexChanged: {
710- if (selectedIndex === -1 || d.__suppressActivation)
711- return;
712-
713- // this assumes operator names are unique,
714- // revise if not so
715- for (var op in operators) {
716- if (operators[op].name === operatorNames[selectedIndex]) {
717- operators[op].registerOperator();
718- return;
719- }
720- }
721- // just asserting to verify the logic
722- // remove once proven functional
723- throw "should not be reached.";
724- }
725- }
726- }
727- }
728- ListItem.Standard {
729- text: i18n.tr("APN")
730- progression: true
731- enabled: sim.connMan.powered
732- onClicked: {
733- pageStack.push(Qt.resolvedUrl("PageChooseApn.qml"), {sim: sim})
734+ /* When e.g. the model changes, the selectedIndex is set to
735+ 0. Ignore this, since we never want the selectedIndex to be
736+ anything other than -1. This component is shown only when
737+ registration is "Automatic". */
738+ if (selectedIndex >= 0) {
739+ selectedIndex = -1;
740+ }
741+ }
742+
743+ Behavior on height {
744+ NumberAnimation {
745+ duration: UbuntuAnimation.SnapDuration
746+ }
747+ }
748+
749+ Behavior on opacity {
750+ NumberAnimation {
751+ duration: UbuntuAnimation.SnapDuration
752+ }
753 }
754 }
755 }
756
757=== added file 'plugins/cellular/carriers.js'
758--- plugins/cellular/carriers.js 1970-01-01 00:00:00 +0000
759+++ plugins/cellular/carriers.js 2014-12-16 16:24:38 +0000
760@@ -0,0 +1,106 @@
761+// Map of path to OfonoNetworkOperator objects
762+var _pathToQml = {}
763+
764+/*
765+Given an array of paths, it will create and associate
766+an OfonoNetworkOperator QML object for each new path.
767+
768+It will also delete any QML that is not in given list of paths.
769+
770+@param {Array} paths - Array of operator paths
771+@return {undefined}
772+*/
773+function updateOperatorQML (paths) {
774+ _garbageCollect(paths);
775+ _createQml(paths);
776+}
777+
778+function _garbageCollect (paths) {
779+ var path;
780+ for (path in _pathToQml) {
781+ if (_pathToQml.hasOwnProperty(path)) {
782+ if (paths.indexOf(path) === -1) {
783+ _pathToQml[path].destroy();
784+ delete _pathToQml[path];
785+ }
786+ }
787+ }
788+}
789+
790+function _createQml (paths) {
791+ paths.forEach(function (path, i) {
792+ if (!_pathToQml.hasOwnProperty(path)) {
793+ _pathToQml[path] = netOp.createObject(root, {
794+ 'operatorPath': path
795+ });
796+ }
797+ });
798+}
799+
800+/*
801+Takes a list of paths and returns
802+OfonoNetworkOperator objects for each path.
803+
804+This function will create OfonoNetworkOperator
805+objects.
806+
807+@param {Array} paths - Array of operator paths
808+@param {Array} ignore - Array of operator paths to ignore
809+@return {Array} of OfonoNetworkOperators
810+*/
811+function getOps (paths, ignore) {
812+ var ret = [];
813+ ignore = ignore || [];
814+ paths.forEach(function (op) {
815+ var ofonoOp = getOrCreateOpQml(op);
816+ if (ignore.indexOf(op) >= 0) {
817+ return;
818+ } else if (ofonoOp.status === "forbidden") {
819+ return;
820+ }
821+ ret.push(ofonoOp);
822+ });
823+ return ret;
824+}
825+
826+/*
827+@param path String an operator path
828+@return {Object|null} OfonoNetworkOperator|null - null if no QML exist for path
829+*/
830+function getOp (path) {
831+ if (_pathToQml.hasOwnProperty(path)) {
832+ return _pathToQml[path];
833+ } else {
834+ return null;
835+ }
836+}
837+
838+/*
839+Returns an operator. Before returning it sees
840+if we have created QML for this operator path
841+before. QML is created if not.
842+
843+It is guaranteed that a QML object will be returned.
844+
845+@param {String} path - an operator path
846+@return {Object} OfonoNetworkOperator - the created qml
847+*/
848+function getOrCreateOpQml (path) {
849+ if (getOp(path)) {
850+ return getOp(path);
851+ } else {
852+ _createQml([path]);
853+ return getOp(path);
854+ }
855+}
856+
857+/*
858+Registers operator on path
859+
860+@param {String} path - operator to register
861+@return {undefined}
862+*/
863+function setOp (path) {
864+ var op = getOrCreateOpQml(path);
865+ op.registerOperator();
866+}
867
868=== modified file 'tests/autopilot/ubuntu_system_settings/__init__.py'
869--- tests/autopilot/ubuntu_system_settings/__init__.py 2014-11-18 20:13:35 +0000
870+++ tests/autopilot/ubuntu_system_settings/__init__.py 2014-12-16 16:24:38 +0000
871@@ -277,28 +277,16 @@
872
873 @autopilot.logging.log_action(logger.debug)
874 def change_carrier(self, carrier, sim=None):
875- if sim:
876- carriersPage = self._click_carriers()
877- carrierPage = carriersPage.select_sim(sim)
878- else:
879- carrierPage = self._click_carrier()
880-
881- carrierPage.set_manual()
882- carrierPage.set_carrier(carrier)
883-
884- @autopilot.logging.log_action(logger.debug)
885- def _click_carrier(self):
886- item = self.select_single(objectName='carrier')
887- self.pointing_device.click_object(item)
888- return self.get_root_instance().wait_select_single(
889- objectName='chooseCarrierPage')
890-
891- @autopilot.logging.log_action(logger.debug)
892- def _click_carriers(self):
893- item = self.select_single(objectName='carriers')
894- self.pointing_device.click_object(item)
895- return self.get_root_instance().wait_select_single(
896- objectName='chooseCarriersPage')
897+ carrierApnPage = self._click_carrier_apn()
898+ chooseCarrierPage = carrierApnPage.open_carrier(sim)
899+ chooseCarrierPage.set_carrier(carrier)
900+
901+ @autopilot.logging.log_action(logger.debug)
902+ def _click_carrier_apn(self):
903+ item = self.select_single(objectName='carrierApnEntry')
904+ self.pointing_device.click_object(item)
905+ return self.get_root_instance().wait_select_single(
906+ objectName='carrierApnPage')
907
908 @autopilot.logging.log_action(logger.debug)
909 def select_sim_for_data(self, sim):
910@@ -340,30 +328,42 @@
911 self.pointing_device.click_object(ok)
912
913
914-class PageChooseCarriers(ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase):
915-
916- """Autopilot helper for carrier selection page (multisim)."""
917-
918- @autopilot.logging.log_action(logger.debug)
919- def select_sim(self, sim):
920- return self._select_sim(sim)
921-
922- @autopilot.logging.log_action(logger.debug)
923- def _select_sim(self, sim):
924- item = self.select_single(objectName='%s_carriers' % sim)
925- self.pointing_device.click_object(item)
926+class PageCarrierAndApn(ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase):
927+
928+ """Autopilot helper for carrier/apn entry page (singlesim)."""
929+ @autopilot.logging.log_action(logger.debug)
930+ def open_carrier(self, sim):
931+ return self._click_carrier(sim)
932+
933+ @autopilot.logging.log_action(logger.debug)
934+ def _click_carrier(self, sim):
935+ obj = self.select_single(
936+ objectName='carrier')
937+ self.pointing_device.click_object(obj)
938+ return self.get_root_instance().wait_select_single(
939+ objectName='chooseCarrierPage')
940+
941+
942+class PageCarriersAndApns(
943+ ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase):
944+ """Autopilot helper for carrier/apn entry page (multisim)."""
945+ """Autopilot helper for carrier/apn entry page (singlesim)."""
946+ @autopilot.logging.log_action(logger.debug)
947+ def open_carrier(self, sim):
948+ return self._click_carrier(sim)
949+
950+ @autopilot.logging.log_action(logger.debug)
951+ def _click_carrier(self, sim):
952+ obj = self.select_single(
953+ objectName='%s_carriers' % sim)
954+ self.pointing_device.click_object(obj)
955 return self.get_root_instance().wait_select_single(
956 objectName='chooseCarrierPage')
957
958
959 class PageChooseCarrier(ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase):
960
961- """Autopilot helper for carrier selection page (singlesim)."""
962-
963- @autopilot.logging.log_action(logger.debug)
964- def set_manual(self):
965- item = self.select_single(text='Manually')
966- self.pointing_device.click_object(item)
967+ """Autopilot helper for carrier selection page"""
968
969 @autopilot.logging.log_action(logger.debug)
970 def set_automatic(self):
971@@ -374,7 +374,17 @@
972 # wait for animation, since page.animationRunning.wait_for(False)
973 # does not work?
974 sleep(0.5)
975- item = self.select_single(text=carrier)
976+ allOperators = self.select_single(objectName="allOperators")
977+ otherOperators = self.select_single(objectName="otherOperators")
978+
979+ if allOperators.visible:
980+ opList = allOperators
981+ elif otherOperators.visible:
982+ opList = otherOperators
983+ else:
984+ raise Exception("No operator list visible.")
985+
986+ item = opList.select_single(text=carrier, objectName="carrier")
987 self.pointing_device.click_object(item)
988
989

Subscribers

People subscribed via source and target branches