Merge lp:~ken-vandine/ubuntu-system-settings/rtm-1388044 into lp:ubuntu-system-settings/rtm-14.09
- rtm-1388044
- Merge into rtm-14.09
Proposed by
Ken VanDine
on 2014-12-16
| Status: | Merged |
|---|---|
| Approved by: | Jonas G. Drange on 2015-01-14 |
| 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 |
| Related bugs: |
| Reviewer | Review Type | Date Requested | Status |
|---|---|---|---|
| Jonas G. Drange (community) | 2014-12-16 | Approve on 2015-01-09 | |
| PS Jenkins bot | continuous-integration | Approve on 2014-12-16 | |
|
Review via email:
|
|||
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.
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 |


PASSED: Continuous integration, rev:951 jenkins. qa.ubuntu. com/job/ ubuntu- system- settings- rtm-14. 09-ci/19/ jenkins. qa.ubuntu. com/job/ ubuntu- system- settings- rtm-14. 09-14.09- armhf-ci/ 20 jenkins. qa.ubuntu. com/job/ ubuntu- system- settings- rtm-14. 09-14.09- armhf-ci/ 20/artifact/ work/output/ *zip*/output. zip
http://
Executed test runs:
SUCCESS: http://
deb: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/ubuntu- system- settings- rtm-14. 09-ci/19/ rebuild
http://