Merge lp:~unity-api-team/ubuntu-system-settings/apneditor into lp:ubuntu-system-settings
- apneditor
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Ken VanDine |
Approved revision: | 1119 |
Merged at revision: | 1129 |
Proposed branch: | lp:~unity-api-team/ubuntu-system-settings/apneditor |
Merge into: | lp:ubuntu-system-settings |
Prerequisite: | lp:~jonas-drange/ubuntu-system-settings/cellular-slot2-online-status-not-persisting-1375832 |
Diff against target: |
1590 lines (+1297/-90) 11 files modified
plugins/cellular/CMakeLists.txt (+4/-0) plugins/cellular/Components/CMakeLists.txt (+6/-0) plugins/cellular/Components/MultiSim.qml (+4/-4) plugins/cellular/Components/SingleSim.qml (+4/-3) plugins/cellular/CustomApnEditor.qml (+326/-0) plugins/cellular/PageChooseApn.qml (+610/-0) plugins/cellular/PageChooseCarrier.qml (+163/-80) plugins/cellular/PageChooseCarriers.qml (+4/-3) plugins/cellular/ofonoactivator.cpp (+132/-0) plugins/cellular/ofonoactivator.h (+42/-0) plugins/cellular/plugin.cpp (+2/-0) |
To merge this branch: | bzr merge lp:~unity-api-team/ubuntu-system-settings/apneditor |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ken VanDine | Approve | ||
PS Jenkins bot | continuous-integration | Needs Fixing | |
Iain Lane | Pending | ||
Jonas G. Drange | Pending | ||
Review via email: mp+237138@code.launchpad.net |
This proposal supersedes a proposal from 2014-07-21.
Commit message
Add an APN editor.
Description of the change
Bug affecting the landing:
https:/
As of our platform is not currently able to handle max. 1 MMS APN[0], here is the "logic" of the editor:
- it will always create a custom internet APN if none exists for the system
- ofono provisioning might add Internet APN's that are also used for MMS
- these are identified by having a MessageCenter property set, although
strictly speaking this is violating ofono API
- When user switches between Internet APNs, NetworkManager is told
to activate the selected APN through ofonoActivator:
- as the system is only able to handle one MMS APN, custom MMS APN is only
created if user explicitly configures one
- if there is a provisioned MMS APN it will get removed and one custom one
created
- as the QOfono API does not offer a way to directly access an APN created
with ConnectionManag
MMS APN by magic (isEmptyCustom()) and lazily populate it when detected
(pendingMms
- Any configured MMS APN (both custom and provisioned) will be removed if
user activates a dual Internet APN with MMS capability
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:799
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:800
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:801
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
Iain Lane (laney) wrote : Posted in a previous version of this proposal | # |
Not reviewed, but please make sure to wrap all lines at 80 characters and fix the copyright years.
Jussi Pakkanen (jpakkane) wrote : Posted in a previous version of this proposal | # |
We don't have an 80 character line limit any more. It's 132 now. See for example:
https:/
Iain Lane (laney) wrote : Posted in a previous version of this proposal | # |
On Wed, Jul 23, 2014 at 02:08:11PM -0000, Jussi Pakkanen wrote:
> We don't have an 80 character line limit any more. It's 132 now. See for example:
Who decided this for ubuntu-
--
Iain Lane [ <email address hidden> ]
Debian Developer [ <email address hidden> ]
Ubuntu Developer [ <email address hidden> ]
Sebastien Bacher (seb128) wrote : Posted in a previous version of this proposal | # |
@Jussi, the document you pointed is not from the settings project, we use a 80 chars wrap count here
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:802
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
Iain Lane (laney) wrote : Posted in a previous version of this proposal | # |
On Wed, Jul 23, 2014 at 03:15:53PM -0000, Sebastien Bacher wrote:
> @Jussi, the document you pointed is not from the settings project, we use a 80 chars wrap count here
However we are discussing it - GNOME recommends between 80 and 120 & we
might align on this.
--
Iain Lane [ <email address hidden> ]
Debian Developer [ <email address hidden> ]
Ubuntu Developer [ <email address hidden> ]
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:803
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:805
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:807
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:809
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
Iain Lane (laney) wrote : Posted in a previous version of this proposal | # |
Please could you make sure the AP tests are passing. Also remove all stray warnings.
If this isn't ready - some comments suggest it isn't - set the branch to WIP please.
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:810
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
Jonas G. Drange (jonas-drange) wrote : Posted in a previous version of this proposal | # |
See inline comments. There's some Loader magic going on. Happy to explain, but for now, remove the data preference code in PageComponent as well as the code that re-creates a lot of ofono objects.
Jussi Pakkanen (jpakkane) wrote : Posted in a previous version of this proposal | # |
Fixed one, need some help with the other. Thanks.
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:819
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
Ken VanDine (ken-vandine) wrote : Posted in a previous version of this proposal | # |
There are a number of asserts in the code with comments that they should be removed, like:
// just asserting to verify the logic
// remove once proven functional
Those should probably removed.
There are a number of places with commented out code (like properties), other than the TODOs and place holders for future work. Please remove them if they aren't needed.
Pat McGowan (pat-mcgowan) wrote : Posted in a previous version of this proposal | # |
I see the following output using those debs
2014-08-27 16:23:38,267 - WARNING - file://
2014-08-27 16:23:38,308 - WARNING - QOfonoNetworkOp
2014-08-27 16:23:38,308 - WARNING - registerComplete failed with error: org.ofono.
2014-08-27 16:24:12,488 - WARNING - file://
y "onContextsChanged"
2014-08-27 16:24:12,493 - WARNING - file://
2014-08-27 16:24:12,494 - WARNING - file://
pa
and this is syslog:
Aug 20 09:04:19 ubuntu-phablet URfkill[22242]: Modem found: '/ril_0'
Aug 20 09:04:19 ubuntu-phablet URfkill[22242]: killswitch state: KILLSWITCH_
Aug 20 09:04:19 ubuntu-phablet URfkill[22242]: Setting device 100 (WWAN) to unblocked
Aug 20 09:04:19 ubuntu-phablet URfkill[22242]: device_changed_cb: Fake Manufacturer Fake Modem Model
Aug 20 09:04:19 ubuntu-phablet URfkill[22242]: killswitch state: KILLSWITCH_
Aug 20 09:04:19 ubuntu-phablet URfkill[22242]: <warning> Could not set Online property in oFono: GDBus.Error:
Aug 20 09:04:19 ubuntu-phablet NetworkManager[
er" doesn't exist
Aug 20 09:04:19 ubuntu-phablet /03mmsproxy: Adding route for MMS connection /31041052892425
Aug 20 09:04:19 ubuntu-phablet /03mmsproxy: failed to add route: org.freedesktop
ctionContext" doesn't exist
Aug 20 09:04:19 ubuntu-phablet kernel: [34624.654748] mmc0: mmc_start_bkops: Starting bkops
Aug 20 09:04:20 ubuntu-phablet kernel: [34626.169291] mdm_power_
Aug 20 09:04:21 ubuntu-phablet NetworkManager[
Aug 20 09:04:21 ubuntu-phablet NetworkManager[
Aug 20 09:04:21 ubuntu-phablet NetworkManager[
Aug 20 09:04:21 ubuntu-phablet NetworkManager[
Aug 20 09:04:21 ubuntu-phablet NetworkManager[
Aug 20 09:04:21 ubuntu-phablet NetworkManager[
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:820
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:821
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:822
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
Antti Kaijanmäki (kaijanmaki) wrote : Posted in a previous version of this proposal | # |
OK, after extensive testing this should be good to go.
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:823
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:824
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
Pat McGowan (pat-mcgowan) wrote : Posted in a previous version of this proposal | # |
I get a large number (>50) of these when I enter the APN panel
2014-08-29 08:58:11,004 - WARNING - file://
Pat McGowan (pat-mcgowan) wrote : Posted in a previous version of this proposal | # |
actually the above happens when you scroll the page
Pat McGowan (pat-mcgowan) wrote : Posted in a previous version of this proposal | # |
note to test these debs you need latest from
https:/
Other than the binding loop seems good
Jonas G. Drange (jonas-drange) wrote : Posted in a previous version of this proposal | # |
WFM (krillin, telenor)
Ken VanDine (ken-vandine) wrote : Posted in a previous version of this proposal | # |
CI is failing because you changed the carrierSelector from an ItemSelector to an OptionSelector but didn't change the tests to match.
Ken VanDine (ken-vandine) wrote : Posted in a previous version of this proposal | # |
Inline comment, typo in a visible string.
Antti Kaijanmäki (kaijanmaki) wrote : Posted in a previous version of this proposal | # |
> I get a large number (>50) of these when I enter the APN panel
> 2014-08-29 08:58:11,004 - WARNING - file://
> /qml-plugins/
> Binding loop detected for property "height"
This is a height property of the top level ItemPage which is not even being modified in PageChooseCarri
If this does not affect the UX in any visible way, I would say it's totally minor and no reason to block the landing.
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:973
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:974
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
Ken VanDine (ken-vandine) wrote : Posted in a previous version of this proposal | # |
You're anchoring the buttonRectangle to parent.bottom, which causes it to get pushed up above the input fields when the OSK is displayed. You should put it inside the flickable, so they stay below the inputs.
Ken VanDine (ken-vandine) wrote : Posted in a previous version of this proposal | # |
Testing on krillin, I can't get a working context for my t-mobile US SIM. Looking at the output of list-contexts, it isn't setting the value I entered for MessageCenter.
Looking at the upstart logs, I see this output when trying to set the context:
2014-08-29 15:39:19,973 - CRITICAL - Context error on /ril_0/context3: Invalid arguments in method call
Ken VanDine (ken-vandine) wrote : Posted in a previous version of this proposal | # |
After re-reading the MP description, I see that the failure I get above is consistent with bug 1362068. So apparently this can't work until we get that bug fixed?
Ken VanDine (ken-vandine) wrote : Posted in a previous version of this proposal | # |
The implementation is considerably different from the [1]design, has someone from design looked at this?
Jussi Pakkanen (jpakkane) wrote : Posted in a previous version of this proposal | # |
Here's the design review.
------
Thanks for helping me get the APN settings going on my handset. For
your convenience, I've attached a couple of screenshots of what I see.
Comparing the current implementation with
<https:/
* "On the carrier screen, the “APN” item should be insensitive
whenever the SIM is not associated with a carrier."
When I'm in Flight Mode, (a) the carrier menu is empty, but (b) the
"APN" item is still choosable. At least one of those is wrong
(possibly both).
* On the APN screen, the radio lists are in Ubuntu shapes. If these
are quick to remove, please remove them. Compare with the
"Automatica
looks much nicer.
* "The “Internet APN:” and “MMS APN:” radio lists should each consist
of: * a “None” item, if no APN is currently activated for that
connection type;..."
On my handset, there are two items in the "Internet APN:" list, but
neither of them are selected. If it's really true that no Internet
APN is set on my phone, there should be a selected "None" item.
* Consequently, in the "MMS APN:" list, if I tap "Same APN as for
Internet", I get a dialog: "Error: No Internet APN has been
selected." Abolish this dialog, and instead just make that "Same
APN" item insensitive whenever no Internet APN is selected.
* "Choosing “Custom Internet APN…” or “Custom MMS APN…” should open
the relevant dialog..."
These screens are currently stack pages instead of dialogs. This
means that I can enter some settings, complete or not, then tap
the Back button, and it isn't clear whether those settings will be
saved or not, which is pretty confusing. Even worse, in the "Custom
MMS APN" screen, the "Password" field is hidden partly under the
"Cancel" and "Save" buttons, and partly under the OSK. And the
field labels are weirdly close to the left edge of the screen.
* "“Internet APN”, “MMS APN”, “MMSC”, and “Proxy” should be URL
fields (using the URL OSK and ignoring non-URL characters)..."
Currently, "Internet APN", "MMS APN", "MMSC", and "Proxy" are all
normal text fields, allowing impossible characters, and assuming
that I want to capitalize and spell-check their contents when I do
not.
* "...auto-inserting http:// on unfocus if no protocol was entered."
This doesn't happen.
* When I tap "Activate", even after entering a non-existent APN name,
the settings are apparently accepted without being tried.
Though I'm a perfectionist, I have a low bar for whether a feature is
better than nothing. But that last point is what makes me say no, this
isn't ready to land. If custom APNs aren't implemented at all yet, the
buttons and screens to specify them shouldn't be present, because
that's actively misleading. And if they are implemented, why is a
non-existent APN accepted?
Matthew Paul Thomas (mpt) wrote : Posted in a previous version of this proposal | # |
Antti has explained to me the current asynchronous and uncommunicative API that makes validating a custom APN impossible to implement for MMS, and impractically difficult for Internet, at least without a new API. So I withdraw the last point, and instead suggest that "Activate" should be merely "OK" (since it won't be doing any activation right then).
Antti Kaijanmäki (kaijanmaki) wrote : Posted in a previous version of this proposal | # |
> Here's the design review.
>
> ------
>
> Thanks for helping me get the APN settings going on my handset. For
> your convenience, I've attached a couple of screenshots of what I see.
> Comparing the current implementation with
> <https:/
>
> * "On the carrier screen, the “APN” item should be insensitive
> whenever the SIM is not associated with a carrier."
>
> When I'm in Flight Mode, (a) the carrier menu is empty, but (b) the
> "APN" item is still choosable. At least one of those is wrong
> (possibly both).
Fixed both.
> * On the APN screen, the radio lists are in Ubuntu shapes. If these
> are quick to remove, please remove them. Compare with the
> "Automatically"
> looks much nicer.
We could argue that the OptionSelector looks way better, but let's be consistently ugly ;)
Fixed.
> * "The “Internet APN:” and “MMS APN:” radio lists should each consist
> of: * a “None” item, if no APN is currently activated for that
> connection type;..."
>
> On my handset, there are two items in the "Internet APN:" list, but
> neither of them are selected. If it's really true that no Internet
> APN is set on my phone, there should be a selected "None" item.
Will land this separately when we get nuntium support for multiple MMS APN contexts.
> * Consequently, in the "MMS APN:" list, if I tap "Same APN as for
> Internet", I get a dialog: "Error: No Internet APN has been
> selected." Abolish this dialog, and instead just make that "Same
> APN" item insensitive whenever no Internet APN is selected.
Done. No more dialogs.
> * "Choosing “Custom Internet APN…” or “Custom MMS APN…” should open
> the relevant dialog..."
>
> These screens are currently stack pages instead of dialogs. This
> means that I can enter some settings, complete or not, then tap
> the Back button, and it isn't clear whether those settings will be
> saved or not, which is pretty confusing. Even worse, in the "Custom
> MMS APN" screen, the "Password" field is hidden partly under the
> "Cancel" and "Save" buttons, and partly under the OSK. And the
> field labels are weirdly close to the left edge of the screen.
jgdx takes care of this in a separate landing.
> * "“Internet APN”, “MMS APN”, “MMSC”, and “Proxy” should be URL
> fields (using the URL OSK and ignoring non-URL characters)..."
>
> Currently, "Internet APN", "MMS APN", "MMSC", and "Proxy" are all
> normal text fields, allowing impossible characters, and assuming
> that I want to capitalize and spell-check their contents when I do
> not.
I set the relevant hints, but seems the TextField is not validating based on them. We should at least now get a custom OSK for them.
> * "...auto-inserting http:// on unfocus if no protocol was entered."
>
> This doesn't happen.
Nope. Will either fix this on the next landing or file a medium bug.
Antti Kaijanmäki (kaijanmaki) wrote : Posted in a previous version of this proposal | # |
> Antti has explained to me the current asynchronous and uncommunicative API
> that makes validating a custom APN impossible to implement for MMS, and
> impractically difficult for Internet, at least without a new API. So I
> withdraw the last point, and instead suggest that "Activate" should be merely
> "OK" (since it won't be doing any activation right then).
For Internet it's "Activate" as that we can actually try to activate but don't get any feedback if it succeeds or not. If the config is bad, NM starts to try the other available APNs until it either finds one that works or gives up. You see the selected APN changing in the list while NM does it's magic.
For MMS it's "Save" as that is what it does.
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:977
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
Antti Kaijanmäki (kaijanmaki) wrote : Posted in a previous version of this proposal | # |
APN editor: Buttons stay pressed after first tap:
https:/
APN editor: Grey selection box when tapping just below/above the last/first entry.
https:/
APN editor: Pressing enter key should shift focus to next field.
https:/
APN editor: Selected APN states don't persist on exit and re-entry
https:/
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:978
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
Ken VanDine (ken-vandine) wrote : Posted in a previous version of this proposal | # |
Please put the button rectangle inside the flickable instead of anchoring the flickable to the top. We've run into this problem in a number of places in other plugins, putting them inside the flickable has worked out much better.
Please see inline comments
Jonas G. Drange (jonas-drange) wrote : Posted in a previous version of this proposal | # |
Could you quickly improve the throwing of exceptions? It might be a bit cryptic as it is?
Also, I added a comment about the tmp variable not being a copy (forgive me if that was intended) and a small inconsistency referring to the __suppress… flag.
See inline comments.
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:981
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:982
http://
Executed test runs:
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:984
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
- 1111. By Launchpad Translations on behalf of system-settings-touch
-
Launchpad automatic translations update.
Pat McGowan (pat-mcgowan) wrote : | # |
Installed packages from the silo and tested the UI.
I made a test apn that did not work and the selection for active went back to the original.
My second sim has no signal so the UI did not enable the APN editing option which I assume is intended.
It occurs to me there seems to be a flaw in the general UI. If "Same APN as for internet" is enabled then the custom internet APN page needs to include the MMS settings.
The custom panel was supposed to be pre-populated with the currently active APN information.
Choosing “Custom Internet APN…” or “Custom MMS APN…” should open the relevant dialog, pre-filled with the details of the already-selected APN so that you can view, tweak, or replace them as necessary.
I wonder if we should also show the protocol field as IPv4 without an option to change it.
Pat McGowan (pat-mcgowan) wrote : | # |
I tried to make a custom Internet APN that matched the active one and it would not be accepted
Context2 below is what is being used, context3 I made. Note the "settings" are missing from our editor,not sure if they are required.
[ /ril_0 ]
[ /ril_0/context1 ]
Password =
Settings = { }
Type = internet
Username =
Active = 0
Name = ATT Phone
Protocol = ip
[ /ril_0/context2 ]
Password =
Settings = { Gateway=
Type = internet
Username =
Active = 1
Name = ATT WAP
Protocol = ip
[ /ril_0/context3 ]
Password =
Settings = { }
Type = internet
Username =
Active = 0
Name = ___ubuntu_
Protocol = ip
Pat McGowan (pat-mcgowan) wrote : | # |
T-Mobile users simply need to create a custom apn with a change of protocol from ipv6 to ip(v4). The UI will not be clear to them, they will see a custom APN that looks the same as their current APN since we do not show the protocol field. Be nice to illustrate the faulty setting perhaps.
[ /ril_1 ]
[ /ril_1/context1 ]
Username =
Settings = { }
Protocol = ipv6
Active = 0
Name = T-Mobile GPRS
Password =
Type = internet
Antti Kaijanmäki (kaijanmaki) wrote : Posted in a previous version of this proposal | # |
Fixed by the review comments in r980. The only non-trivial comments are:
Ken VanDine (ken-vandine) wrote:
> I think you shouldn't be anchoring to the buttonRectangle,
> the buttonRectangle should be in the Flickable.
Yes. I know, but in this case the user usually just enters two of the top fields and having the buttons always visible has some value. I took great care on verifying that the buttons react properly on the viewport changes. If I get it to break on my last testing round, then I will put the buttons inside the flickable, OK?
Ken VanDine (ken-vandine) wrote:
> Does this really return an empty list?
> Perhaps it would be safer to set connections to a QStringList()
the connection list is an array of object paths. QDBusPendingReply quarantees that .value() returns a default constructed T, which in this case is an empty array of dbus-paths.
For the logic that follows it's really irrelevant if an empty list is received (that is also a valid reply).
Antti Kaijanmäki (kaijanmaki) wrote : Posted in a previous version of this proposal | # |
Now resolving merge conflicts.
IMHO the dynamic SIM logic is a bit broken, but it's more or less a design question. Let's continue on that after this MP is in.
Antti Kaijanmäki (kaijanmaki) wrote : | # |
> Installed packages from the silo and tested the UI.
> I made a test apn that did not work and the selection for active went back to
> the original.
OK, this needs a bit more investigating. Was it an Internet APN or MMS?
https:/
possible causes: ofono not updating the Active properties correctly, NM not setting the Active properties correctly, APN editor not reacting to the Active properties correctly.
> My second sim has no signal so the UI did not enable the APN editing option
> which I assume is intended.
Yes, you can only access the APN editor page if your phone is registered to a network.
> It occurs to me there seems to be a flaw in the general UI. If "Same APN as
> for internet" is enabled then the custom internet APN page needs to include
> the MMS settings.
>
> The custom panel was supposed to be pre-populated with the currently active
> APN information.
> Choosing “Custom Internet APN…” or “Custom MMS APN…” should open the relevant
> dialog, pre-filled with the details of the already-selected APN so that you
> can view, tweak, or replace them as necessary.
This is for provisioned APN's. The ones that come from ofono and android provider database. Such Internet APNs can and do define shared APN's. You can't create one right now through the UI. If the provisioning fails for both Internet and MMS, then yes, the user would need to create two separate APN's (one for Internet, one for MMS).
We don't allow editing of the provisioned APNs (for now). There is only one Custom APN which is separate from the provisioned ones.
The whole "use the same values as for Internet" in the MMS editor was getting so messy that I disabled that toggle for now. We should enable that once we allow editing of the provisioned APNs.
> I wonder if we should also show the protocol field as IPv4 without an option
> to change it.
My opinion this would be that we keep it hidden until we actually support both.
Antti Kaijanmäki (kaijanmaki) wrote : | # |
> I tried to make a custom Internet APN that matched the active one and it would
> not be accepted
:/
> Context2 below is what is being used, context3 I made. Note the "settings" are
> missing from our editor,not sure if they are required.
>
> [ /ril_0 ]
> [ /ril_0/context1 ]
> IPv6.Settings = { }
> Password =
> Settings = { }
> MessageCenter = http://
> MessageProxy = proxy.mobile.
> Type = internet
> Username =
> Active = 0
> Name = ATT Phone
> Protocol = ip
> AccessPointName = nxtgenphone
>
> [ /ril_0/context2 ]
> IPv6.Settings = { }
> Password =
> Settings = { Gateway=
> DomainNameServe
> Method=static Address=
> MessageCenter = http://
> MessageProxy = wireless.
> Type = internet
> Username =
> Active = 1
> Name = ATT WAP
> Protocol = ip
> AccessPointName = wap.cingular
>
> [ /ril_0/context3 ]
> IPv6.Settings = { }
> Password =
> Settings = { }
> Type = internet
> Username =
> Active = 0
> Name = ___ubuntu_
> Protocol = ip
> AccessPointName = wap.cingular
the data looks valid, it's just the static DNS and IP assignments that worry me. We don't support that in the editor right now. I'll finish my testing as it could be that you have just unlucky settings on your SIM that we can't support right now.
Antti Kaijanmäki (kaijanmaki) wrote : | # |
> T-Mobile users simply need to create a custom apn with a change of protocol
> from ipv6 to ip(v4). The UI will not be clear to them, they will see a custom
> APN that looks the same as their current APN since we do not show the protocol
> field. Be nice to illustrate the faulty setting perhaps.
>
> [ /ril_1 ]
> [ /ril_1/context1 ]
> Username =
> Settings = { }
> Protocol = ipv6
> AccessPointName = fast.t-mobile.com
> IPv6.Settings = { }
> Active = 0
> Name = T-Mobile GPRS
> MessageProxy =
> MessageCenter = http://
> Password =
> Type = internet
Is that above now faulty or not?
So, this is an automatically provisioned APN, right? As I said above, we don't currently support editing provisioned APNs. Instead we should modify the file we use for provisioning and change the protocol there directly.
OR if we now do support also IPv6 APNs then we must include the protocol field to the editor.
Ken VanDine (ken-vandine) wrote : | # |
It's not activating my custom internet APN for t-mobile. After creating it, it goes back out and neither are selected. After a few seconds the provisioned APN is selected again instead of the custom. Here's the output of list-contexts:
[ /ril_0 ]
[ /ril_0/context1 ]
Name = T-Mobile GPRS
Password =
Type = internet
Settings = { Netmask=
Protocol = ip
Username =
Active = 1
[ /ril_0/context2 ]
Name = ___ubuntu_
Password =
Type = internet
Settings = { }
Protocol = ip
Username =
Active = 0
[ /ril_0/context3 ]
Name = ___ubuntu_
Password =
Type = mms
Settings = { }
Protocol = ip
Username =
Active = 0
Antti Kaijanmäki (kaijanmaki) wrote : | # |
> It's not activating my custom internet APN for t-mobile. After creating it,
> it goes back out and neither are selected. After a few seconds the
> provisioned APN is selected again instead of the custom. Here's the output of
> list-contexts:
>
> [ /ril_0 ]
> [ /ril_0/context1 ]
> Name = T-Mobile GPRS
> Password =
> IPv6.Settings = { }
> Type = internet
> Settings = { Netmask=
> DomainNameServe
> Gateway=
> Protocol = ip
> AccessPointName = fast.t-mobile.com
> Username =
> MessageCenter = http://
> MessageProxy =
> Active = 1
>
> [ /ril_0/context2 ]
> Name = ___ubuntu_
> Password =
> IPv6.Settings = { }
> Type = internet
> Settings = { }
> Protocol = ip
> AccessPointName = fast.t-mobile.com
> Username =
> Active = 0
>
> [ /ril_0/context3 ]
> Name = ___ubuntu_
> Password =
> IPv6.Settings = { }
> Type = mms
> Settings = { }
> Protocol = ip
> AccessPointName = fast.t-mobile.com
> Username =
> MessageCenter = http://
> MessageProxy =
> Active = 0
We identified a NM bug which prevents activating Custom Internet APN if there already is a provisioned one active at the same time.
There also was a bug in switching between multiple provisioned Internet APNs, now fixed in the branch.
Ken VanDine (ken-vandine) wrote : | # |
I'll approve the code, it seems to work in the case where the user doesn't have a context that can be activated. I want to wait until we triage the NM bug before top approving and preparing to land.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:987
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
- 1114. By Launchpad Translations on behalf of system-settings-touch
-
Launchpad automatic translations update.
Mathieu Trudel-Lapierre (cyphermox) wrote : | # |
I think the activation of new contexts should also be fixed at the APN editor level. You should be able to explicitly Disconnect an interface if it's found to currently be connected as per NetworkManager, without having to bother with which context was activated. Once disconnected, you would be able to freely activate a new context.
The issue with doing automatic deactivation just before activating a new context in NM directly is that all of these are time-sensitive operations; and can't be run synchronously (otherwise it would cause visible delays when you try to activate the connection and weird behavior in the indicators). When running them async; it's still possible for the disconnect to be delayed enough that the deactivation of the old context and activation of the new one to happen pretty much simultaneously; in other words, you'll still risk failure cases; which can be safely avoided by explicitly disconnecting the device and connecting a new context altogether when trying to activate a newly-created context.
Ken VanDine (ken-vandine) wrote : | # |
I agree with what Mathieu said, we should handle it in the apneditor. Fixing it in NM is nice too, but we should still do the disconnect ourselves.
- 1115. By Jonas G. Drange
-
[wifi/phone] dynamically chooses what SIM to use when there's only one present. Fixes: 1375832
Approved by: Ken VanDine, PS Jenkins bot - 1116. By PS Jenkins bot
-
Releasing 0.3+14.
10.20141007- 0ubuntu1 - 1117. By Launchpad Translations on behalf of system-settings-touch
-
Launchpad automatic translations update.
- 1118. By Launchpad Translations on behalf of system-settings-touch
-
Launchpad automatic translations update.
- 1119. By Ken VanDine
-
merged apneditor
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:988
http://
Executed test runs:
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1119
http://
Executed test runs:
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
Pat McGowan (pat-mcgowan) wrote : | # |
When there is no working APN I can define and activate a new Internet APN
When there is a working APN, no other APNs will activate
I can define an MMS APN which matches the existing working dual internet/mms APN, but it will not activate. The UI shows it selected however.
I suspect that AT&T may not support activating 2 different APNs and the UI should support defining an internet apn that does both.
The custom internet apn screen offers cancel and activate while the mms screen offers cancel and save.
Antti Kaijanmäki (kaijanmaki) wrote : | # |
> When there is no working APN I can define and activate a new Internet APN
> When there is a working APN, no other APNs will activate
Are the other APNs valid? You can only activate a valid APN.
> I can define an MMS APN which matches the existing working dual internet/mms
> APN, but it will not activate. The UI shows it selected however.
MMS APNs activate only for a short period of time when MMS message is either sent or received. ofono Activate is not applicable here. The selection is correct, as you only have a single MMS context, so that one is the one that nuntium will use.
> The custom internet apn screen offers cancel and activate while the mms screen
> offers cancel and save.
This is agreed with mpt, I though the design has also been updated. Internet APN can be activated, but MMS apn can only be saved. hence the difference.
Ken VanDine (ken-vandine) wrote : | # |
I think we need to get this landed and iterate to improve it. It seems to create a valid APN for some networks.
Preview Diff
1 | === modified file 'plugins/cellular/CMakeLists.txt' |
2 | --- plugins/cellular/CMakeLists.txt 2014-08-17 14:50:51 +0000 |
3 | +++ plugins/cellular/CMakeLists.txt 2014-10-09 14:10:12 +0000 |
4 | @@ -4,6 +4,8 @@ |
5 | install(FILES settings-cellular.svg DESTINATION ${PLUGIN_MANIFEST_DIR}/icons) |
6 | |
7 | set(QML_SOURCES |
8 | + CustomApnEditor.qml |
9 | + PageChooseApn.qml |
10 | PageChooseCarrier.qml |
11 | PageChooseCarriers.qml |
12 | PageComponent.qml |
13 | @@ -18,6 +20,8 @@ |
14 | plugin.h |
15 | hotspotmanager.cpp |
16 | hotspotmanager.h |
17 | + ofonoactivator.cpp |
18 | + ofonoactivator.h |
19 | nm_manager_proxy.h |
20 | nm_settings_proxy.h |
21 | nm_settings_connection_proxy.h |
22 | |
23 | === modified file 'plugins/cellular/Components/CMakeLists.txt' |
24 | --- plugins/cellular/Components/CMakeLists.txt 2014-08-21 20:25:08 +0000 |
25 | +++ plugins/cellular/Components/CMakeLists.txt 2014-10-09 14:10:12 +0000 |
26 | @@ -9,3 +9,9 @@ |
27 | SimEditor.qml |
28 | ) |
29 | install(FILES ${QML_SOURCES} DESTINATION ${PLUGIN_QML_DIR}/cellular/Components) |
30 | + |
31 | +# add a phony target to get the files visible in Qt Creator. |
32 | +add_custom_target( |
33 | + plugins_cellular_components_sources |
34 | + SOURCES ${QML_SOURCES} |
35 | +) |
36 | |
37 | === modified file 'plugins/cellular/Components/MultiSim.qml' |
38 | --- plugins/cellular/Components/MultiSim.qml 2014-08-19 23:24:04 +0000 |
39 | +++ plugins/cellular/Components/MultiSim.qml 2014-10-09 14:10:12 +0000 |
40 | @@ -33,7 +33,7 @@ |
41 | property var settings: phoneSettings |
42 | |
43 | CellularMultiSim { |
44 | - anchors { left: parent.left; right: parent.right } |
45 | + anchors { left: parent.left; right: parent.right } |
46 | } |
47 | |
48 | ListItem.Divider {} |
49 | @@ -79,13 +79,13 @@ |
50 | ListItem.Divider {} |
51 | |
52 | SimEditor { |
53 | - anchors { left: parent.left; right: parent.right } |
54 | + anchors { left: parent.left; right: parent.right } |
55 | } |
56 | |
57 | ListItem.Divider {} |
58 | |
59 | DefaultSim { |
60 | - anchors { left: parent.left; right: parent.right } |
61 | + anchors { left: parent.left; right: parent.right } |
62 | } |
63 | |
64 | GSettings { |
65 | @@ -99,7 +99,7 @@ |
66 | if (!simNames[m0]) { |
67 | simNames[m0] = "SIM 1"; |
68 | } |
69 | - if (!simNames[m1]) { |
70 | + if (!simNames[m1]) { |
71 | simNames[m1] = "SIM 2"; |
72 | } |
73 | phoneSettings.simNames = simNames; |
74 | |
75 | === modified file 'plugins/cellular/Components/SingleSim.qml' |
76 | --- plugins/cellular/Components/SingleSim.qml 2014-08-22 10:53:16 +0000 |
77 | +++ plugins/cellular/Components/SingleSim.qml 2014-10-09 14:10:12 +0000 |
78 | @@ -28,10 +28,10 @@ |
79 | property var sim |
80 | |
81 | CellularSingleSim { |
82 | - anchors { left: parent.left; right: parent.right } |
83 | + anchors { left: parent.left; right: parent.right } |
84 | } |
85 | |
86 | - ListItem.Divider {} |
87 | + ListItem.Divider {} |
88 | |
89 | ListItem.SingleValue { |
90 | text : i18n.tr("Hotspot disabled because Wi-Fi is off.") |
91 | @@ -60,9 +60,10 @@ |
92 | objectName: "chooseCarrier" |
93 | progression: enabled |
94 | value: sim.netReg.name || i18n.tr("N/A") |
95 | + enabled: sim.netReg.status !== "" |
96 | onClicked: { |
97 | pageStack.push(Qt.resolvedUrl("../PageChooseCarrier.qml"), { |
98 | - netReg: sim.netReg, |
99 | + sim: sim, |
100 | title: i18n.tr("Carrier") |
101 | }) |
102 | } |
103 | |
104 | === added file 'plugins/cellular/CustomApnEditor.qml' |
105 | --- plugins/cellular/CustomApnEditor.qml 1970-01-01 00:00:00 +0000 |
106 | +++ plugins/cellular/CustomApnEditor.qml 2014-10-09 14:10:12 +0000 |
107 | @@ -0,0 +1,326 @@ |
108 | +/* |
109 | + * This file is part of system-settings |
110 | + * |
111 | + * Copyright (C) 2014 Canonical Ltd. |
112 | + * |
113 | + * Contact: Pat McGowan <pat.mcgowan@canonical.com> |
114 | + * |
115 | + * This program is free software: you can redistribute it and/or modify it |
116 | + * under the terms of the GNU General Public License version 3, as published |
117 | + * by the Free Software Foundation. |
118 | + * |
119 | + * This program is distributed in the hope that it will be useful, but |
120 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
121 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
122 | + * PURPOSE. See the GNU General Public License for more details. |
123 | + * |
124 | + * You should have received a copy of the GNU General Public License along |
125 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
126 | + */ |
127 | + |
128 | +import QtQuick 2.0 |
129 | +import QtQuick.Layouts 1.1 |
130 | +import SystemSettings 1.0 |
131 | +import Ubuntu.Components 1.1 |
132 | +import Ubuntu.Components.ListItems 1.0 as ListItem |
133 | + |
134 | +ItemPage { |
135 | + objectName: "customapnPage" |
136 | + id: root |
137 | + |
138 | + // "internet" or "mms" |
139 | + property var type |
140 | + |
141 | + // dict of "type" : ctx |
142 | + property var contexts; |
143 | + |
144 | + /// work around LP(#1361919) |
145 | + property var activateCb; |
146 | + |
147 | + QtObject { |
148 | + id: d |
149 | + property var typeText : type === "internet" ? i18n.tr("Internet") : i18n.tr("MMS") |
150 | + property bool isMms : type === "mms" |
151 | + |
152 | + property bool isValid : false |
153 | + |
154 | + function validateFields() { |
155 | + if (apnName.text === "") { |
156 | + isValid = false; |
157 | + return |
158 | + } |
159 | + if (isMms) { |
160 | + if (mmsc.text === "") { |
161 | + isValid = false; |
162 | + return; |
163 | + } |
164 | + /// @todo validate proxy |
165 | + /// @todo force port to be integer and validate it's value |
166 | + } |
167 | + |
168 | + // @todo the rest |
169 | + isValid = true; |
170 | + } |
171 | + } |
172 | + |
173 | + //TRANSLATORS: %1 is either i18n.tr("Internet") or i18n.tr("MMS") |
174 | + title: i18n.tr("Custom %1 APN").arg(d.typeText) |
175 | + |
176 | + // workaround of getting the following error on startup: |
177 | + // WARNING - ... : QML Page: Binding loop detected for property "flickable" |
178 | + flickable: null |
179 | + Component.onCompleted: { |
180 | + flickable: scrollWidget |
181 | + |
182 | + var ctx; |
183 | + if (d.isMms) { |
184 | + ctx = contexts["mms"]; |
185 | + if (ctx === undefined) { |
186 | + // @bug LP(:#1362795) |
187 | + return; |
188 | + } |
189 | + } else { |
190 | + ctx = contexts["internet"] |
191 | + } |
192 | + |
193 | + apnName.text = ctx.accessPointName; |
194 | + userName.text = ctx.username; |
195 | + pword.text = ctx.password; |
196 | + mmsc.text = ctx.messageCenter; |
197 | + var proxyText = ctx.messageProxy.split(":"); |
198 | + proxy.text = proxyText[0] !== undefined ? proxyText[0] : ""; |
199 | + port.text = proxyText[1] !== undefined ? proxyText[1] : ""; |
200 | + /// @todo protocol values |
201 | + |
202 | + if (d.isMms) { |
203 | + /// @todo disabled for now |
204 | + doBoth.checked = false; |
205 | + return; |
206 | + var internetApn = contexts["internet"] |
207 | + if (ctx.accessPointName === internetApn.accessPointName && |
208 | + ctx.username == internetApn.username && |
209 | + ctx.password == internetApn.password |
210 | + /* auth + procol */) { |
211 | + doBoth.checked = true; |
212 | + } |
213 | + else |
214 | + doBoth.checked = false; |
215 | + } |
216 | + } |
217 | + |
218 | + Flickable { |
219 | + id: scrollWidget |
220 | + anchors { |
221 | + top: parent.top |
222 | + left: parent.left |
223 | + right: parent.right |
224 | + bottom: parent.bottom |
225 | + margins: units.gu(2) |
226 | + } |
227 | + contentWidth: parent.width |
228 | + clip: true |
229 | + contentHeight: theContents.height |
230 | + boundsBehavior: (contentHeight > height) ? Flickable.DragAndOvershootBounds : Flickable.StopAtBounds |
231 | + flickableDirection: Flickable.VerticalFlick |
232 | + |
233 | + ColumnLayout { |
234 | + id: theContents |
235 | + anchors { |
236 | + left: parent.left |
237 | + right: parent.right |
238 | + } |
239 | + spacing: units.gu(2) |
240 | + |
241 | + ListItem.Standard { |
242 | + id: sameSwitch |
243 | + anchors { |
244 | + left: parent.left |
245 | + right: parent.right |
246 | + } |
247 | + /// @todo disable for now |
248 | + //visible: d.isMms |
249 | + visible: false |
250 | + text: i18n.tr("Same APN as for Internet") |
251 | + control: Switch { |
252 | + id: doBoth |
253 | + checked: false |
254 | + anchors.verticalCenter: parent.verticalCenter |
255 | + onClicked: { |
256 | + if (checked) { |
257 | + var internetApn = contexts["internet"] |
258 | + apnName.text = internetApn.accessPointName; |
259 | + userName.text = internetApn.username; |
260 | + pword.text = internetApn.password; |
261 | + } |
262 | + } |
263 | + } |
264 | + } |
265 | + |
266 | + GridLayout { |
267 | + id: theGrid |
268 | + columns: 2 |
269 | + columnSpacing: units.gu(1) |
270 | + rowSpacing: units.gu(1) |
271 | + anchors{ |
272 | + right: parent.right |
273 | + left:parent.left |
274 | + } |
275 | + |
276 | + Label { |
277 | + //TRANSLATORS: %1 is either i18n.tr("Internet") or i18n.tr("MMS") |
278 | + text: i18n.tr("%1 APN").arg(d.typeText) |
279 | + } |
280 | + TextField { |
281 | + id: apnName |
282 | + enabled: !doBoth.checked |
283 | + onTextChanged: d.validateFields() |
284 | + inputMethodHints: Qt.ImhUrlCharactersOnly | Qt.ImhNoAutoUppercase | Qt.ImhNoPredictiveText |
285 | + } |
286 | + |
287 | + Label { |
288 | + text: i18n.tr("MMSC") |
289 | + visible: d.isMms |
290 | + } |
291 | + TextField { |
292 | + id: mmsc |
293 | + visible: d.isMms |
294 | + onTextChanged: d.validateFields() |
295 | + inputMethodHints: Qt.ImhUrlCharactersOnly | Qt.ImhNoAutoUppercase | Qt.ImhNoPredictiveText |
296 | + } |
297 | + Label { |
298 | + text: i18n.tr("Proxy") |
299 | + visible: d.isMms |
300 | + } |
301 | + TextField { |
302 | + id: proxy |
303 | + visible: d.isMms |
304 | + onTextChanged: d.validateFields() |
305 | + inputMethodHints: Qt.ImhUrlCharactersOnly | Qt.ImhNoAutoUppercase | Qt.ImhNoPredictiveText |
306 | + } |
307 | + Label { |
308 | + text: "Port" |
309 | + visible: d.isMms |
310 | + } |
311 | + TextField { |
312 | + id: port |
313 | + visible: d.isMms |
314 | + maximumLength: 4 |
315 | + onTextChanged: d.validateFields() |
316 | + inputMethodHints: Qt.ImhDigitsOnly | Qt.ImhNoAutoUppercase | Qt.ImhNoPredictiveText |
317 | + } |
318 | + |
319 | + Label { |
320 | + text: i18n.tr("Username") |
321 | + } |
322 | + TextField { |
323 | + id: userName |
324 | + enabled: !doBoth.checked |
325 | + inputMethodHints: Qt.ImhNoAutoUppercase | Qt.ImhNoPredictiveText |
326 | + } |
327 | + |
328 | + Label { |
329 | + text: i18n.tr("Password") |
330 | + } |
331 | + TextField { |
332 | + id: pword |
333 | + enabled: !doBoth.checked |
334 | + inputMethodHints: Qt.ImhNoAutoUppercase | Qt.ImhNoPredictiveText |
335 | + } |
336 | + /// @todo support for ipv6 will be added after RTM |
337 | + } |
338 | + |
339 | + Item { |
340 | + id: buttonRectangle |
341 | + |
342 | + height: cancelButton.height + units.gu(2) |
343 | + |
344 | + anchors { |
345 | + left: parent.left |
346 | + right: parent.right |
347 | + } |
348 | + |
349 | + Button { |
350 | + id: cancelButton |
351 | + |
352 | + text: i18n.tr("Cancel") |
353 | + |
354 | + anchors { |
355 | + left: parent.left |
356 | + right: parent.horizontalCenter |
357 | + bottom: parent.bottom |
358 | + topMargin: units.gu(1) |
359 | + rightMargin: units.gu(1) |
360 | + bottomMargin: units.gu(1) |
361 | + } |
362 | + |
363 | + onClicked: { |
364 | + pageStack.pop() |
365 | + } |
366 | + } |
367 | + |
368 | + Button { |
369 | + id: confirmButton |
370 | + |
371 | + text: d.isMms ? i18n.tr("Save") : i18n.tr("Activate") |
372 | + |
373 | + anchors { |
374 | + left: parent.horizontalCenter |
375 | + right: parent.right |
376 | + bottom: parent.bottom |
377 | + topMargin: units.gu(1) |
378 | + leftMargin: units.gu(1) |
379 | + rightMargin: units.gu(4) |
380 | + bottomMargin: units.gu(1) |
381 | + } |
382 | + |
383 | + enabled: d.isValid; |
384 | + |
385 | + onClicked: { |
386 | + var ctx; |
387 | + if (d.isMms) |
388 | + ctx = contexts["mms"]; |
389 | + else |
390 | + ctx = contexts["internet"]; |
391 | + |
392 | + /// @bug LP(:#1362795) |
393 | + if (d.isMms && ctx === undefined) { |
394 | + var mmsData = ({}) |
395 | + mmsData["accessPointName"] = apnName.text; |
396 | + mmsData["username"] = userName.text; |
397 | + mmsData["password"] = pword.text; |
398 | + mmsData["messageCenter"] = mmsc.text |
399 | + var proxyValue = ""; |
400 | + if (proxy.text !== "") { |
401 | + proxyValue = proxy.text; |
402 | + if (port.text !== "") |
403 | + proxyValue = proxyValue + ":" + port.text; |
404 | + } |
405 | + mmsData["messageProxy"] = proxyValue; |
406 | + activateCb("mms", undefined, mmsData); |
407 | + pageStack.pop(); |
408 | + return; |
409 | + } |
410 | + |
411 | + ctx.accessPointName = apnName.text; |
412 | + ctx.username = userName.text; |
413 | + ctx.password = pword.text; |
414 | + if (d.isMms) { |
415 | + ctx.messageCenter = mmsc.text; |
416 | + var proxyValue = ""; |
417 | + if (proxy.text !== "") { |
418 | + proxyValue = proxy.text; |
419 | + if (port.text !== "") |
420 | + proxyValue = proxyValue + ":" + port.text; |
421 | + } |
422 | + ctx.messageProxy = proxyValue |
423 | + } |
424 | + /// @todo map protocol values |
425 | + |
426 | + activateCb(ctx.type, ctx.contextPath); |
427 | + pageStack.pop(); |
428 | + } |
429 | + } |
430 | + } // item for buttons |
431 | + } // the contents |
432 | + } // the flickable |
433 | +} |
434 | |
435 | === added file 'plugins/cellular/PageChooseApn.qml' |
436 | --- plugins/cellular/PageChooseApn.qml 1970-01-01 00:00:00 +0000 |
437 | +++ plugins/cellular/PageChooseApn.qml 2014-10-09 14:10:12 +0000 |
438 | @@ -0,0 +1,610 @@ |
439 | +/* |
440 | + * This file is part of system-settings |
441 | + * |
442 | + * Copyright (C) 2014 Canonical Ltd. |
443 | + * |
444 | + * Contact: Pat McGowan <pat.mcgowan@canonical.com> |
445 | + * |
446 | + * This program is free software: you can redistribute it and/or modify it |
447 | + * under the terms of the GNU General Public License version 3, as published |
448 | + * by the Free Software Foundation. |
449 | + * |
450 | + * This program is distributed in the hope that it will be useful, but |
451 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
452 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
453 | + * PURPOSE. See the GNU General Public License for more details. |
454 | + * |
455 | + * You should have received a copy of the GNU General Public License along |
456 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
457 | + */ |
458 | + |
459 | +import QtQuick 2.0 |
460 | +import SystemSettings 1.0 |
461 | +import Ubuntu.Components 1.1 |
462 | +import Ubuntu.Components.Popups 0.1 |
463 | +import Ubuntu.Components.ListItems 0.1 as ListItem |
464 | +import MeeGo.QOfono 0.2 |
465 | +import Ubuntu.SystemSettings.Cellular 1.0 |
466 | + |
467 | +ItemPage { |
468 | + id: root |
469 | + title: i18n.tr("APN") |
470 | + objectName: "apnPage" |
471 | + |
472 | + property var sim |
473 | + |
474 | + QtObject { |
475 | + id: d |
476 | + |
477 | + // map of contextPath : connCtx |
478 | + property var mContexts: ({}) |
479 | + |
480 | + readonly property string mCustomContextNameInternet: "___ubuntu_custom_apn_internet" |
481 | + readonly property string mCustomContextNameMms: "___ubuntu_custom_apn_mms" |
482 | + property var mCustomContextInternet : undefined |
483 | + property var mCustomContextMms : undefined |
484 | + |
485 | + // LP(:#1362795) |
486 | + property var pendingCustomMmsData : ({}) |
487 | + |
488 | + // suppress any actions that we don't want to take |
489 | + // when updating selectedIndexes, etc |
490 | + property bool __suppressActivation : true; |
491 | + |
492 | + function isEmptyCustom (type, ctx) |
493 | + { |
494 | + /* OK, this sucks _hard_, |
495 | + * QOfono does not return the added context, so instead we have to "figure it out" |
496 | + * by looking for "contextAdded" for totally empty context with default Name values. |
497 | + * LP(#1361864) |
498 | + */ |
499 | + |
500 | + var targetName = ""; |
501 | + var targetAccessPointName = ""; |
502 | + if (type === "internet") { |
503 | + targetName = "Internet"; |
504 | + targetAccessPointName = ""; |
505 | + } else if (type == "mms") { |
506 | + targetName = "MMS"; |
507 | + targetAccessPointName = ""; |
508 | + } |
509 | + |
510 | + if (ctx.type === type && |
511 | + ctx.name === targetName && |
512 | + ctx.accessPointName === targetAccessPointName) |
513 | + return true; |
514 | + return false; |
515 | + } |
516 | + |
517 | + function updateContexts() |
518 | + { |
519 | + var tmp = sim.connMan.contexts.slice(0); |
520 | + var added = tmp.filter(function(i) { |
521 | + return mContexts[i] === undefined; |
522 | + }); |
523 | + var removed = Object.keys(mContexts).filter(function(i) { |
524 | + return tmp.indexOf(i) === -1; |
525 | + }) |
526 | + |
527 | + removed.forEach(function(currentValue, index, array) { |
528 | + // just asserting to verify the logic |
529 | + // remove once proven functional |
530 | + // the exception gives a very nice log error message from QmlEngine and does not |
531 | + // have any side effects |
532 | + if (mContexts[currentValue] === undefined) { |
533 | + throw "updateContexts: removed is broken"; |
534 | + } |
535 | + |
536 | + if (mContexts[currentValue].name === mCustomContextNameInternet) |
537 | + mCustomContextInternet = undefined |
538 | + else if (mContexts[currentValue].name === mCustomContextNameMms) |
539 | + mCustomContextMms = undefined |
540 | + |
541 | + mContexts[currentValue].destroy(); |
542 | + delete mContexts[currentValue]; |
543 | + }); |
544 | + |
545 | + added.forEach(function(currentValue, index, array) { |
546 | + // just asserting to verify the logic |
547 | + // remove once proven functional |
548 | + // the exception gives a very nice log error message from QmlEngine and does not |
549 | + // have any side effects |
550 | + if (mContexts[currentValue] !== undefined) { |
551 | + throw "updateContexts: added is broken"; |
552 | + } |
553 | + |
554 | + var ctx = connCtx.createObject(parent, |
555 | + { |
556 | + "contextPath": currentValue |
557 | + }); |
558 | + mContexts[currentValue] = ctx; |
559 | + |
560 | + if (isEmptyCustom("internet", ctx)) |
561 | + { |
562 | + ctx.name = mCustomContextNameInternet; |
563 | + // name updates async, so return here and |
564 | + // have the buildLists() called from Context::onNameChanged |
565 | + return; |
566 | + } else if (isEmptyCustom("mms", ctx)) |
567 | + { |
568 | + ctx.name = mCustomContextNameMms; |
569 | + ctx.accessPointName = pendingCustomMmsData["accessPointName"]; |
570 | + ctx.username = pendingCustomMmsData["username"]; |
571 | + ctx.password = pendingCustomMmsData["password"]; |
572 | + ctx.messageCenter = pendingCustomMmsData["messageCenter"]; |
573 | + ctx.messageProxy = pendingCustomMmsData["messageProxy"]; |
574 | + pendingCustomMmsData = ({}); |
575 | + // values update async, so return here and |
576 | + // have the buildLists() called from Context::onNameChanged |
577 | + return; |
578 | + } |
579 | + }); |
580 | + |
581 | + // just asserting to verify the logic |
582 | + // remove once proven functional |
583 | + // the exception gives a very nice log error message from QmlEngine and does not |
584 | + // have any side effects |
585 | + if (Object.keys(mContexts).length !== tmp.length) { |
586 | + throw "Object.keys(contexts).length !== tmp.length"; |
587 | + } |
588 | + tmp.forEach(function(currentValue, index, array) { |
589 | + if (mContexts[currentValue] === undefined) |
590 | + throw "contexts[currentValue] === undefined"; |
591 | + }); |
592 | + |
593 | + buildLists(); |
594 | + } |
595 | + |
596 | + // expects updateContexts() to have ran before executing. |
597 | + function checkAndCreateCustomContexts() |
598 | + { |
599 | + var customInternet = Object.keys(mContexts).filter(function (i) { |
600 | + var ctx = mContexts[i]; |
601 | + return ctx.name === mCustomContextNameInternet || |
602 | + isEmptyCustom("internet", ctx); |
603 | + }); |
604 | + var customMms = Object.keys(mContexts).filter(function (i) { |
605 | + var ctx = mContexts[i]; |
606 | + return ctx.name === mCustomContextNameMms || |
607 | + isEmptyCustom("mms", ctx); |
608 | + }); |
609 | + |
610 | + // make sure there is only one context per type |
611 | + if (customInternet.length > 1) { |
612 | + customInternet.forEach(function(currentValue, index, array) { |
613 | + if (index === 0) |
614 | + return; |
615 | + sim.connMan.removeContext(currentValue); |
616 | + }); |
617 | + } |
618 | + if (customMms.length > 1) { |
619 | + customMms.forEach(function(currentValue, index, array) { |
620 | + if (index === 0) |
621 | + return; |
622 | + sim.connMan.removeContext(currentValue); |
623 | + }); |
624 | + } |
625 | + |
626 | + if (customInternet.length === 0) { |
627 | + sim.connMan.addContext("internet"); |
628 | + } |
629 | + |
630 | + // @bug don't create the custom MMS context |
631 | + // LP(:#1362795) |
632 | + // if (customMms.length === 0) { |
633 | + // sim.connMan.addContext("mms"); |
634 | + // } |
635 | + |
636 | + buildLists(); |
637 | + } |
638 | + |
639 | + property var mInternetApns : []; |
640 | + property var mMmsApns : []; |
641 | + function buildLists() |
642 | + { |
643 | + d.__suppressActivation = true; |
644 | + |
645 | + var internet = []; |
646 | + var mms = []; |
647 | + |
648 | + internet = Object.keys(mContexts).filter(function(i) { |
649 | + var ctx = mContexts[i]; |
650 | + if (ctx.type === "internet") { |
651 | + if (ctx.name === mCustomContextNameInternet) { |
652 | + mCustomContextInternet = ctx |
653 | + // don't add yet |
654 | + return false; |
655 | + } |
656 | + return true; |
657 | + } |
658 | + return false; |
659 | + }); |
660 | + mms = Object.keys(mContexts).filter(function(i) { |
661 | + var ctx = mContexts[i]; |
662 | + if ( ctx.type === "mms") { |
663 | + if (ctx.name === mCustomContextNameMms) { |
664 | + mCustomContextMms = ctx; |
665 | + // don't add yet |
666 | + return false; |
667 | + } |
668 | + return true; |
669 | + } |
670 | + return false; |
671 | + }); |
672 | + |
673 | + // make sure customized are the last on the lists |
674 | + if (mCustomContextInternet !== undefined) |
675 | + internet = internet.concat([mCustomContextInternet.contextPath]) |
676 | + if (mCustomContextMms !== undefined) |
677 | + mms = mms.concat([mCustomContextMms.contextPath]) |
678 | + else { |
679 | + /// @bug LP(#1361864) |
680 | + // add anyway a "dummy" Custom so we can show at least the one provisioned |
681 | + // MMS context as long as the user does not hit "Custom" in the MMS list. |
682 | + mms = mms.concat(["dummycustom"]) |
683 | + } |
684 | + |
685 | + // add "Same APN as for Internet" to be the first on the MMS list |
686 | + mms = ["/same/as/internet"].concat(mms); |
687 | + |
688 | + mInternetApns = internet; |
689 | + mMmsApns = mms; |
690 | + |
691 | + d.__suppressActivation = false; |
692 | + } |
693 | + |
694 | + function openApnEditor(type) { |
695 | + var ctx; |
696 | + if (type === "internet") { |
697 | + ctx = mCustomContextInternet; |
698 | + } else if (type == "mms") { |
699 | + ctx = mCustomContextMms; |
700 | + } |
701 | + /// can't modify active context |
702 | + if (ctx !== undefined && ctx.active) |
703 | + ctx.active = false; |
704 | + |
705 | + pageStack.push(Qt.resolvedUrl("CustomApnEditor.qml"), |
706 | + { |
707 | + type: type, |
708 | + contexts: {"internet": mCustomContextInternet, |
709 | + "mms": mCustomContextMms}, |
710 | + activateCb: activateHelper |
711 | + }); |
712 | + } |
713 | + |
714 | + function activateHelper(type, contextPath, customMmsData) { |
715 | + if (type === "internet") { |
716 | + activator.activate(contextPath, sim.simMng.subscriberIdentity, sim.simMng.modemPath) |
717 | + } |
718 | + else if (type === "mms") { |
719 | + if (contextPath === undefined) { |
720 | + // LP(:#1362795) |
721 | + pendingCustomMmsData = customMmsData |
722 | + /// remove any provisioned ones.. |
723 | + var remove = [] |
724 | + Object.keys(mContexts).forEach(function(currentValue, index, array) { |
725 | + var ctx = mContexts[currentValue]; |
726 | + if (ctx.type === "mms") |
727 | + remove = remove.concat([ctx.contextPath]) |
728 | + }); |
729 | + remove.forEach(function(currentValue, index, array) { |
730 | + sim.connMan.removeContext(currentValue); |
731 | + }); |
732 | + sim.connMan.addContext("mms") |
733 | + } |
734 | + } else { |
735 | + // somebody is calling the function wrong |
736 | + // the exception gives a very nice log error message from QmlEngine and does not |
737 | + // have any side effects |
738 | + throw "activateHelper: bad data: type: " + type + ", contextPath: " + contextPath + ", customMmsData: " + customMmsData; |
739 | + } |
740 | + } |
741 | + } |
742 | + |
743 | + OfonoActivator { |
744 | + id:activator |
745 | + } |
746 | + |
747 | + Component { |
748 | + id: connCtx |
749 | + OfonoContextConnection { |
750 | + |
751 | + // add helper property to detect dual internet/MMS contexts |
752 | + property bool dual : false |
753 | + Component.onCompleted:{ |
754 | + if (type == "internet") |
755 | + if (messageCenter !== "") |
756 | + dual = true |
757 | + } |
758 | + |
759 | + onActiveChanged: if (type === "internet") internetApnSelector.updateSelectedIndex() |
760 | + onNameChanged: d.buildLists() |
761 | + onAccessPointNameChanged: d.buildLists() |
762 | + onReportError: console.error("Context error on " + contextPath + ": " + errorString) |
763 | + } |
764 | + } |
765 | + |
766 | + Connections { |
767 | + target: sim.connMan |
768 | + onContextsChanged: d.updateContexts() |
769 | + |
770 | + Component.onCompleted: { |
771 | + d.updateContexts(); |
772 | + |
773 | + |
774 | + /// @todo workaround the work around that the UI currently only supports max. 1 MMS context |
775 | + /// remove once nuntium stuff is implemented |
776 | + // remove all but one MMS context |
777 | + var mms = Object.keys(d.mContexts).filter(function(i) { |
778 | + var ctx = d.mContexts[i] |
779 | + if (ctx.type === "mms") |
780 | + return true; |
781 | + return false; |
782 | + }); |
783 | + mms = mms.slice(1); |
784 | + mms.forEach(function(currentValue, index, array) { |
785 | + sim.connMan.removeContext(currentValue); |
786 | + }); |
787 | + |
788 | + |
789 | + // do this once. |
790 | + d.checkAndCreateCustomContexts(); |
791 | + } |
792 | + } |
793 | + |
794 | + Flickable { |
795 | + id: scrollWidget |
796 | + anchors.fill: parent |
797 | + contentHeight: contentItem.childrenRect.height |
798 | + boundsBehavior: (contentHeight > root.height) ? Flickable.DragAndOvershootBounds : Flickable.StopAtBounds |
799 | + flickableDirection: Flickable.VerticalFlick |
800 | + |
801 | + Column { |
802 | + anchors { |
803 | + left: parent.left |
804 | + right: parent.right |
805 | + } |
806 | + |
807 | + ListItem.Standard { |
808 | + id: heading1 |
809 | + objectName: "internetapn" |
810 | + text: i18n.tr("Internet APN:") |
811 | + progression: false |
812 | + } |
813 | + ListItem.ThinDivider {} |
814 | + ListItem.SingleControl { |
815 | + control: ListItem.ItemSelector { |
816 | + id: internetApnSelector |
817 | + width: parent.width - units.gu(4) |
818 | + model: d.mInternetApns |
819 | + expanded: true |
820 | + selectedIndex: -1 |
821 | + onModelChanged: updateSelectedIndex() |
822 | + |
823 | + function updateSelectedIndex() |
824 | + { |
825 | + var tmp = d.__suppressActivation |
826 | + d.__suppressActivation = true; |
827 | + var idx = -1; |
828 | + if (model) { |
829 | + model.forEach(function(currentValue, index, array) { |
830 | + if (d.mContexts[currentValue].active) |
831 | + idx = index; |
832 | + }); |
833 | + } |
834 | + selectedIndex = idx; |
835 | + d.__suppressActivation = tmp; |
836 | + } |
837 | + |
838 | + delegate: OptionSelectorDelegate { |
839 | + showDivider: false |
840 | + text: { |
841 | + var ctx = d.mContexts[modelData]; |
842 | + if (ctx.name !== "") { |
843 | + if (ctx.name !== d.mCustomContextNameInternet) { |
844 | + return ctx.name |
845 | + } else { |
846 | + //: user visible name of the custom Internet APN |
847 | + return i18n.tr("Custom"); |
848 | + } |
849 | + } else { |
850 | + return ctx.accessPointName |
851 | + } |
852 | + } |
853 | + } |
854 | + onSelectedIndexChanged: { |
855 | + if (selectedIndex === -1) { |
856 | + if (mmsApnSelector && mmsApnSelector.model[mmsApnSelector.selectedIndex] === "/same/as/internet") |
857 | + mmsApnSelector.selectedIndex = -1; |
858 | + return; |
859 | + } |
860 | + |
861 | + var ctx = d.mContexts[model[selectedIndex]]; |
862 | + if(ctx.dual) { |
863 | + if (!d.mCustomContextMms) |
864 | + mmsApnSelector.selectedIndex = mmsApnSelector.model.indexOf("/same/as/internet"); |
865 | + } |
866 | + else if (mmsApnSelector.model[mmsApnSelector.selectedIndex] === "/same/as/internet") |
867 | + mmsApnSelector.selectedIndex = -1; |
868 | + |
869 | + if (d.__suppressActivation) |
870 | + return; |
871 | + |
872 | + if (d.mCustomContextInternet && model[selectedIndex] === d.mCustomContextInternet.contextPath) { |
873 | + if (d.mCustomContextInternet.accessPointName === "") { |
874 | + d.openApnEditor("internet"); |
875 | + updateSelectedIndex(); |
876 | + return; |
877 | + } |
878 | + } |
879 | + |
880 | + d.activateHelper("internet", ctx.contextPath); |
881 | + } |
882 | + } |
883 | + } |
884 | + ListItem.SingleControl { |
885 | + control: Button { |
886 | + objectName: "customApnEdit" |
887 | + text: i18n.tr("Custom Internet APN…") |
888 | + width: parent.width - units.gu(4) |
889 | + onClicked: d.openApnEditor("internet") |
890 | + } |
891 | + } |
892 | + |
893 | + ListItem.Divider {} |
894 | + |
895 | + ListItem.Standard { |
896 | + id: heading2 |
897 | + objectName: "mmsapn" |
898 | + text: i18n.tr("MMS APN:") |
899 | + progression: false |
900 | + } |
901 | + ListItem.ThinDivider {} |
902 | + ListItem.SingleControl { |
903 | + control: ListItem.ItemSelector { |
904 | + id: mmsApnSelector |
905 | + width: parent.width - units.gu(4) |
906 | + model: d.mMmsApns |
907 | + expanded: true |
908 | + selectedIndex: -1 |
909 | + delegate: OptionSelectorDelegate { |
910 | + showDivider: modelData === "/same/as/internet" |
911 | + enabled: { |
912 | + if (modelData !== "/same/as/internet") |
913 | + return true; |
914 | + else { |
915 | + var tmp = d.mContexts[internetApnSelector.model[internetApnSelector.selectedIndex]] |
916 | + return tmp === undefined ? false : tmp.dual |
917 | + } |
918 | + } |
919 | + // work around OptionSelectorDelegate not having a visual change depending on being disabled |
920 | + opacity: enabled ? 1.0 : 0.5 |
921 | + text: { |
922 | + if (modelData === "/same/as/internet") { |
923 | + return i18n.tr("Same APN as for Internet"); |
924 | + } |
925 | + if (modelData === "dummycustom") { |
926 | + return i18n.tr("Custom"); |
927 | + } |
928 | + var ctx = d.mContexts[modelData]; |
929 | + if (ctx.name !== "") { |
930 | + if (ctx.name !== d.mCustomContextNameMms) { |
931 | + return ctx.name |
932 | + } else { |
933 | + //: user visible name of the custom MMS APN |
934 | + return i18n.tr("Custom"); |
935 | + } |
936 | + } else { |
937 | + return ctx.accessPointName |
938 | + } |
939 | + } |
940 | + } |
941 | + onModelChanged: updateSelectedIndex(); |
942 | + function updateSelectedIndex() |
943 | + { |
944 | + // if we have custom MMS context, it must be active. |
945 | + // @bug LP(#1361864) |
946 | + var tmp = d.__suppressActivation; |
947 | + d.__suppressActivation = true; |
948 | + if (d.mCustomContextMms) { |
949 | + selectedIndex = model.indexOf(d.mCustomContextMms.contextPath); |
950 | + } else if (model.length === 3) { |
951 | + /* meaning we have: |
952 | + * 0 - /same/as/internet |
953 | + * 1 - some provisioned one |
954 | + * 2 - dummycustom |
955 | + */ |
956 | + selectedIndex = 1; |
957 | + } else if (internetApnSelector.model && internetApnSelector.selectedIndex !== -1) { |
958 | + if (d.mContexts[internetApnSelector.model[internetApnSelector.selectedIndex]].dual) { |
959 | + selectedIndex = model.indexOf("/same/as/internet"); |
960 | + } else |
961 | + selectedIndex = -1; |
962 | + } else { |
963 | + selectedIndex = -1; |
964 | + } |
965 | + d.__suppressActivation = tmp; |
966 | + } |
967 | + |
968 | + onSelectedIndexChanged: { |
969 | + if (selectedIndex === -1 || d.__suppressActivation) |
970 | + return; |
971 | + |
972 | + if (model[selectedIndex] === "/same/as/internet") { |
973 | + // @bug delete _any_ actual MMS context |
974 | + // LP:(#1362795) |
975 | + var remove = []; |
976 | + Object.keys(d.mContexts).forEach(function(currentValue, index, array) { |
977 | + var ctx = d.mContexts[currentValue]; |
978 | + if (ctx.type === "mms") |
979 | + remove = remove.concat([ctx.contextPath]); |
980 | + }); |
981 | + remove.forEach(function(currentValue, index, array) { |
982 | + sim.connMan.removeContext(currentValue); |
983 | + }); |
984 | + return; |
985 | + } |
986 | + |
987 | + if (model[selectedIndex] === "dummycustom") { |
988 | + d.openApnEditor("mms"); |
989 | + updateSelectedIndex() |
990 | + return; |
991 | + } |
992 | + |
993 | + // no need to "activate" anything. |
994 | + // just fall through return here. |
995 | + // once we actually are able to suppport multiple MMS contexts |
996 | + // on the system, add some code here to set one of them active |
997 | + } |
998 | + } |
999 | + } |
1000 | + ListItem.SingleControl { |
1001 | + control: Button { |
1002 | + objectName: "customApnEdit" |
1003 | + text: i18n.tr("Custom MMS APN…") |
1004 | + width: parent.width - units.gu(4) |
1005 | + onClicked: d.openApnEditor("mms") |
1006 | + } |
1007 | + } |
1008 | + |
1009 | + // @todo: no means of doing any meaningful reset right now. |
1010 | + // LP(#1338758) |
1011 | + // ListItem.ThinDivider {} |
1012 | + // ListItem.SingleControl { |
1013 | + // control: Button { |
1014 | + // objectName: "resetButton" |
1015 | + // text: i18n.tr("Reset APN Settings") |
1016 | + // width: parent.width - units.gu(4) |
1017 | + // onClicked: { |
1018 | + // PopupUtils.open(resetDialog) |
1019 | + // } |
1020 | + // } |
1021 | + // } |
1022 | + } |
1023 | + } |
1024 | + |
1025 | + Component { |
1026 | + id: resetDialog |
1027 | + Dialog { |
1028 | + id: dialogue |
1029 | + title: i18n.tr("Reset APN Settings") |
1030 | + text: i18n.tr("Are you sure that you want to Reset APN Settings?") |
1031 | + Button { |
1032 | + text: i18n.tr("Cancel") |
1033 | + onClicked: PopupUtils.close(dialogue) |
1034 | + } |
1035 | + Button { |
1036 | + text: i18n.tr("Reset") |
1037 | + color: UbuntuColors.orange |
1038 | + onClicked: { |
1039 | + // delete all APNs |
1040 | + // kick ofono per |
1041 | + // https://bugs.launchpad.net/ubuntu/+source/ofono/+bug/1338758 |
1042 | + |
1043 | + } |
1044 | + } |
1045 | + |
1046 | + } |
1047 | + } |
1048 | +} |
1049 | |
1050 | === modified file 'plugins/cellular/PageChooseCarrier.qml' |
1051 | --- plugins/cellular/PageChooseCarrier.qml 2014-07-24 19:00:45 +0000 |
1052 | +++ plugins/cellular/PageChooseCarrier.qml 2014-10-09 14:10:12 +0000 |
1053 | @@ -19,55 +19,103 @@ |
1054 | */ |
1055 | |
1056 | import QtQuick 2.0 |
1057 | +import QtQuick.Layouts 1.1 |
1058 | import SystemSettings 1.0 |
1059 | -import Ubuntu.Components 0.1 |
1060 | -import Ubuntu.Components.ListItems 0.1 as ListItem |
1061 | +import Ubuntu.Components 1.1 |
1062 | +import Ubuntu.Components.ListItems 1.0 as ListItem |
1063 | import MeeGo.QOfono 0.2 |
1064 | |
1065 | ItemPage { |
1066 | - title: title |
1067 | + id: root |
1068 | + title: i18n.tr("Carrier") |
1069 | + |
1070 | objectName: "chooseCarrierPage" |
1071 | |
1072 | - property var netReg |
1073 | - property var operators: [] |
1074 | - property bool scanning: false |
1075 | + property var sim |
1076 | + |
1077 | property variant operatorNames |
1078 | - property variant operatorStatus |
1079 | - property int curOp |
1080 | - Component.onCompleted: buildLists(); |
1081 | + property int mode |
1082 | + |
1083 | + QtObject { |
1084 | + id: d |
1085 | + property bool __suppressActivation : true; |
1086 | + } |
1087 | + |
1088 | + Component.onCompleted: { |
1089 | + updateNetworkOperators(); |
1090 | + } |
1091 | |
1092 | Connections { |
1093 | - target: netReg |
1094 | - onStatusChanged: { |
1095 | - if (netReg.status === "registered") |
1096 | - buildLists(); |
1097 | - } |
1098 | - onNetworkOperatorsChanged: buildLists(); |
1099 | - onScanFinished: scanning = false; |
1100 | - onScanError: { |
1101 | - scanning = false; |
1102 | - console.warn ("onScanError: " + message); |
1103 | - } |
1104 | + target: sim.netReg |
1105 | + onNetworkOperatorsChanged: updateNetworkOperators(); |
1106 | + onCurrentOperatorPathChanged: buildLists(); |
1107 | + } |
1108 | + |
1109 | + // map of operatorPath : netOp |
1110 | + property var operators: ({}) |
1111 | + function updateNetworkOperators() |
1112 | + { |
1113 | + var tmp = sim.netReg.networkOperators; |
1114 | + var added = tmp.filter(function(i) { |
1115 | + return operators[i] === undefined; |
1116 | + }); |
1117 | + var removed = Object.keys(operators).filter(function(i) { |
1118 | + return tmp.indexOf(i) === -1; |
1119 | + }) |
1120 | + |
1121 | + removed.forEach(function(currentValue, index, array) { |
1122 | + // just asserting to verify the logic |
1123 | + // remove once proven functional |
1124 | + if (operators[currentValue] === undefined) { |
1125 | + throw "updateNetworkOperators: removed is broken"; |
1126 | + } |
1127 | + |
1128 | + operators[currentValue].destroy(); |
1129 | + delete operators[currentValue]; |
1130 | + }); |
1131 | + |
1132 | + added.forEach(function(currentValue, index, array) { |
1133 | + // just asserting to verify the logic |
1134 | + // remove once proven functional |
1135 | + if (operators[currentValue] !== undefined) { |
1136 | + throw "updateNetworkOperators: added is broken"; |
1137 | + } |
1138 | + |
1139 | + operators[currentValue] = netOp.createObject(parent, |
1140 | + { |
1141 | + "operatorPath": currentValue |
1142 | + }); |
1143 | + }); |
1144 | + |
1145 | + // just asserting to verify the logic |
1146 | + // remove once proven functional |
1147 | + if (Object.keys(operators).length !== tmp.length) { |
1148 | + throw "Object.keys(operators).length !== tmp.length"; |
1149 | + } |
1150 | + tmp.forEach(function(currentValue, index, array) { |
1151 | + if (operators[currentValue] === undefined) |
1152 | + throw "operators[currentValue] === undefined"; |
1153 | + }); |
1154 | + |
1155 | + buildLists(); |
1156 | } |
1157 | |
1158 | function buildLists() |
1159 | { |
1160 | - var ops = []; |
1161 | + d.__suppressActivation = true; |
1162 | var oN = new Array(); |
1163 | - var oS = new Array(); |
1164 | - for (var i = 0; i < netReg.networkOperators.length; i++) { |
1165 | - var tempOp = netOp.createObject(parent, {"operatorPath": netReg.networkOperators[i]}); |
1166 | + |
1167 | + for (var i in operators) { |
1168 | + var tempOp = operators[i]; |
1169 | if (tempOp.status === "forbidden") |
1170 | continue |
1171 | oN.push(tempOp.name); |
1172 | - oS.push(tempOp.status); |
1173 | - ops.push(tempOp) |
1174 | } |
1175 | - curOp = oS.indexOf("current"); |
1176 | operatorNames = oN; |
1177 | - operatorStatus = oS; |
1178 | - operators = ops; |
1179 | - carrierSelector.selectedIndex = curOp; |
1180 | + |
1181 | + var cur = operators[sim.netReg.currentOperatorPath]; |
1182 | + carrierSelector.selectedIndex = cur === undefined ? -1 : operatorNames.indexOf(cur.name); |
1183 | + d.__suppressActivation = false; |
1184 | } |
1185 | |
1186 | Component { |
1187 | @@ -78,78 +126,113 @@ |
1188 | console.warn("registerComplete failed with error: " + errorString); |
1189 | } else if (error !== OfonoNetworkOperator.NoError) { |
1190 | console.warn("registerComplete failed with error: " + errorString + " Falling back to default"); |
1191 | - netReg.registration(); |
1192 | + sim.netReg.registration(); |
1193 | } |
1194 | } |
1195 | + onNameChanged: buildLists(); |
1196 | + onStatusChanged: buildLists(); |
1197 | } |
1198 | } |
1199 | |
1200 | Flickable { |
1201 | + id: scrollWidget |
1202 | anchors.fill: parent |
1203 | contentWidth: parent.width |
1204 | contentHeight: parent.height |
1205 | boundsBehavior: (contentHeight > parent.height) ? Flickable.DragAndOvershootBounds : Flickable.StopAtBounds |
1206 | |
1207 | - Column { |
1208 | - anchors.left: parent.left |
1209 | - anchors.right: parent.right |
1210 | + ColumnLayout { |
1211 | + anchors { |
1212 | + left: parent.left |
1213 | + right: parent.right |
1214 | + } |
1215 | |
1216 | ListItem.ItemSelector { |
1217 | id: chooseCarrier |
1218 | objectName: "autoChooseCarrierSelector" |
1219 | expanded: true |
1220 | - enabled: netReg.mode !== "auto-only" |
1221 | + enabled: sim.netReg.mode !== "auto-only" |
1222 | text: i18n.tr("Choose carrier:") |
1223 | model: [i18n.tr("Automatically"), i18n.tr("Manually")] |
1224 | - selectedIndex: netReg.mode === "manual" ? 1 : 0 |
1225 | + |
1226 | + delegate: OptionSelectorDelegate { showDivider: false } |
1227 | + selectedIndex: sim.netReg.mode === "manual" ? 1 : 0 |
1228 | + |
1229 | + // we only want to do this per user input |
1230 | onSelectedIndexChanged: { |
1231 | - if (selectedIndex === 0) |
1232 | - netReg.registration(); |
1233 | + if (selectedIndex === -1 || d.__suppressActivation) |
1234 | + return; |
1235 | + |
1236 | + if (selectedIndex === 0) { |
1237 | + sim.netReg.registration(); |
1238 | + } else if (selectedIndex === 1) { |
1239 | + if (sim.netReg.status !== "searching") |
1240 | + sim.netReg.scan(); |
1241 | + } |
1242 | } |
1243 | } |
1244 | - |
1245 | - ListItem.ItemSelector { |
1246 | - id: carrierSelector |
1247 | - objectName: "carrierSelector" |
1248 | - expanded: enabled |
1249 | + ListItem.SingleControl { |
1250 | enabled: chooseCarrier.selectedIndex === 1 |
1251 | - model: operatorNames |
1252 | - onSelectedIndexChanged: { |
1253 | - if ((selectedIndex !== curOp) && operators[selectedIndex]) { |
1254 | - operators[selectedIndex].registerOperator(); |
1255 | - } |
1256 | - } |
1257 | - } |
1258 | - } |
1259 | - |
1260 | - ListItem.SingleControl { |
1261 | - anchors.bottom: parent.bottom |
1262 | - control: Button { |
1263 | - objectName: "refreshButton" |
1264 | - width: parent.width - units.gu(4) |
1265 | - text: i18n.tr("Refresh") |
1266 | - enabled: (netReg.status !== "searching") && (netReg.status !== "denied") |
1267 | - onTriggered: { |
1268 | - scanning = true; |
1269 | - netReg.scan(); |
1270 | - } |
1271 | - } |
1272 | - } |
1273 | - |
1274 | - ActivityIndicator { |
1275 | - id: activityIndicator |
1276 | - anchors.centerIn: parent |
1277 | - running: scanning |
1278 | - } |
1279 | - |
1280 | - Label { |
1281 | - anchors { |
1282 | - top: activityIndicator.bottom |
1283 | - topMargin: units.gu(2) |
1284 | - horizontalCenter: activityIndicator.horizontalCenter |
1285 | - } |
1286 | - text: i18n.tr("Searching") |
1287 | - visible: activityIndicator.running |
1288 | + anchors { |
1289 | + left: parent.left |
1290 | + leftMargin: units.gu(0) |
1291 | + } |
1292 | + control: ColumnLayout { |
1293 | + id: child |
1294 | + width: parent.width - units.gu(4) |
1295 | + anchors.left: parent.left |
1296 | + RowLayout { |
1297 | + id: searchingRow |
1298 | + spacing: units.gu(1) |
1299 | + |
1300 | + visible: sim.netReg.status === "searching" |
1301 | + ActivityIndicator { |
1302 | + id: activityIndicator |
1303 | + anchors.verticalCenter: parent.verticalCenter |
1304 | + running: parent.visible |
1305 | + } |
1306 | + Label { |
1307 | + anchors.verticalCenter: parent.verticalCenter |
1308 | + text: i18n.tr("Searching for carriers…") |
1309 | + } |
1310 | + } |
1311 | + ListItem.ItemSelector { |
1312 | + id: carrierSelector |
1313 | + objectName: "carrierSelector" |
1314 | + expanded: true |
1315 | + enabled: sim.netReg.status !== "searching" && chooseCarrier.selectedIndex === 1 |
1316 | + // work around ItemSelector not having a visual change depending on being disabled |
1317 | + opacity: enabled ? 1.0 : 0.5 |
1318 | + width: parent.width |
1319 | + model: operatorNames |
1320 | + delegate: OptionSelectorDelegate { enabled: carrierSelector.enabled; showDivider: false } |
1321 | + onSelectedIndexChanged: { |
1322 | + if (selectedIndex === -1 || d.__suppressActivation) |
1323 | + return; |
1324 | + |
1325 | + // this assumes operator names are unique, |
1326 | + // revise if not so |
1327 | + for (var op in operators) { |
1328 | + if (operators[op].name === operatorNames[selectedIndex]) { |
1329 | + operators[op].registerOperator(); |
1330 | + return; |
1331 | + } |
1332 | + } |
1333 | + // just asserting to verify the logic |
1334 | + // remove once proven functional |
1335 | + throw "should not be reached."; |
1336 | + } |
1337 | + } |
1338 | + } |
1339 | + } |
1340 | + ListItem.Standard { |
1341 | + text: i18n.tr("APN") |
1342 | + progression: true |
1343 | + enabled: sim.connMan.powered |
1344 | + onClicked: { |
1345 | + pageStack.push(Qt.resolvedUrl("PageChooseApn.qml"), {sim: sim}) |
1346 | + } |
1347 | + } |
1348 | } |
1349 | } |
1350 | } |
1351 | |
1352 | === modified file 'plugins/cellular/PageChooseCarriers.qml' |
1353 | --- plugins/cellular/PageChooseCarriers.qml 2014-08-17 14:50:51 +0000 |
1354 | +++ plugins/cellular/PageChooseCarriers.qml 2014-10-09 14:10:12 +0000 |
1355 | @@ -21,7 +21,6 @@ |
1356 | import SystemSettings 1.0 |
1357 | import Ubuntu.Components 0.1 |
1358 | import Ubuntu.Components.ListItems 0.1 as ListItem |
1359 | -import MeeGo.QOfono 0.2 |
1360 | |
1361 | ItemPage { |
1362 | id: root |
1363 | @@ -47,10 +46,11 @@ |
1364 | ListItem.SingleValue { |
1365 | objectName: "chooseCarrierSim1" |
1366 | value: sims[0].netReg.name ? sims[0].netReg.name : i18n.tr("N/A") |
1367 | + enabled: sims[0].netReg.status !== "" |
1368 | progression: true |
1369 | onClicked: { |
1370 | pageStack.push(Qt.resolvedUrl("PageChooseCarrier.qml"), { |
1371 | - netReg: sims[0].netReg, |
1372 | + sim: sims[0], |
1373 | title: sims[0].title |
1374 | }) |
1375 | } |
1376 | @@ -63,10 +63,11 @@ |
1377 | ListItem.SingleValue { |
1378 | objectName: "chooseCarrierSim2" |
1379 | value: sims[1].netReg.name ? sims[1].netReg.name : i18n.tr("N/A") |
1380 | + enabled: sims[1].netReg.status !== "" |
1381 | progression: true |
1382 | onClicked: { |
1383 | pageStack.push(Qt.resolvedUrl("PageChooseCarrier.qml"), { |
1384 | - netReg: sims[1].netReg, |
1385 | + sim: sims[1], |
1386 | title: sims[1].title |
1387 | }) |
1388 | } |
1389 | |
1390 | === added file 'plugins/cellular/ofonoactivator.cpp' |
1391 | --- plugins/cellular/ofonoactivator.cpp 1970-01-01 00:00:00 +0000 |
1392 | +++ plugins/cellular/ofonoactivator.cpp 2014-10-09 14:10:12 +0000 |
1393 | @@ -0,0 +1,132 @@ |
1394 | +/* |
1395 | + * Copyright (C) 2014 Canonical, Ltd. |
1396 | + * |
1397 | + * Authors: |
1398 | + * Jussi Pakkanen <jussi.pakkanen@canonical.com> |
1399 | + * |
1400 | + * This program is free software: you can redistribute it and/or modify it |
1401 | + * under the terms of the GNU General Public License version 3, as published |
1402 | + * by the Free Software Foundation. |
1403 | + * |
1404 | + * This library is distributed in the hope that it will be useful, but WITHOUT |
1405 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
1406 | + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more |
1407 | + * details. |
1408 | + * |
1409 | + * You should have received a copy of the GNU General Public License |
1410 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1411 | + */ |
1412 | + |
1413 | +#include "ofonoactivator.h" |
1414 | + |
1415 | +#include"nm_manager_proxy.h" |
1416 | +#include"nm_settings_proxy.h" |
1417 | +#include"nm_settings_connection_proxy.h" |
1418 | +#include<QCoreApplication> |
1419 | + |
1420 | +typedef QMap<QString,QVariantMap> Vardict; |
1421 | +Q_DECLARE_METATYPE(Vardict) |
1422 | + |
1423 | +namespace { |
1424 | + |
1425 | +QString nmService("org.freedesktop.NetworkManager"); |
1426 | +QString nmSettingsPath("/org/freedesktop/NetworkManager/Settings"); |
1427 | +QString nmPath("/org/freedesktop/NetworkManager"); |
1428 | + |
1429 | +QDBusObjectPath detectConnection(const QString &ofonoContext, const QString imsi) { |
1430 | + auto ofonoContextBase = ofonoContext.split('/').back(); |
1431 | + auto target = "/" + imsi + "/" + ofonoContextBase; |
1432 | + |
1433 | + OrgFreedesktopNetworkManagerSettingsInterface settings(nmService, nmSettingsPath, |
1434 | + QDBusConnection::systemBus()); |
1435 | + auto reply = settings.ListConnections(); |
1436 | + reply.waitForFinished(); |
1437 | + if(!reply.isValid()) { |
1438 | + qWarning() << "Error getting connection list: " << reply.error().message() << "\n"; |
1439 | + } |
1440 | + auto connections = reply.value(); // Empty list if failed. |
1441 | + |
1442 | + for(const auto &c : connections) { |
1443 | + OrgFreedesktopNetworkManagerSettingsConnectionInterface connProxy(nmService, |
1444 | + c.path(), QDBusConnection::systemBus()); |
1445 | + auto reply2 = connProxy.GetSettings(); |
1446 | + reply2.waitForFinished(); |
1447 | + if(!reply2.isValid()) { |
1448 | + qWarning() << "Error getting property: " << reply2.error().message() << "\n"; |
1449 | + continue; |
1450 | + } |
1451 | + auto settings = reply2.value(); |
1452 | + auto id = settings["connection"]["id"].toString(); |
1453 | + if(id == target) { |
1454 | + return c; |
1455 | + } |
1456 | + } |
1457 | + return QDBusObjectPath(""); |
1458 | +} |
1459 | + |
1460 | +QDBusObjectPath detectDevice(const QString &modemPath) { |
1461 | + OrgFreedesktopNetworkManagerInterface nm(nmService, nmPath, QDBusConnection::systemBus()); |
1462 | + auto reply = nm.GetDevices(); |
1463 | + reply.waitForFinished(); |
1464 | + auto devices = reply.value(); |
1465 | + |
1466 | + for(const auto &device : devices) { |
1467 | + QDBusInterface iface(nmService, device.path(), "org.freedesktop.DBus.Properties", |
1468 | + QDBusConnection::systemBus()); |
1469 | + QDBusReply<QDBusVariant> ifaceReply = iface.call("Get", |
1470 | + "org.freedesktop.NetworkManager.Device", "Interface"); |
1471 | + if(!ifaceReply.isValid()) { |
1472 | + qWarning() << "Error getting property: " << ifaceReply.error().message() << "\n"; |
1473 | + continue; |
1474 | + } |
1475 | + auto devIface = ifaceReply.value().variant().toString(); |
1476 | + if(devIface == modemPath) { |
1477 | + return device; |
1478 | + } |
1479 | + } |
1480 | + return QDBusObjectPath(""); |
1481 | +} |
1482 | +} |
1483 | + |
1484 | +void activateOfono(QDBusObjectPath connection, QDBusObjectPath device) |
1485 | +{ |
1486 | + OrgFreedesktopNetworkManagerInterface nm(nmService, nmPath, QDBusConnection::systemBus()); |
1487 | + |
1488 | + |
1489 | + /// @bug https://bugs.launchpad.net/ubuntu/+source/network-manager/+bug/1378102 |
1490 | + /// This is a big and fat workaround for the above bug |
1491 | + // this is probably racy as well as we are not tracking the ActiveConnection to know |
1492 | + // when the Device has actually disconnected. |
1493 | + QDBusInterface dev_iface("org.freedesktop.NetworkManager", |
1494 | + device.path(), |
1495 | + "org.freedesktop.NetworkManager.Device", |
1496 | + nm.connection()); |
1497 | + dev_iface.call("Disconnect"); |
1498 | + |
1499 | + |
1500 | + nm.ActivateConnection(connection, device, QDBusObjectPath("/")); |
1501 | +} |
1502 | + |
1503 | +OfonoActivator::OfonoActivator(QObject *parent) : QObject(parent) { |
1504 | + static bool isRegistered = false; |
1505 | + if(!isRegistered) { |
1506 | + qDBusRegisterMetaType<Vardict>(); |
1507 | + isRegistered = true; |
1508 | + } |
1509 | +} |
1510 | + |
1511 | +Q_INVOKABLE bool OfonoActivator::activate(const QString ofonoContext, const QString imsi, const QString modemPath) |
1512 | +{ |
1513 | + auto dev = detectDevice(modemPath); |
1514 | + if(dev.path() == "") { |
1515 | + qWarning() << "Could not detect device object to use for Ofono activation.\n"; |
1516 | + return false; |
1517 | + } |
1518 | + auto conn = detectConnection(ofonoContext, imsi); |
1519 | + if(conn.path() == "") { |
1520 | + qWarning() << "Could not detect connection object to use for Ofono activation.\n"; |
1521 | + return false; |
1522 | + } |
1523 | + activateOfono(conn, dev); |
1524 | + return true; |
1525 | +} |
1526 | |
1527 | === added file 'plugins/cellular/ofonoactivator.h' |
1528 | --- plugins/cellular/ofonoactivator.h 1970-01-01 00:00:00 +0000 |
1529 | +++ plugins/cellular/ofonoactivator.h 2014-10-09 14:10:12 +0000 |
1530 | @@ -0,0 +1,42 @@ |
1531 | +/* |
1532 | + * Copyright (C) 2014 Canonical, Ltd. |
1533 | + * |
1534 | + * Authors: |
1535 | + * Jussi Pakkanen <jussi.pakkanen@canonical.com> |
1536 | + * |
1537 | + * This program is free software: you can redistribute it and/or modify it |
1538 | + * under the terms of the GNU General Public License version 3, as published |
1539 | + * by the Free Software Foundation. |
1540 | + * |
1541 | + * This library is distributed in the hope that it will be useful, but WITHOUT |
1542 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
1543 | + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more |
1544 | + * details. |
1545 | + * |
1546 | + * You should have received a copy of the GNU General Public License |
1547 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1548 | + */ |
1549 | + |
1550 | +#ifndef OFONO_ACTIVATOR |
1551 | +#define OFONO_ACTIVATOR |
1552 | + |
1553 | +#include <QObject> |
1554 | + |
1555 | +/** |
1556 | + * For exposing ofono controls to qml. |
1557 | + */ |
1558 | + |
1559 | +class OfonoActivator : public QObject { |
1560 | + Q_OBJECT |
1561 | + |
1562 | +public: |
1563 | + OfonoActivator(QObject *parent = nullptr); |
1564 | + ~OfonoActivator() {}; |
1565 | + |
1566 | + Q_INVOKABLE bool activate(const QString ofonoContext, const QString imsi, const QString modemPath); |
1567 | + |
1568 | +private: |
1569 | +}; |
1570 | + |
1571 | + |
1572 | +#endif |
1573 | |
1574 | === modified file 'plugins/cellular/plugin.cpp' |
1575 | --- plugins/cellular/plugin.cpp 2014-07-23 13:44:31 +0000 |
1576 | +++ plugins/cellular/plugin.cpp 2014-10-09 14:10:12 +0000 |
1577 | @@ -20,11 +20,13 @@ |
1578 | #include <QtQml> |
1579 | #include <QtQml/QQmlContext> |
1580 | #include "hotspotmanager.h" |
1581 | +#include "ofonoactivator.h" |
1582 | |
1583 | void BackendPlugin::registerTypes(const char *uri) |
1584 | { |
1585 | Q_ASSERT(uri == QLatin1String("Ubuntu.SystemSettings.Cellular")); |
1586 | qmlRegisterType<HotspotManager>(uri, 1, 0, "HotspotManager"); |
1587 | + qmlRegisterType<OfonoActivator>(uri, 1, 0, "OfonoActivator"); |
1588 | } |
1589 | |
1590 | void BackendPlugin::initializeEngine(QQmlEngine *engine, const char *uri) |
FAILED: Continuous integration, rev:798 jenkins. qa.ubuntu. com/job/ ubuntu- system- settings- ci/1028/ jenkins. qa.ubuntu. com/job/ generic- deb-autopilot- utopic- touch/2226 jenkins. qa.ubuntu. com/job/ generic- mediumtests- utopic/ 1853 jenkins. qa.ubuntu. com/job/ ubuntu- system- settings- utopic- amd64-ci/ 220 jenkins. qa.ubuntu. com/job/ ubuntu- system- settings- utopic- armhf-ci/ 220 jenkins. qa.ubuntu. com/job/ ubuntu- system- settings- utopic- armhf-ci/ 220/artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ ubuntu- system- settings- utopic- i386-ci/ 220 jenkins. qa.ubuntu. com/job/ generic- deb-autopilot- runner- mako/2437 jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- utopic- armhf/3408 jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- utopic- armhf/3408/ artifact/ work/output/ *zip*/output. zip s-jenkins. ubuntu- ci:8080/ job/touch- flash-device/ 10130 jenkins. qa.ubuntu. com/job/ autopilot- testrunner- otto-utopic/ 1557 jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- utopic- amd64/2072 jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- utopic- amd64/2072/ artifact/ work/output/ *zip*/output. zip
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/ubuntu- system- settings- ci/1028/ rebuild
http://