Initial Import
authorPrajwal Mohan <prajwal.karur.mohan@intel.com>
Fri, 27 Apr 2012 22:50:12 +0000 (15:50 -0700)
committerPrajwal Mohan <prajwal.karur.mohan@intel.com>
Fri, 27 Apr 2012 22:50:12 +0000 (15:50 -0700)
93 files changed:
LICENSE [new file with mode: 0644]
README [new file with mode: 0644]
dialer.desktop [new file with mode: 0644]
dialer.service [new file with mode: 0644]
dialerassets/bluetooth-smartphone.png [new file with mode: 0644]
dialerassets/computer.png [new file with mode: 0644]
dialerassets/dialerassets.pro [new file with mode: 0644]
dialerassets/ivi-v1_ivi-Dialer-incall.jpg [new file with mode: 0644]
dialerassets/ivi-v1_ivi-background.jpg [new file with mode: 0644]
dialerassets/ivi_btn-call-active.png [new file with mode: 0644]
dialerassets/ivi_btn-call.png [new file with mode: 0644]
dialerassets/ivi_btn-close.png [new file with mode: 0644]
dialerassets/ivi_btn-delete-active.png [new file with mode: 0644]
dialerassets/ivi_btn-delete.png [new file with mode: 0644]
dialerassets/ivi_btn-endcall-active.png [new file with mode: 0644]
dialerassets/ivi_btn-endcall.png [new file with mode: 0644]
dialerassets/ivi_btn-incomingcall-accept-active.png [new file with mode: 0644]
dialerassets/ivi_btn-incomingcall-accept.png [new file with mode: 0644]
dialerassets/ivi_btn-incomingcall-decline-active.png [new file with mode: 0644]
dialerassets/ivi_btn-incomingcall-decline.png [new file with mode: 0644]
dialerassets/ivi_btn-list-active.png [new file with mode: 0644]
dialerassets/ivi_btn-list-inactive.png [new file with mode: 0644]
dialerassets/ivi_btn-list.png [new file with mode: 0644]
dialerassets/ivi_btn-numbers-active.png [new file with mode: 0644]
dialerassets/ivi_btn-numbers.png [new file with mode: 0644]
dialerassets/ivi_buttonarea.png [new file with mode: 0644]
dialerassets/ivi_icon-call.png [new file with mode: 0644]
dialerassets/ivi_icon-delete.png [new file with mode: 0644]
dialerassets/ivi_icon-endcall.png [new file with mode: 0644]
dialerassets/ivi_icon-list-delete-active.png [new file with mode: 0644]
dialerassets/ivi_icon-list-delete.png [new file with mode: 0644]
dialerassets/ivi_icon-list-inactive-delete-active.png [new file with mode: 0644]
dialerassets/ivi_icon-list-inactive-delete.png [new file with mode: 0644]
dialerassets/ivi_icon-time.png [new file with mode: 0644]
dialerassets/ivi_textarea.png [new file with mode: 0644]
hfdialer.conf [new file with mode: 0644]
packaging/hfdialer.spec [new file with mode: 0644]
projects.pro [new file with mode: 0644]
qml/AbstractDialog.qml [new file with mode: 0644]
qml/CallItemView.qml [new file with mode: 0644]
qml/CallItemViewLarge.qml [new file with mode: 0644]
qml/DeviceDelegate.qml [new file with mode: 0644]
qml/DeviceDelegateActive.qml [new file with mode: 0644]
qml/DialNumPad.qml [new file with mode: 0644]
qml/DialNumPadButton.qml [new file with mode: 0644]
qml/DialNumberEntry.qml [new file with mode: 0644]
qml/DialPage.qml [new file with mode: 0644]
qml/MessageDialog.qml [new file with mode: 0644]
qml/RequestConfirmDialog.qml [new file with mode: 0644]
qml/RequestPidCodeDialog.qml [new file with mode: 0644]
qml/RequestpasskeyDialog.qml [new file with mode: 0644]
qml/javascripts/framework.js [new file with mode: 0644]
qml/main.qml [new file with mode: 0644]
qml/qml.pro [new file with mode: 0644]
sounds/ring-1.wav [new file with mode: 0644]
sounds/sounds.pro [new file with mode: 0644]
src/callitem.cpp [new file with mode: 0644]
src/callitem.h [new file with mode: 0644]
src/callmanager.cpp [new file with mode: 0644]
src/callmanager.h [new file with mode: 0644]
src/callproxy.cpp [new file with mode: 0644]
src/callproxy.h [new file with mode: 0644]
src/common.h [new file with mode: 0644]
src/dbus/com.hfdialer.xml [new file with mode: 0644]
src/dbus/org.ofono.history.xml [new file with mode: 0644]
src/dbus/org.ofono.manager.xml [new file with mode: 0644]
src/dbus/org.ofono.modem.xml [new file with mode: 0644]
src/dbus/org.ofono.operator.xml [new file with mode: 0644]
src/dbus/org.ofono.voicecall.xml [new file with mode: 0644]
src/dbusdialeradapter.cpp [new file with mode: 0644]
src/dbusdialeradapter.h [new file with mode: 0644]
src/dbustypes.cpp [new file with mode: 0644]
src/dbustypes.h [new file with mode: 0644]
src/dialerapplication.cpp [new file with mode: 0644]
src/dialerapplication.h [new file with mode: 0644]
src/dialercontext.cpp [new file with mode: 0644]
src/dialercontext.h [new file with mode: 0644]
src/main.cpp [new file with mode: 0644]
src/managerproxy.cpp [new file with mode: 0644]
src/managerproxy.h [new file with mode: 0644]
src/modemproxy.cpp [new file with mode: 0644]
src/modemproxy.h [new file with mode: 0644]
src/networkproxy.cpp [new file with mode: 0644]
src/networkproxy.h [new file with mode: 0644]
src/pacontrol.cpp [new file with mode: 0644]
src/pacontrol.h [new file with mode: 0644]
src/qmlcallitem.cpp [new file with mode: 0644]
src/qmlcallitem.h [new file with mode: 0644]
src/qmldialer.cpp [new file with mode: 0644]
src/qmldialer.h [new file with mode: 0644]
src/qmlmainwindow.cpp [new file with mode: 0644]
src/qmlmainwindow.h [new file with mode: 0644]
src/src.pro [new file with mode: 0644]

diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..d645695
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/dialer.desktop b/dialer.desktop
new file mode 100644 (file)
index 0000000..18e5bf8
--- /dev/null
@@ -0,0 +1,7 @@
+[Desktop Entry]
+Type=Application
+Name=Handsfree Dialer
+Icon=hfdialer
+Exec=dialer
+Comment=Handsfree Dialer Application
+X-Desktop-File-Install-Version=0.16
diff --git a/dialer.service b/dialer.service
new file mode 100644 (file)
index 0000000..b9ea896
--- /dev/null
@@ -0,0 +1,3 @@
+[D-BUS Service]
+Name=com.hfdialer
+Exec=/usr/bin/dialer -prestart
diff --git a/dialerassets/bluetooth-smartphone.png b/dialerassets/bluetooth-smartphone.png
new file mode 100644 (file)
index 0000000..f54ae68
Binary files /dev/null and b/dialerassets/bluetooth-smartphone.png differ
diff --git a/dialerassets/computer.png b/dialerassets/computer.png
new file mode 100644 (file)
index 0000000..83498ea
Binary files /dev/null and b/dialerassets/computer.png differ
diff --git a/dialerassets/dialerassets.pro b/dialerassets/dialerassets.pro
new file mode 100644 (file)
index 0000000..382a2a5
--- /dev/null
@@ -0,0 +1,7 @@
+TEMPLATE = subdirs
+CONFIG += ordered
+
+assets.files += *.png *.jpg
+assets.path  += $${installPrefix}/usr/share/hfdialer/images
+
+INSTALLS += assets
diff --git a/dialerassets/ivi-v1_ivi-Dialer-incall.jpg b/dialerassets/ivi-v1_ivi-Dialer-incall.jpg
new file mode 100644 (file)
index 0000000..9350e59
Binary files /dev/null and b/dialerassets/ivi-v1_ivi-Dialer-incall.jpg differ
diff --git a/dialerassets/ivi-v1_ivi-background.jpg b/dialerassets/ivi-v1_ivi-background.jpg
new file mode 100644 (file)
index 0000000..6f1d57d
Binary files /dev/null and b/dialerassets/ivi-v1_ivi-background.jpg differ
diff --git a/dialerassets/ivi_btn-call-active.png b/dialerassets/ivi_btn-call-active.png
new file mode 100644 (file)
index 0000000..3d0a058
Binary files /dev/null and b/dialerassets/ivi_btn-call-active.png differ
diff --git a/dialerassets/ivi_btn-call.png b/dialerassets/ivi_btn-call.png
new file mode 100644 (file)
index 0000000..2fd535c
Binary files /dev/null and b/dialerassets/ivi_btn-call.png differ
diff --git a/dialerassets/ivi_btn-close.png b/dialerassets/ivi_btn-close.png
new file mode 100644 (file)
index 0000000..94d623d
Binary files /dev/null and b/dialerassets/ivi_btn-close.png differ
diff --git a/dialerassets/ivi_btn-delete-active.png b/dialerassets/ivi_btn-delete-active.png
new file mode 100644 (file)
index 0000000..282618a
Binary files /dev/null and b/dialerassets/ivi_btn-delete-active.png differ
diff --git a/dialerassets/ivi_btn-delete.png b/dialerassets/ivi_btn-delete.png
new file mode 100644 (file)
index 0000000..97a00da
Binary files /dev/null and b/dialerassets/ivi_btn-delete.png differ
diff --git a/dialerassets/ivi_btn-endcall-active.png b/dialerassets/ivi_btn-endcall-active.png
new file mode 100644 (file)
index 0000000..d7bf6e7
Binary files /dev/null and b/dialerassets/ivi_btn-endcall-active.png differ
diff --git a/dialerassets/ivi_btn-endcall.png b/dialerassets/ivi_btn-endcall.png
new file mode 100644 (file)
index 0000000..658774a
Binary files /dev/null and b/dialerassets/ivi_btn-endcall.png differ
diff --git a/dialerassets/ivi_btn-incomingcall-accept-active.png b/dialerassets/ivi_btn-incomingcall-accept-active.png
new file mode 100644 (file)
index 0000000..94c451a
Binary files /dev/null and b/dialerassets/ivi_btn-incomingcall-accept-active.png differ
diff --git a/dialerassets/ivi_btn-incomingcall-accept.png b/dialerassets/ivi_btn-incomingcall-accept.png
new file mode 100644 (file)
index 0000000..4e69ced
Binary files /dev/null and b/dialerassets/ivi_btn-incomingcall-accept.png differ
diff --git a/dialerassets/ivi_btn-incomingcall-decline-active.png b/dialerassets/ivi_btn-incomingcall-decline-active.png
new file mode 100644 (file)
index 0000000..f733398
Binary files /dev/null and b/dialerassets/ivi_btn-incomingcall-decline-active.png differ
diff --git a/dialerassets/ivi_btn-incomingcall-decline.png b/dialerassets/ivi_btn-incomingcall-decline.png
new file mode 100644 (file)
index 0000000..8c683f5
Binary files /dev/null and b/dialerassets/ivi_btn-incomingcall-decline.png differ
diff --git a/dialerassets/ivi_btn-list-active.png b/dialerassets/ivi_btn-list-active.png
new file mode 100644 (file)
index 0000000..65597d1
Binary files /dev/null and b/dialerassets/ivi_btn-list-active.png differ
diff --git a/dialerassets/ivi_btn-list-inactive.png b/dialerassets/ivi_btn-list-inactive.png
new file mode 100644 (file)
index 0000000..ac8f33f
Binary files /dev/null and b/dialerassets/ivi_btn-list-inactive.png differ
diff --git a/dialerassets/ivi_btn-list.png b/dialerassets/ivi_btn-list.png
new file mode 100644 (file)
index 0000000..1675dda
Binary files /dev/null and b/dialerassets/ivi_btn-list.png differ
diff --git a/dialerassets/ivi_btn-numbers-active.png b/dialerassets/ivi_btn-numbers-active.png
new file mode 100644 (file)
index 0000000..d36f01f
Binary files /dev/null and b/dialerassets/ivi_btn-numbers-active.png differ
diff --git a/dialerassets/ivi_btn-numbers.png b/dialerassets/ivi_btn-numbers.png
new file mode 100644 (file)
index 0000000..edc2205
Binary files /dev/null and b/dialerassets/ivi_btn-numbers.png differ
diff --git a/dialerassets/ivi_buttonarea.png b/dialerassets/ivi_buttonarea.png
new file mode 100644 (file)
index 0000000..6761817
Binary files /dev/null and b/dialerassets/ivi_buttonarea.png differ
diff --git a/dialerassets/ivi_icon-call.png b/dialerassets/ivi_icon-call.png
new file mode 100644 (file)
index 0000000..4579c3f
Binary files /dev/null and b/dialerassets/ivi_icon-call.png differ
diff --git a/dialerassets/ivi_icon-delete.png b/dialerassets/ivi_icon-delete.png
new file mode 100644 (file)
index 0000000..7844410
Binary files /dev/null and b/dialerassets/ivi_icon-delete.png differ
diff --git a/dialerassets/ivi_icon-endcall.png b/dialerassets/ivi_icon-endcall.png
new file mode 100644 (file)
index 0000000..bb15214
Binary files /dev/null and b/dialerassets/ivi_icon-endcall.png differ
diff --git a/dialerassets/ivi_icon-list-delete-active.png b/dialerassets/ivi_icon-list-delete-active.png
new file mode 100644 (file)
index 0000000..7003a32
Binary files /dev/null and b/dialerassets/ivi_icon-list-delete-active.png differ
diff --git a/dialerassets/ivi_icon-list-delete.png b/dialerassets/ivi_icon-list-delete.png
new file mode 100644 (file)
index 0000000..1f5523a
Binary files /dev/null and b/dialerassets/ivi_icon-list-delete.png differ
diff --git a/dialerassets/ivi_icon-list-inactive-delete-active.png b/dialerassets/ivi_icon-list-inactive-delete-active.png
new file mode 100644 (file)
index 0000000..05c443f
Binary files /dev/null and b/dialerassets/ivi_icon-list-inactive-delete-active.png differ
diff --git a/dialerassets/ivi_icon-list-inactive-delete.png b/dialerassets/ivi_icon-list-inactive-delete.png
new file mode 100644 (file)
index 0000000..5421d7e
Binary files /dev/null and b/dialerassets/ivi_icon-list-inactive-delete.png differ
diff --git a/dialerassets/ivi_icon-time.png b/dialerassets/ivi_icon-time.png
new file mode 100644 (file)
index 0000000..6d205bb
Binary files /dev/null and b/dialerassets/ivi_icon-time.png differ
diff --git a/dialerassets/ivi_textarea.png b/dialerassets/ivi_textarea.png
new file mode 100644 (file)
index 0000000..63f4e5f
Binary files /dev/null and b/dialerassets/ivi_textarea.png differ
diff --git a/hfdialer.conf b/hfdialer.conf
new file mode 100644 (file)
index 0000000..9be7fa2
--- /dev/null
@@ -0,0 +1,10 @@
+<!DOCTYPE busconfig PUBLIC
+ "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+               <policy context="default">
+                       <allow own="com.hfdialer" />
+                       <allow send_destination="com.hfdialer" />
+                       <allow send_interface="com.hfdialer" />
+               </policy>
+</busconfig>
diff --git a/packaging/hfdialer.spec b/packaging/hfdialer.spec
new file mode 100644 (file)
index 0000000..b7fa64f
--- /dev/null
@@ -0,0 +1,61 @@
+%define buildwayland 1 
+%if %{buildwayland}
+%define backend wayland
+%else
+%define backend xlib
+%endif
+
+Name:       hfdialer-%{backend}
+Summary:    QML based Voice Call Application
+Version:    0.3.2
+Release:    11.1
+Group:      System/GUI/Other
+License:    Apache License, Version 2.0
+URL:        http://www.tizen.org
+Source0:    hfdialer-%{version}.tar.bz2
+Requires:   ofono
+Requires:   pulseaudio
+Requires:   bluetooth-qt-%{backend}
+BuildRequires:  pkgconfig(QtCore-%{backend})
+BuildRequires:  pkgconfig(QtOpenGL-%{backend})
+BuildRequires:  pkgconfig(QtDeclarative-%{backend})
+BuildRequires:  pkgconfig(libpulse)
+BuildRequires:  pkgconfig(libpulse-mainloop-glib)
+BuildRequires:  pkgconfig(ofono-qt-%{backend})
+BuildRequires:  pkgconfig(mlite-%{backend})
+BuildRequires:  desktop-file-utils
+
+%description
+QML based Dialer Application
+
+
+%prep
+%setup -q -n hfdialer-%{version}
+
+%build
+unset LD_AS_NEEDED
+
+%qmake CONFIG+=%{backend} 
+
+make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+
+%qmake_install
+
+desktop-file-install --delete-original       \
+  --dir %{buildroot}%{_datadir}/applications             \
+   %{buildroot}%{_datadir}/applications/*.desktop
+
+
+%files
+%defattr(-,root,root,-)
+/etc/dbus-1/system.d/hfdialer.conf
+%{_bindir}/dialer
+%{_datadir}/dbus-1/services/dialer.service
+%{_datadir}/applications/dialer.desktop
+%{_datadir}/hfdialer
+%{_datadir}/hfdialer/qml
+%{_datadir}/hfdialer/LICENSE
+
diff --git a/projects.pro b/projects.pro
new file mode 100644 (file)
index 0000000..c1a35c8
--- /dev/null
@@ -0,0 +1,38 @@
+VERSION = 0.3.2
+CONFIG += link_pkgconfig network opengl
+
+TEMPLATE = subdirs
+CONFIG += ordered 
+SUBDIRS = src qml dialerassets sounds
+
+OTHER_FILES += *.service *.desktop *.sh
+
+# Desktop
+desktop_entry.files = dialer.desktop
+desktop_entry.path += $$INSTALL_ROOT/usr/share/applications
+desktop_entry.CONFIG += no_check_exist
+
+# DBus service
+dbus_service.files = dialer.service
+dbus_service.path += $$INSTALL_ROOT/usr/share/dbus-1/services
+
+dbus_conf.files = hfdialer.conf
+dbus_conf.path += $$INSTALL_ROOT/etc/dbus-1/system.d
+
+# Documentation
+documentation.files = AUTHORS ChangeLog LICENSE README TODO
+documentation.path  = $$INSTALL_ROOT/usr/share/hfdialer/
+
+INSTALLS += \
+    desktop_entry \
+    dbus_service \
+    dbus_conf \
+    documentation \
+
+PROJECT_NAME = hfdialer
+
+dist.commands += rm -fR $${PROJECT_NAME}-$${VERSION} &&
+dist.commands += git clone . $${PROJECT_NAME}-$${VERSION} &&
+dist.commands += rm -fR $${PROJECT_NAME}-$${VERSION}/.git &&
+dist.commands += tar jcpvf $${PROJECT_NAME}-$${VERSION}.tar.bz2 $${PROJECT_NAME}-$${VERSION}
+QMAKE_EXTRA_TARGETS += dist
diff --git a/qml/AbstractDialog.qml b/qml/AbstractDialog.qml
new file mode 100644 (file)
index 0000000..55937a3
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * dialer - QML User Interface Component
+ *
+ * Copyright (c) 2011, Tom Swindell.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0.  The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ */
+
+import Qt 4.7
+
+Item {
+    id: root
+
+    anchors.fill: parent
+
+    states: [
+        State {
+            name: 'shown'
+            PropertyChanges {target: root; opacity: 1.0}
+        },
+        State {
+            name: 'hidden'
+            PropertyChanges {target: root; opacity: 0.0}
+        }
+    ]
+
+    Behavior on opacity {PropertyAnimation {duration: 250}}
+
+    Rectangle {
+        id: blind
+        anchors.fill: parent
+        color: 'black'
+        opacity: 0.7
+    }
+
+    MouseArea {
+        anchors.fill: parent
+        onPressed: {
+            root.state = 'hidden'
+        }
+    }
+}
diff --git a/qml/CallItemView.qml b/qml/CallItemView.qml
new file mode 100644 (file)
index 0000000..3117016
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2012 Intel Corporation.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0.  The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+import Qt 4.7
+
+Item
+{
+    id: root
+    anchors.fill: parent
+    property variant call: null
+
+    state: 'disconnected'
+    onStateChanged: {
+        console.log("*** STATE IS now >> " + root.state);
+    }
+    Connections {
+        target: adapter
+        onCallCountChanged: {
+            if (callCount <= 0)
+                root.state = 'disconnected'
+        }
+    }
+    onCallChanged: {
+        if(call) {
+            largeView.call = call;
+            console.log("*** QML *** :: CALL ITEM CHANGED, STATE: " + call.state);
+            root.state = call.state;
+
+            if (call.stateChanged)
+            {
+                call.stateChanged.connect(function(state) {
+                    console.log("*** QML *** :: CALL ITEM STATE CHANGED: " + state);
+                    console.log("");
+
+                    root.state = state;
+                    });
+            }
+        }
+    }
+
+    states {
+        State {
+            name: 'active'
+            PropertyChanges {target: root; visible: true}
+        }
+
+        State {
+            name: 'held'
+            PropertyChanges {target: root; visible: true}
+        }
+
+        State {
+            name: 'dialing'
+            PropertyChanges {target: root; visible: true}
+        }
+
+        State {
+            name: 'alerting'
+            PropertyChanges {target: root; visible: true}
+        }
+
+        State {
+            name: 'incoming'
+            PropertyChanges {target: root; visible: true}
+        }
+
+        State {
+            name: 'waiting'
+            PropertyChanges {target: root; visible: true}
+        }
+
+        State {
+            name: 'disconnected'
+            PropertyChanges {target: root; visible: false}
+        }
+    }
+
+    Rectangle
+    {
+        id: background
+        anchors {top: parent.top; left: parent.left; right: parent.right; bottom: parent.bottom; topMargin: parent.height / 4; bottomMargin: parent.height / 5}
+
+        gradient: Gradient {
+            GradientStop {position: 0.0; color: '#4f4f4f'}
+            GradientStop {position: 1.0; color: '#000000'}
+        }
+
+        CallItemViewLarge
+        {
+            id: largeView
+            call: root.call //parent.call
+            state: root.state //parent.state
+        }
+    }
+}
+
diff --git a/qml/CallItemViewLarge.qml b/qml/CallItemViewLarge.qml
new file mode 100644 (file)
index 0000000..1ea7dd6
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * Copyright 2012 Intel Corporation.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0.  The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+import Qt 4.7
+
+import 'javascripts/framework.js' as Support
+
+Item
+{
+    id: root
+
+    anchors.fill: parent
+
+    property variant call  
+    property string  callDuration: "00:00:00"
+    property string  callerLabelText: "Unknown Caller"
+    state : 'disconnected'
+
+    onCallChanged: {
+     console.log("*** call changed in large, before if")   
+     if(call && call.msisdn) {
+            console.log("*** in calllarge if >> " + call.state );
+           
+           root.state = call.state
+
+            if (call.name) {
+                root.callerLabelText = call.name;
+
+            } else {
+
+               if (call.numberLen <= 10)
+               {
+                  root.callerLabelText = call.msisdn[0] + call.msisdn[1] + call.msisdn[2] + '-' +
+                                        call.msisdn[3] + call.msisdn[4] + call.msisdn[5] + '-' +
+                                        call.msisdn[6] + call.msisdn[7] + call.msisdn[8] + call.msisdn[9];
+               }
+               else
+                 root.callerLabelText = call.msisdn;
+            }
+        }
+    }
+
+    Timer {
+        interval: 1000; repeat: true; running: true;
+
+        onTriggered: {
+            if(call) {
+                if(call.duration && call.duration > 0)
+                {
+                    callDuration = Support.friendlyInterval(call.duration);
+                }
+            }
+        }
+    }
+
+    states {
+        State {
+            name: 'active'           
+           PropertyChanges {target: root; callDuration: "00:00:00"}
+            PropertyChanges {target: answerButton; visible: false}
+            PropertyChanges {target: hangupButton; visible: true; width: parent.width}
+            PropertyChanges {target: stateInd; text: qsTr("Active")}
+        }
+
+        State {
+            name: 'held'          
+            PropertyChanges {target: answerButton; visible: false}
+            PropertyChanges {target: hangupButton; visible: true; width: parent.width}
+            PropertyChanges {target: stateInd; text: qsTr("Held")}
+        }
+
+        State {
+            name: 'dialing'           
+           PropertyChanges {target: root; callDuration: "00:00:00"}
+            PropertyChanges {target: answerButton; visible: false}
+            PropertyChanges {target: hangupButton; visible: true; width: parent.width}
+            PropertyChanges {target: stateInd; text: qsTr("Dialing...")}
+        }
+
+        State {
+            name: 'alerting'           
+            PropertyChanges {target: answerButton; visible: false}
+            PropertyChanges {target: hangupButton; visible: true; width: parent.width}
+            PropertyChanges {target: stateInd; text: qsTr("Alerting...")}
+        }
+
+        State {
+            name: 'incoming'            
+           PropertyChanges {target: root; callDuration: "00:00:00"}
+            PropertyChanges {target: answerButton; visible: true}
+            PropertyChanges {target: hangupButton; visible: true; width: parent.width * 0.45}
+            PropertyChanges {target: stateInd; text: qsTr("Incoming...")}
+        }
+
+        State {
+            name: 'waiting'            
+            PropertyChanges {target: answerButton; visible: false}
+            PropertyChanges {target: hangupButton; visible: true; width: parent.width}
+            PropertyChanges {target: stateInd; text: qsTr("Waiting...")}
+        }
+
+        State {
+            name: 'disconnected'    
+           PropertyChanges {target: callDurationInd; text: "00:00:00"}        
+            PropertyChanges {target: answerButton; visible: false}
+            PropertyChanges {target: hangupButton; visible: false}
+            PropertyChanges {target: stateInd; text: qsTr("Disconnected")}
+        }
+    }
+
+    Text
+    {
+        id: stateInd
+        anchors {top: parent.top; topMargin: 20; horizontalCenter: parent.horizontalCenter}
+        color: '#ffffff'
+        font {pixelSize: 38}
+       text: qsTr("Disconnected")
+    }
+
+    Text
+    {
+        id: callerInd
+        anchors {top: stateInd.bottom; topMargin: 20; horizontalCenter: parent.horizontalCenter}
+        color: '#ffffff'
+        font {pixelSize: 75}
+        text: callerLabelText
+    }
+    
+    Image
+    {
+        id: clock
+       source: "/usr/share/hfdialer/images/ivi_icon-time.png"
+       anchors { right: callDurationInd.left; rightMargin: 2; bottom: callerInd.top}
+       width: 25
+       height: 25
+       smooth: true
+    }
+    
+    Text
+    {
+        id: callDurationInd
+        anchors {bottom: callerInd.top; right: parent.right; topMargin: 10; rightMargin: parent.width * 0.2}
+        font {pixelSize: 22}
+        color: '#dfdfdf'
+        text: callDuration
+    }
+
+    Item
+    {
+        id: buttons
+        anchors {top: callerInd.bottom; topMargin: 15; left: parent.left; leftMargin: parent.width * 0.2; right: parent.right; rightMargin: parent.width * 0.2}
+       
+        width: parent.width * 0.75
+        height: 72
+
+        Image
+        {
+            id: answerButton
+            height: 72
+            width: parent.width *0.45
+            anchors {left: parent.left;}
+            source: "/usr/share/hfdialer/images/ivi_btn-incomingcall-accept.png"
+           
+            Image
+            {
+                width: 40; height: width
+                anchors.centerIn: parent
+                smooth: true
+                source: "/usr/share/hfdialer/images/ivi_icon-call.png"
+            }
+
+            MouseArea
+            {
+                anchors.fill: parent
+
+                onPressed: {
+                    answerButton.source = "/usr/share/hfdialer/images/ivi_btn-incomingcall-accept-active.png"
+                }
+
+                onReleased: {
+                    answerButton.source = "/usr/share/hfdialer/images/ivi_btn-incomingcall-accept.png"
+                }
+
+                onClicked: {
+                    console.log("*** QML *** :: Answering call");
+                    adapter.currentCall.answer();
+                }
+            }
+        }
+
+        Image
+        {
+            id: hangupButton
+            height: 72
+           width: parent.width * 0.45
+            anchors {right: parent.right;}
+            source: "/usr/share/hfdialer/images/ivi_btn-incomingcall-decline.png"
+
+            Image
+            {
+                width: 40; height: width
+                anchors.centerIn: parent
+                smooth: true
+                source: "/usr/share/hfdialer/images/ivi_icon-endcall.png"
+            }
+
+            MouseArea
+            {
+                anchors.fill: parent
+
+                onPressed: {
+                    hangupButton.source = "/usr/share/hfdialer/images/ivi_btn-incomingcall-decline-active.png"
+                }
+
+                onReleased: {
+                    hangupButton.source = "/usr/share/hfdialer/images/ivi_btn-incomingcall-decline.png"
+                }
+
+                onClicked: {
+                    console.log("*** QML *** :: Hanging up call");
+                   root.parent.state = 'disconnected'
+                   adapter.hangupAll();
+                    root.state = 'disconnected'
+                   root.parent.parent.state = 'disconnected'
+                    if (root.parent.parent.call)
+                       root.parent.parent.call = null
+                   if (root.call)
+                       root.call = null
+                }
+            }
+        }
+    }
+}
+
diff --git a/qml/DeviceDelegate.qml b/qml/DeviceDelegate.qml
new file mode 100644 (file)
index 0000000..a4cc51c
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2012 Intel Corporation.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0.  The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+import Qt 4.7
+Item {
+    id: root
+    property string deviceName
+    property string address
+    property string icon: ""
+    property string alias: ""
+    property string dbuspath: ""
+    property variant uuids: []
+
+    property int containerHeight: 80
+    height: containerHeight
+    width: parent.width
+    signal clicked()
+    signal close()
+    Image {
+        id: availableBluetoothItem
+        source: "/usr/share/hfdialer/images/ivi_btn-list-inactive.png"   
+        anchors {fill: parent; leftMargin: 8; rightMargin: 8; topMargin: 8}
+
+       Image {
+           id: iconImg
+           source: icon == "phone" ? "/usr/share/hfdialer/images/bluetooth-smartphone.png" : 
+                                     "/usr/share/hfdialer/images/computer.png"
+            height: availableBluetoothItem.containerHeight * 0.75
+           width: height
+            anchors {left: parent.left; verticalCenter: parent.verticalCenter; leftMargin: icon == "phone"? 10 : 10;}
+       }
+       
+        Text {
+            id: mainText
+
+            anchors {left: iconImg.right; right: parent.right; top: parent.top; bottom: parent.bottom; rightMargin: 10; leftMargin: icon == "phone"? 18 : 18;}
+            verticalAlignment: Text.AlignVCenter
+            height:  availableBluetoothItem.containerHeight
+            font.pixelSize: parent.height / 2
+            style: Text.Outline
+            styleColor: "#3B3A39"
+            color: "white"            
+            text: root.deviceName
+            elide: Text.ElideRight
+        }
+
+    }
+
+    MouseArea {
+        id: mArea
+          anchors.fill: parent
+
+          onPressed: {
+              availableBluetoothItem.source = "/usr/share/hfdialer/images/ivi_btn-list.png"
+          }
+          onReleased: {
+              availableBluetoothItem.source = "/usr/share/hfdialer/images/ivi_btn-list-inactive.png"
+              root.clicked()
+          }
+    }
+}
diff --git a/qml/DeviceDelegateActive.qml b/qml/DeviceDelegateActive.qml
new file mode 100644 (file)
index 0000000..663b9ce
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2012 Intel Corporation.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0.  The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+import Qt 4.7
+Item {
+    id: root
+    property string deviceName
+    property string address
+    property string icon: ""
+    property string alias: ""
+    property string dbuspath: ""
+    property variant uuids: []
+
+    property int containerHeight: 80
+    height: containerHeight
+    width: parent.width
+    signal clicked()
+    signal close()
+
+    Connections {
+        target: adapter
+        onModemOnlineChanged: {
+
+            //If the modem gets powered down for any reason, attempt to power it again to maintain connection
+            if (!adapter.modemOnline)
+            {
+                mainText.color = "grey"
+                availableBluetoothItem.source = "/usr/share/hfdialer/images/ivi_btn-list-inactive.png"
+            }
+            else
+            {
+                mainText.color = "white"
+                availableBluetoothItem.source = "/usr/share/hfdialer/images/ivi_btn-list.png"
+            }
+         }
+    }
+
+    Image {
+        id: availableBluetoothItem
+
+        source: !adapter.modemOnline? "/usr/share/hfdialer/images/ivi_btn-list-inactive.png" : availableBluetoothItem.source = "/usr/share/hfdialer/images/ivi_btn-list.png"
+        anchors {fill: parent; leftMargin: 8; rightMargin: 8; topMargin: 8}
+
+       MouseArea {
+          id: clickArea
+          anchors.fill: parent
+
+           onPressed: {
+                availableBluetoothItem.source = "/usr/share/hfdialer/images/ivi_btn-list.png"            
+            }
+
+            onReleased: {
+                availableBluetoothItem.source = "/usr/share/hfdialer/images/ivi_btn-list-inactive.png"      
+            }
+
+            onClicked: {
+                adapter.modemOnline = true
+            }
+        }
+
+        Text {
+            id: mainText
+
+            anchors {left: parent.left; top: parent.top; bottom: parent.bottom; leftMargin: 15}
+            width: parent.width * 0.75
+
+            verticalAlignment: Text.AlignVCenter
+            height:  availableBluetoothItem.containerHeight
+            font.pixelSize: parent.height / 2
+            style: Text.Outline
+            styleColor: "#3B3A39"
+            color: !adapter.modemOnline? "grey" : "white"
+            text: root.deviceName
+            elide: Text.ElideRight
+        }
+
+        Image {
+            id: closeButton
+            source: "/usr/share/hfdialer/images/ivi_icon-list-delete.png"
+            anchors { left: mainText.right; right: parent.right; top: parent.top; bottom: parent.bottom}
+
+            MouseArea {
+                id: closeArea
+                  anchors.fill: parent
+
+            onPressed: {
+                closeButton.source = "/usr/share/hfdialer/images/ivi_icon-list-delete-active.png"
+            }
+
+            onReleased: {
+                closeButton.source = "/usr/share/hfdialer/images/ivi_icon-list-delete.png"
+            }
+
+            onClicked: {
+                console.log("CLOSE BUTTON CLICKED")
+                root.close()
+                }
+            }
+        }
+    }
+}
diff --git a/qml/DialNumPad.qml b/qml/DialNumPad.qml
new file mode 100644 (file)
index 0000000..a4d8b68
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ * Copyright 2012 Intel Corporation.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0.  The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+import Qt 4.7
+
+Item
+{
+    id: root
+
+    property bool numPadShown: true
+    property DialNumberEntry entry
+    property TextInput pidEdit
+    property bool pidRequest: false
+
+    height: parent.height
+    property real buttonHeight: (parent.height / 5) - 41;
+
+    function insertText(text)
+    {
+        if (!pidRequest)
+            entry.appendChar(text)
+        else if (text != "*" && text != "#")
+        {
+            pidEdit.text += text
+        }
+    }
+
+    Image
+    {
+        id: numpad
+        width: parent.width; height: childrenRect.height + 21;
+        source: "/usr/share/hfdialer/images/ivi_buttonarea.png"
+        Behavior on opacity {PropertyAnimation {duration: 500}}
+
+        Column
+        {
+            id: columnBox
+            anchors {top: parent.top; right: parent.right; left: parent.left; margins: 11}
+            spacing: 5
+
+            Row
+            {
+                width: parent.width
+                anchors {bottomMargin: 5}
+                spacing: 5
+
+                DialNumPadButton {
+                    id: dial1
+                    text: qsTr("1");
+                    height: buttonHeight;
+                    onClicked: root.insertText(text);
+                    onPressAndHold: main.dialMailbox();
+                }
+                DialNumPadButton {
+                    text: qsTr("2");
+                    height: buttonHeight;
+                    detail: qsTr("abc");
+                    onClicked: root.insertText(text);
+                    onPressAndHold: main.dialSpeedDial(1);
+                }
+                DialNumPadButton {
+                    text: qsTr("3");
+                    height: buttonHeight;
+                    detail: qsTr("def");
+                    onClicked: root.insertText(text);
+                    onPressAndHold: main.dialSpeedDial(2);
+                }
+            }
+            Row
+            {
+                width: parent.width
+                anchors.horizontalCenter: parent.horizontalCenter
+                spacing: 5
+                DialNumPadButton {
+                    text: qsTr("4");
+                    height: buttonHeight;
+                    detail: qsTr("ghi");
+                    onClicked: root.insertText(text);
+                    onPressAndHold: main.dialSpeedDial(3);
+                }
+                DialNumPadButton {
+                    text: qsTr("5");
+                    height: buttonHeight;
+                    detail: qsTr("jkl");
+                    onClicked: root.insertText(text);
+                    onPressAndHold: main.dialSpeedDial(4);
+                }
+                DialNumPadButton {
+                    text: qsTr("6");
+                    height: buttonHeight;
+                    detail: qsTr("mno");
+                    onClicked: root.insertText(text);
+                    onPressAndHold: main.dialSpeedDial(5);
+                }
+            }
+            Row
+            {
+                width: parent.width
+                anchors.horizontalCenter: parent.horizontalCenter
+                spacing: 5
+                DialNumPadButton {
+                    text: qsTr("7");
+                    height: buttonHeight;
+                    detail: qsTr("pqrs");
+                    onClicked: root.insertText(text);
+                    onPressAndHold: main.dialSpeedDial(6);
+                }
+                DialNumPadButton {
+                    text: qsTr("8");
+                    height: buttonHeight;
+                    detail: qsTr("tuv");
+                    onClicked: root.insertText(text);
+                    onPressAndHold: main.dialSpeedDial(7);
+                }
+                DialNumPadButton {
+                    text: qsTr("9");
+                    height: buttonHeight;
+                    detail: qsTr("wxyz");
+                    onClicked: root.insertText(text);
+                    onPressAndHold: main.dialSpeedDial(8);
+                }
+            }
+            Row
+            {
+                width: parent.width
+                anchors.horizontalCenter: parent.horizontalCenter
+                spacing: 5
+                DialNumPadButton {
+                    text: qsTr("*");
+                    height: buttonHeight;
+                    onClicked: root.insertText(text);
+                    onPressAndHold: root.insertText("p");
+                }
+                DialNumPadButton {
+                    text: qsTr("0");
+                    height: buttonHeight;
+                    detail: qsTr("+");
+                    onClicked: root.insertText(text);
+                    onPressAndHold: root.insertText("+");
+                }
+                DialNumPadButton {
+                    text: qsTr("#");
+                    height: buttonHeight;
+                    onClicked: root.insertText(text);
+                    onPressAndHold: root.insertText("w");
+                }
+            }
+
+
+
+            Row
+            {
+                id: actions
+                width: parent.width; height: dial1.height
+
+                spacing: 5
+                Image {
+                    id: bDelete;
+                    width: parent.width / 4; height: parent.height
+                    source: "/usr/share/hfdialer/images/ivi_btn-delete.png"
+                    Image {
+                        anchors{ left: bDelete.left}
+                        height: parent.height
+                        width: parent.width
+                        source: "/usr/share/hfdialer/images/ivi_icon-delete.png"
+                        fillMode: Image.PreserveAspectFit
+                    }
+                    MouseArea
+                    {
+                        anchors.fill: parent
+                        onClicked:
+                        {
+                            if (!pidRequest){
+
+                                if(entry.textInput.text == entry.placeHolderText)
+                                    return;
+
+                                entry.textInput.text = entry.textInput.text.substring(0, entry.textInput.text.length -1);
+                            }
+                            else
+                                pidEdit.text = pidEdit.text.substring(0, pidEdit.text.length -1);
+                        }
+
+                        onPressAndHold:
+                        {
+                            if (!pidRequest)
+                                entry.clear();
+                            else
+                                pidEdit.text = "";
+                        }
+                    }
+                }
+
+                Image {
+                    id: bCall;
+
+                    height: parent.height
+                    width: parent.width - bDelete.width - closeButton.width - 5
+                    source: "/usr/share/hfdialer/images/ivi_btn-call.png"
+
+                    Image {
+                        anchors { centerIn: parent}
+                        height: parent.height
+                        width: parent.width
+                        source: "/usr/share/hfdialer/images/ivi_icon-call.png"
+                        fillMode: Image.PreserveAspectFit
+                    }
+
+                    MouseArea{
+                        anchors.fill: parent
+                        onClicked: {
+                            if (!pidRequest)
+                            {
+                                if(entry.isBlank())
+                                {
+                                    console.log("*** QML *** :: You can not dial without a number!");
+                                    main.showErrorMessage(qsTr("You can't dial without a number!"));
+                                    return;
+                                }
+
+                                if(main.dial(entry.textInput.text))
+                                {
+                                    entry.clear();
+                                }
+                            }
+                        }
+                    }
+                }
+
+                Image
+                {
+                    id: closeButton
+                    source: "/usr/share/hfdialer/images/ivi_btn-close.png"
+                    height: parent.height   
+                    width: (parent.width / 7) - 5
+
+                    MouseArea {
+                        id: closeArea
+                          anchors.fill: parent
+
+                    onClicked: {
+                        console.log("CLOSE BUTTON CLICKED")
+
+                        Qt.quit()
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/qml/DialNumPadButton.qml b/qml/DialNumPadButton.qml
new file mode 100644 (file)
index 0000000..0593768
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2012 Intel Corporation.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0.  The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+import Qt 4.7
+
+Item
+{
+    id: root
+
+    property Item numpad
+
+    property string text: ''
+    property string detail: ''
+
+    property int marginSize: 10
+
+    signal clicked
+    signal pressAndHold
+
+    width: (parent.width - marginSize) / 3; height: 72
+
+    SystemPalette {id: palette; colorGroup: SystemPalette.Active}
+
+    Image
+    {
+        id: buttonImg
+        anchors {fill: parent;}                       
+        source: "/usr/share/hfdialer/images/ivi_btn-numbers.png"
+
+    }
+
+    Text
+    {
+        width: parent.width
+        height: parent.height * 0.6
+        anchors {centerIn: parent}
+        text: parent.text
+        horizontalAlignment: Text.AlignHCenter
+        verticalAlignment: Text.AlignVCenter
+        font {pixelSize: parent.height / 2}
+        color: "white"
+       style: Text.Outline;
+       styleColor: "#3B3A39"
+    }
+
+    Text
+    {    
+        anchors {top: parent.top; right: parent.right; topMargin: 21; rightMargin: 17}
+        text: parent.detail       
+        font {pixelSize: 15}
+        color: "#D8D8D8"
+    }
+
+    MouseArea
+    {
+        anchors.fill: parent
+
+        onPressed: {
+            buttonImg.source = "/usr/share/hfdialer/images/ivi_btn-numbers-active.png"
+        }
+       
+       onReleased: {
+           buttonImg.source = "/usr/share/hfdialer/images/ivi_btn-numbers.png"        
+       }
+        onClicked: {
+            root.clicked();
+        }
+        onPressAndHold: root.pressAndHold();
+    }
+}
diff --git a/qml/DialNumberEntry.qml b/qml/DialNumberEntry.qml
new file mode 100644 (file)
index 0000000..926f96e
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * dialer - QML User Interface Component
+ *
+ * Copyright (c) 2011, Tom Swindell.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0.  The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ */
+
+import Qt 4.7
+
+Image
+{
+    property string placeHolderText: qsTr("Enter Number")
+    property TextInput textInput: input
+
+    id: root
+    source: "/usr/share/hfdialer/images/ivi_textarea.png"
+    function clear()
+    {
+        input.color = "#3B3A39";
+        input.text = placeHolderText;
+    }
+
+    function isBlank()
+    {
+        return (input.text == placeHolderText);
+    }
+
+    function appendChar(character)
+    {
+        if(input.text == placeHolderText) {input.text = character} else {input.text += character};
+    }
+
+    TextInput
+    {
+        id: input
+        anchors.centerIn: parent   
+        color: "#3B3A39"
+        cursorVisible: false
+        activeFocusOnPress: false
+        inputMethodHints: Qt.ImhDialableCharactersOnly
+        font {pixelSize: 42}
+        text: placeHolderText
+
+        Component.onCompleted: forceActiveFocus();
+
+        onTextChanged: {
+            if(text.length == 0) root.clear();
+
+            if(text.length > placeHolderText.length && text.substr(0, placeHolderText.length) == placeHolderText)
+            {
+              text = text.substr(placeHolderText.length);
+            }
+
+            if(text.length < placeHolderText.length && placeHolderText.substr(0, text.length) == text)
+            {
+              text = placeHolderText;
+            }
+
+            if(text == placeHolderText)
+            {
+                color = "#3B3A39";
+            }
+            else
+            {
+                color = "#3B3A39";
+            }
+        }
+
+        onAccepted: {
+          main.dial(text)
+        }
+    }
+}
diff --git a/qml/DialPage.qml b/qml/DialPage.qml
new file mode 100644 (file)
index 0000000..272dee6
--- /dev/null
@@ -0,0 +1,410 @@
+/*
+ * Copyright 2012 Intel Corporation.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0.  The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+import Qt 4.7
+
+import Tizen.Bluetooth 0.0 
+
+Item
+{
+    id: root
+    width: parent.width; height: parent.height
+
+    property alias activeCall: activeCallView.call
+    property alias callState: activeCallView.state
+
+    Keys.onEscapePressed: {
+        console.log("Escape Pressed");
+        Qt.quit()
+    }
+
+    onCallStateChanged: {
+        if (activeCallView.state != 'disconnected')
+            dialPage.state = 'activeCall'
+        else
+            dialPage.state = 'noCall'
+    }
+
+    Timer {
+        id: reconnectTimer
+        interval: 3000
+        repeat: false
+        running: false
+
+        onTriggered:
+        {
+            adapter.modemOnline = true
+        }
+    }
+
+    Connections {
+        target: adapter
+        onModemOnlineChanged: {
+
+            //If the modem gets powered down for any reason, attempt to power it again to maintain connection
+            if (!adapter.modemOnline)
+            {
+                reconnectTimer.running = true;
+            }
+        }
+    }
+
+    Image
+    {
+        id: dialPage
+        anchors.fill: parent
+        source: "/usr/share/hfdialer/images/ivi-v1_ivi-background.jpg"
+        state: 'noCall'
+
+        DialNumberEntry
+        {
+            id: numberEntry
+            anchors {
+                top: parent.top; //bottom: numPad.top
+                left: parent.left; margins: 15 //right: parent.right
+                //margins: 10
+            }
+            width: parent.width * 0.60
+            height: parent.height / 4.5
+        }
+
+        DialNumPad
+        {
+            id: numPad
+            width: numberEntry.width
+            anchors {top: numberEntry.bottom; left: parent.left; bottom: parent.bottom; margins: 15}
+            entry: numberEntry
+        }
+        states{
+            State {
+                name: 'activeCall'
+                PropertyChanges {target: numPad; visible: false}
+                PropertyChanges {target: numberEntry; visible: false}
+                PropertyChanges {target: modemList; visible: false}
+                PropertyChanges {target: vertDivider; visible: false}
+            }
+            State {
+                name: 'noCall'
+                PropertyChanges {target: numPad; visible: true}
+                PropertyChanges {target: numberEntry; visible: true}
+                PropertyChanges {target: modemList; visible: true}
+                PropertyChanges {target: vertDivider; visible: true}
+            }
+
+
+        }
+
+        CallItemView
+        {
+            id: activeCallView
+        }
+
+        Rectangle {
+
+            id: vertDivider
+            anchors {left: numberEntry.right; margins: 8}
+            width: 4
+            height: parent.height
+            color: "#262626"
+
+        }
+
+        Rectangle {
+            id: modemList
+            anchors {left: vertDivider.right; right: parent.right; top: parent.top; bottom: parent.bottom}
+            color: "#51504F"
+
+            Text {
+                id: yourDevicesTxt
+                text: "Your Devices"
+                font.pixelSize: 42
+                color: "white"
+                anchors {top: parent.top; right: parent.right; left: parent.left; bottom: horizDivider1.top; leftMargin: 15}
+
+            }
+
+            Rectangle {
+                id: horizDivider1
+                anchors {left: parent.left; right: parent.right; topMargin: 8; bottomMargin: 8;}
+                y: 62
+                height: 3
+                color: "#B3BF3C"
+            }
+
+            Text {
+                id: moreDevicesTxt
+                text: "More Devices"
+                font.pixelSize: 42
+                color: "white"
+                anchors {right: parent.right; left: parent.left; bottom: horizDivider2.top; leftMargin: 15}
+                height: yourDevicesTxt.height
+            }
+
+            Rectangle {
+                id: horizDivider2
+                anchors {left: parent.left; right: parent.right; topMargin: 8; bottomMargin: 8;}
+                y: parent.height / 2
+                height: 3
+                color: "#B3BF3C"
+            }
+
+            Component.onCompleted: {
+                nearbyDevicesModel.discover(true);
+                console.log("Devices qml has been created, checking for BT: " + btDevicesModel.adapterPresent)
+
+            }
+
+            Component.onDestruction: {
+                nearbyDevicesModel.discover(false);
+            }
+
+            BluetoothDevicesModel {
+                id: btDevicesModel
+                property bool successFullPair: false
+                onDevicePaired: {
+
+                }
+            }
+
+            NearbyDevicesModel {
+                id: nearbyDevicesModel
+
+                property bool discovering: false
+
+                Component.onCompleted: {
+
+                }
+
+                onRequestConfirmation: {
+                    console.log("onRequestConfirm called")
+                }
+
+                onRequestPasskey: {
+                    console.log("onRequestPasskey called")
+
+                }
+
+                onRequestPidCode: {
+                    console.log("onRequestPidCode called")
+                }
+
+                onAdapterPropertiesChanged: {
+
+                    if(name == "Discovering") {
+                        discovering = value;
+                    }
+
+                }
+
+                onNearbyDeviceFound: {
+                    //console.log("new device: " + nearbyDevicesModel.alias(index))
+                }
+
+            }
+
+            Flickable{
+                id: activeFlickable
+
+                anchors {top: horizDivider1.bottom; bottom: moreDevicesTxt.top; left: parent.left; right: parent.right}
+                clip: true
+                contentWidth: parent.width
+                contentHeight: parent.height
+                flickableDirection: Flickable.VerticalFlick
+
+                Column {
+                    id: deviceList
+                    width: parent.width
+                    spacing: 2
+                    Repeater {
+                        model: btDevicesModel
+
+                        Component.onCompleted: {
+                            
+                            //Once model is completed, check if the modem is powered. If not, power it
+                            if (!adapter.modemOnline)
+                            {
+                                adapter.modemOnline = true
+                            }
+                        }
+
+                        delegate: DeviceDelegateActive {
+                            id: deligateItem
+                            deviceName: model.name
+                            address: model.address
+                            dbuspath: model.path
+                            uuids: model.profiles
+                            property BluetoothDevice device: btDevicesModel.device(dbuspath)
+
+                            Connections {
+                                target: btDevicesModel
+                                onDevicePaired: {
+                                    console.log("new paired device address:" + device.address + "==" + model.address)
+                                    if(device.address === model.address){
+                                        device.trusted = true
+                                    }
+                                }
+
+                                onConnectedChanged: {
+                                }
+                            }
+
+                            onClose: {
+                                console.log("unparing ...");
+                                device.unpair();
+                                btDevicesModel.deviceRemoved(device.path);
+                            }
+                        }
+                    }
+                }
+            }
+
+            Flickable{
+                id: modelFlickable
+                anchors {top: horizDivider2.bottom; bottom: parent.bottom; left: parent.left; right: parent.right}
+                clip: true
+                contentWidth: parent.width
+                contentHeight: parent.height
+                flickableDirection: Flickable.VerticalFlick
+
+                Column {
+                    id: nearbyDevicesList
+                    width: parent.width
+                    height: parent.height / 2
+
+                    Repeater {
+                        id: modelRepeater
+                        model: nearbyDevicesModel
+
+                        onCountChanged: {
+                            modelFlickable.contentHeight = (count * 80)
+                        }
+
+                        delegate: DeviceDelegate {
+                            id: availableBluetoothItem
+                            width: nearbyDevicesList.width
+                            deviceName: name
+                            icon: model.icon
+                            alias: model.alias
+                            anchors {margins: 8}
+
+                            onClicked: {
+                                console.log("BUTTON CLICKED bubbled up")
+                                nearbyDevicesModel.discover(false)
+                                nearbyDevicesModel.pair(model.address)
+                            }
+
+
+                            Connections {
+                                target: nearbyDevicesModel
+                                onRequestConfirmation: {
+                                    console.log("spawning request confirm dialog, device = " + device + " deviceName = " + deviceName)
+                                    if(device != deviceName) return;
+
+                                    dialogLoader.type = "confirmation"
+                                    dialogLoader.device = device
+                                    dialogLoader.code = code
+                                    dialogLoader.sourceComponent = requestConfirmDialogComponent
+
+                                }
+
+                                onRequestPasskey: {
+                                    console.log("spawning requestPasskeyDialog")
+                                    if(device != deviceName) return;
+
+                                    dialogLoader.type = "passkey"
+                                    dialogLoader.device = device
+                                    dialogLoader.sourceComponent = requestPasskeyDialogComponent
+
+                                }
+
+                                onRequestPidCode: {
+                                    console.log("spawning requestPidCodeDialog")
+                                    if(device != deviceName) return;
+
+
+                                    dialogLoader.type = "pidcode"
+                                    dialogLoader.device = device
+                                    dialogLoader.legacyPairing = model.legacyPairing
+                                    dialogLoader.sourceComponent = requestPidCodeDialogComponent
+
+                                    console.log(device + " model legacyPairing: " + model.legacyPairing)
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+
+
+            Loader {
+                id: dialogLoader
+                anchors.fill: parent
+                property string type: "NULL"
+                property string device: ""
+                property string code: ""
+                property bool legacyPairing: false
+
+                onLoaded: {
+                    console.log("LOADER LOADED! type = " + type)
+                    if (type === "confirmation" )
+                    {
+                        item.deviceName = device
+                        item.key = code
+                    }
+                    else if (type === "passkey" )
+                    {
+                        item.deviceName = device
+                    }
+                    else if (type === "pidcode" )
+                    {
+                        item.deviceName = device
+                        item.legacyPairing = legacyPairing
+                    }
+                }
+            }
+
+            Component {
+                id: requestPasskeyDialogComponent
+                RequestpasskeyDialog {
+                    id: requestPasskeyDialog
+
+                    onReplyRequestPasskey: {
+                        dialogLoader.sourceComponent = undefined
+                        nearbyDevicesModel.replyPasskey(reply)
+                    }
+                }
+            }
+
+            Component {
+                id: requestPidCodeDialogComponent
+                RequestPidCodeDialog {
+                    id: requestPidCodeDialog
+                    onReplyRequestPidCode: {
+                        dialogLoader.sourceComponent = undefined
+                        nearbyDevicesModel.replyRequestPidCode(reply)
+                    }
+                    onCancelRequest: {
+                        dialogLoader.sourceComponent = undefined
+                    }
+                }
+            }
+
+            Component {
+                id: requestConfirmDialogComponent
+                RequestConfirmDialog {
+                    id: requestConfirmDialog
+                    onReplyRequestConfirmation: {
+                        dialogLoader.sourceComponent = undefined
+                        nearbyDevicesModel.replyRequestConfirmation(reply)
+                    }
+                }
+            }
+        }
+    }
+}
+
diff --git a/qml/MessageDialog.qml b/qml/MessageDialog.qml
new file mode 100644 (file)
index 0000000..f707ec2
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * dialer - QML User Interface Component
+ *
+ * Copyright (c) 2011, Tom Swindell.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0.  The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ */
+
+import Qt 4.7
+
+AbstractDialog {
+    id: root
+
+    property string mesg: ''
+
+    Rectangle {
+        id: dialog
+        width: parent.width * 0.8; height: 300;
+        anchors.centerIn: parent
+        color: "white"
+        radius: 15
+        smooth: true
+
+        Text {
+            id: mesgText
+            width: parent.width * 0.9
+            anchors.centerIn: parent
+            wrapMode: Text.WordWrap
+            color: "black"
+            font.pixelSize: 32
+            text: "<center>" + root.mesg + "</center>"
+        }
+    }
+}
diff --git a/qml/RequestConfirmDialog.qml b/qml/RequestConfirmDialog.qml
new file mode 100644 (file)
index 0000000..ef9e74a
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2012 Intel Corporation.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0.  The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+import Qt 4.7
+
+Rectangle {
+    id: root
+    anchors.fill: parent
+    color: "#51504F"
+
+    property string deviceName: ""
+    property string key: ""
+    signal replyRequestConfirmation(bool reply)
+
+Column {
+    id: container
+    width: parent.width - 15
+    anchors {centerIn: parent}
+    spacing: 10
+    Component.onCompleted: {
+        console.log("request confirm dialog height: " + container.height + " width = " + container.width + " name = " + root.deviceName + " code = " + root.key)
+    }
+
+    Text {
+        id: textlabel
+        width: parent.width
+        height: paintedHeight
+        horizontalAlignment: Text.AlignHCenter
+        text: qsTr("Pair with %1 with key %2?").arg(root.deviceName).arg(root.key)
+        wrapMode: Text.WordWrap
+        font.pixelSize: 24
+        color: "White"
+    }
+
+    Row {
+        id: buttonGroup
+        anchors.horizontalCenter: parent.horizontalCenter
+        spacing: 10
+        height: 50
+
+        Image {
+            id: acceptButton
+            source: "/usr/share/hfdialer/images/ivi_btn-incomingcall-accept.png"
+            height: parent.height
+            width:  root.width / 2 - 20
+
+            MouseArea {
+                  anchors.fill: parent
+            onClicked: {
+                replyRequestConfirmation(true);
+            }
+            }
+            Text {
+                 text: qsTr("Accept")
+                 anchors.centerIn:parent
+                 font.pointSize: 14
+                 color: "white"
+             }
+        }
+
+        Image {
+            id: rejectButton
+            source: "/usr/share/hfdialer/images/ivi_btn-incomingcall-decline.png"
+
+            height: parent.height
+            width:  root.width / 2 - 20
+
+            MouseArea {
+                  anchors.fill: parent
+            onClicked: {
+                replyRequestConfirmation(false);
+            }
+            }
+
+            Text {                 
+                 text: qsTr("Reject")
+                 anchors.centerIn:parent
+                 font.pointSize: 14
+                 color: "white"
+             }
+        }
+    }
+
+}
+}
diff --git a/qml/RequestPidCodeDialog.qml b/qml/RequestPidCodeDialog.qml
new file mode 100644 (file)
index 0000000..8ff76e0
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2012 Intel Corporation.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0.  The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+import Qt 4.7
+
+Rectangle {
+    id: root
+    anchors.fill: parent
+    color: "#51504F"
+
+    signal replyRequestPidCode(string reply)
+    signal cancelRequest()
+    property string deviceName
+    property string replyValue: legacyPairing ? "0000" : Math.floor(Math.random()*999999)
+    property bool legacyPairing: false
+
+    Component.onCompleted: {
+        numPad.pidRequest = true
+        numPad.pidEdit = textInputField
+    }
+
+    Column {
+        width: parent.width - 15
+        anchors {centerIn: parent}
+        spacing: 10
+
+        Text {
+            id: textlabel
+            text: qsTr("Enter the following code on %1").arg(deviceName)
+            width: parent.width
+            wrapMode: Text.WordWrap
+            horizontalAlignment: Text.AlignHCenter
+            font.pixelSize: 24
+            color: "white"
+        }
+
+        Rectangle {
+            id: textInput
+            anchors.horizontalCenter: parent.horizontalCenter
+            height: 40
+            width: parent.width
+            color: "white"
+            radius: 5
+
+         TextInput {
+                id: textInputField
+                anchors.centerIn: parent
+                width: parent.width
+                height: parent.height * 0.75
+                font.pixelSize: 24
+                color: "black"
+                text: replyValue
+                horizontalAlignment: Text.AlignHCenter
+                activeFocusOnPress: false
+            }
+        }
+
+        Row {
+            id: buttonGroup
+            anchors.horizontalCenter: parent.horizontalCenter
+            spacing: 10
+            width: parent.width
+            height: 50
+
+            Image {
+                id: acceptButton
+                source: "/usr/share/hfdialer/images/ivi_btn-incomingcall-accept.png"
+                width: buttonGroup.width / 2 - 5
+                height: parent.height
+
+                MouseArea {
+                    anchors.fill: parent
+                    onClicked: {
+                        console.log(deviceName + " replying with key: " + textInputField.text)
+                        numPad.pidRequest = false
+                        replyRequestPidCode(textInputField.text);
+                    }
+                }
+
+                Text {
+                    id: acceptButtonText
+                    text: qsTr("Accept")
+                    anchors.centerIn:parent
+                    horizontalAlignment: Text.AlignHCenter
+                    font.pixelSize: 20
+                    color: "white"
+                }
+            }
+
+            Image {
+                id: rejectButton
+                source: "/usr/share/hfdialer/images/ivi_btn-incomingcall-decline.png"
+                width: buttonGroup.width / 2 - 5
+                height: parent.height
+
+                MouseArea {
+                    anchors.fill: parent
+                    onClicked: {
+                        console.log(deviceName + " replying with key: " + textInputField.text)
+                        numPad.pidRequest = false
+                        cancelRequest()
+                    }
+                }
+
+                Text {
+                    id: cancelButtonText
+                    text: qsTr("Cancel")
+                    anchors.centerIn:parent
+                    horizontalAlignment: Text.AlignHCenter
+                    font.pixelSize: 20
+                    color: "white"
+                }
+            }
+
+
+        }
+
+    }
+    ///we do this because this property is actually set post onCompleted:
+    onLegacyPairingChanged: {
+        console.log("legacy pair? " + legacyPairing)
+        if(!legacyPairing) {
+            replyRequestPidCode(textInputField.text);
+            console.log(deviceName + " replying with key: " + replyValue)
+        }
+    }
+
+}
diff --git a/qml/RequestpasskeyDialog.qml b/qml/RequestpasskeyDialog.qml
new file mode 100644 (file)
index 0000000..828abeb
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2012 Intel Corporation.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0.  The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+import Qt 4.7
+
+Rectangle {
+    id: root
+    anchors.fill: parent
+    color: "#51504F"
+
+
+    signal replyRequestPasskey(int reply)
+    property string deviceName
+
+    Component.onCompleted: {
+        numPad.pidRequest = true
+        numPad.pidEdit = textInputField
+    }
+
+Column {
+    width: parent.width - 15
+    spacing: 10
+
+    Text {
+        id: textlabel
+        anchors.horizontalCenter: parent.horizontalCenter
+        text: qsTr("Enter passcode to use:")
+        wrapMode: Text.WordWrap
+        horizontalAlignment: Text.AlignHCenter
+        width: parent.width
+        font.pixelSize: 24
+        color: "white"
+    }
+
+    Rectangle {
+        id: textInput
+        anchors.horizontalCenter: parent.horizontalCenter
+        height: 40
+        width: parent.width
+        color: "white"
+        radius: 5
+
+        TextInput {
+            id: textInputField           
+            anchors.centerIn: parent
+            width: parent.width
+            height: parent.height * 0.75
+            font.pixelSize: 24
+            color: "black"
+            text: replyValue
+            horizontalAlignment: Text.AlignHCenter
+            activeFocusOnPress: false
+        }
+    }
+
+   Image {
+        id: acceptButton
+        source: "/usr/share/hfdialer/images/ivi_btn-incomingcall-accept.png"
+        anchors.horizontalCenter: parent.horizontalCenter
+        width: textInput.width
+        height: 50
+
+        MouseArea {
+              id: mouseArea
+              anchors.fill: parent
+
+        onClicked: {
+            numPad.pidRequest = false
+            nearbyDevicesModel.replyRequestPasskey(textInputField.text);
+            }
+        }
+    }
+
+   Text {
+        id: text
+        text: qsTr("Accept")
+        anchors.centerIn:parent
+        horizontalAlignment: Text.AlignHCenter
+        font.pixelSize: 20
+        color: "white"
+    }
+}
+}
diff --git a/qml/javascripts/framework.js b/qml/javascripts/framework.js
new file mode 100644 (file)
index 0000000..f8f734e
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Generic Javascript Utility Functions
+ *
+ * Copyright (c) 2011, Tom Swindell.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0.  The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ */
+
+Date.prototype.getFormat = function()
+{
+    return (this.getDate() < 10 ? '0' : '') + this.getDate() + '/' +
+           (this.getMonth() < 10 ? '0' : '') + this.getMonth() + '/' +
+           this.getFullYear() +
+           ' | ' +
+           (this.getHours() < 10 ? '0' : '') + this.getHours() + ':' +
+           (this.getMinutes() < 10 ? '0' : '') + this.getMinutes() + ':' +
+           (this.getSeconds() < 10 ? '0' : '') + this.getSeconds();
+}
+
+function friendlyInterval(duration)
+{
+    duration = Number(duration);
+    if(isNaN(duration)) duration = 0;
+
+    var hours    = Math.floor(duration / 3600);
+    var minutes  = Math.floor((duration % 3600) / 60);
+    var seconds  = duration % 60;
+
+    return (hours < 10 ? '0' : '') + hours + ':' + (minutes < 10 ? '0' : '') + minutes + ':' + (seconds < 10 ? '0' : '') + seconds;
+}
+
+function friendlyDuration(start, end)
+{
+    var duration = Math.floor(((new Date(end)) - (new Date(start))) / 1000);
+    return friendlyInterval(duration);
+}
+
diff --git a/qml/main.qml b/qml/main.qml
new file mode 100644 (file)
index 0000000..694dd09
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2012 Intel Corporation.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0.  The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+import Qt 4.7
+import com.hfdialer 1.0
+
+import 'javascripts/framework.js' as Support
+
+Item
+{
+    id: main
+
+    width: 1024; height: 600
+
+    Dialer { id: adapter }
+
+    Component.onCompleted: {
+      console.log("######## Completed loading component, initializing...");
+
+      adapter.incomingCall.connect(function()
+      {
+        var call = adapter.currentCall;
+
+        console.log("*** QML *** :: INCOMING CALL:" + call);
+        console.log("*** QML *** ::   MSISDN: " + call.msisdn);
+        console.log("*** QML *** ::    START: " + call.startedAt);
+        console.log("");
+
+        dialpage.activeCall = call       
+
+      });
+
+      if(adapter.currentCall)
+      {
+        dialpage.activeCall = call
+      }
+
+    }
+
+    function showErrorMessage(mesg) {
+        mesgDialog.mesg = mesg;
+        mesgDialog.state = 'shown';
+    }
+
+    function dial(msisdn) {
+        if(msisdn.trim().length == 0)
+        {
+            console.log("*** QML *** :: You can't dial without a number!");
+            showErrorMessage(qsTr("No number specified!"));
+            return false;
+        }
+
+        if (!adapter.modemOnline)
+        {
+          console.log("*** QML *** :: modem is not available or powered down");
+          showErrorMessage(qsTr("modem is not available or powered down!"));
+          return false;
+        }
+
+        console.log("*** QML *** :: Attempting to dial MSISDN: " + msisdn);
+
+        dialpage.activeCall = {
+          state: 'dialing',
+          msisdn: msisdn
+        };
+
+        adapter.dial(msisdn);
+
+        return true;
+    }
+
+    function dialMailbox() {
+        if(adapter.mailbox) {
+            console.log("*** QML *** :: Attempting to call mailbox number: " + adapter.mailbox);
+            main.dial(adapter.mailbox);
+        } else {
+            console.log("*** QML *** :: No mailbox number defined!");
+            showErrorMessage(qsTr("No mailbox number defined."));
+        }
+    }
+
+    function dialSpeedDial(index) {
+        if(adapter.speedDial(index))
+        {
+            console.log("*** QML *** :: Calling speed dial " + index + ": " + adapter.speedDial(index));
+            main.dial(adapter.speedDial(index));
+        } else {
+            console.log("*** QML *** :: No speed dial number defined for: " + index);
+            showErrorMessage(qsTr("No speed dial for " + (index + 1)));
+        }
+    }
+
+    DialPage
+    {
+        id: dialpage
+        anchors.fill: parent
+    }
+
+    MessageDialog {
+        id: mesgDialog
+        state: 'hidden'
+    }
+}
+
diff --git a/qml/qml.pro b/qml/qml.pro
new file mode 100644 (file)
index 0000000..6fa77d2
--- /dev/null
@@ -0,0 +1,9 @@
+TEMPLATE = subdirs
+CONFIG += ordered
+
+qml.files = *.qml javascripts
+qml.path  = $${installPrefix}/usr/share/hfdialer/qml
+
+OTHER_FILES += *.qml
+
+INSTALLS += qml
diff --git a/sounds/ring-1.wav b/sounds/ring-1.wav
new file mode 100644 (file)
index 0000000..5730ca4
Binary files /dev/null and b/sounds/ring-1.wav differ
diff --git a/sounds/sounds.pro b/sounds/sounds.pro
new file mode 100644 (file)
index 0000000..de18634
--- /dev/null
@@ -0,0 +1,7 @@
+TEMPLATE = subdirs
+CONFIG += ordered
+
+sounds.files += *.wav
+sounds.path  += $${installPrefix}/usr/share/hfdialer/sounds
+
+INSTALLS += sounds
diff --git a/src/callitem.cpp b/src/callitem.cpp
new file mode 100644 (file)
index 0000000..aff978c
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * hfdialer - Hands Free Voice Call Manager
+ * Copyright (c) 2012, Intel Corporation.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0.  The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ */
+
+#include "common.h"
+#include "callitem.h"
+#include "dialerapplication.h"
+#include "pacontrol.h"
+#include <QGraphicsItem>
+#include <QGraphicsWidget>
+#include <QDebug>
+
+#define DEFAULT_RINGTONE "ring-1.wav"
+
+CallItem::CallItem(const QString path, QObject *parent)
+    : QObject(parent),
+      m_path(path),
+      m_rtKey(new MGConfItem("/apps/dialer/defaultRingtone")),
+      m_isconnected(FALSE)
+{
+    TRACE;
+    QString l_ringtoneFile = QString("/usr/share/hfdialer/sounds/%1").arg(DEFAULT_RINGTONE);
+    QString l_rtKeyValue = m_rtKey->value(QVariant(l_ringtoneFile)).toString();
+
+    if (!QFileInfo(l_rtKeyValue).exists()) {
+        qWarning() << QString("CallItem: %1 ringtone not found: %2")
+            .arg(m_path)
+            .arg(l_rtKeyValue);
+    }
+
+    if (isValid()) {
+        init();
+    }
+}
+
+CallItem::~CallItem()
+{
+    TRACE;
+    PAControl::instance()->unrouteAudio();
+   
+    if (m_rtKey) {
+        delete m_rtKey;
+    }
+    m_rtKey = 0;
+
+    // delete the callproxy object
+    if (callProxy())
+        delete callProxy();
+}
+
+void CallItem::init()
+{
+    TRACE;
+    if (!m_path.isEmpty()) {
+        m_call = new CallProxy(m_path);
+        if (m_call->isValid()) {
+            // dynamic_cast<CallItemModel*>(model())->setCall(call);
+            connect(m_call,SIGNAL(stateChanged()),this,SLOT(callStateChanged()));
+            connect(m_call,SIGNAL(dataChanged()),this,SLOT(callDataChanged()));
+            connect(m_call,SIGNAL(multipartyChanged()),this,SLOT(callMultipartyChanged()));
+        } else {
+            qCritical("Invalid CallProxy instance!");
+        }
+    } else {
+        qCritical("Empty call path.  Can not create CallProxy!");
+    }
+}
+
+bool CallItem::isValid()
+{
+    TRACE;
+    return (!path().isEmpty());
+}
+
+bool CallItem::isValid() const
+{
+    TRACE;
+    return (!path().isEmpty());
+}
+
+QString CallItem::path() const
+{
+    TRACE;
+    return m_path;
+}
+
+bool CallItem::setPath(QString path)
+{
+    TRACE;
+    if (!m_path.isEmpty()) {
+        qCritical("Path already set and can not be changed once it is set");
+        return false;
+    } else if (path.isEmpty()) {
+        qCritical("It makes no sense to set Path to an empty string!?!?");
+        return false;
+    }
+
+    m_path = path;
+
+    init();
+
+    return true;
+}
+
+void CallItem::setDirection(CallDirection direction)
+{
+    TRACE; 
+}
+
+QString CallItem::lineID() const
+{
+    TRACE;
+    return m_call->lineID();
+}
+
+QString CallItem::name() const
+{
+    TRACE;
+    return m_call->name();
+}
+
+CallState CallItem::state() const
+{
+    TRACE;
+    CallState cs = STATE_NONE;
+    QString state = m_call->state();
+
+    if (state == "active")
+        cs = STATE_ACTIVE;
+          
+    else if (state == "held")
+        cs = STATE_HELD;
+    else if (state == "dialing")
+        cs = STATE_DIALING;
+    else if (state == "alerting")
+        cs = STATE_ALERTING;
+    else if (state == "incoming")
+        cs = STATE_INCOMING;
+    else if (state == "waiting")
+        cs = STATE_WAITING;
+    else if (state == "disconnected")
+        cs = STATE_DISCONNECTED;
+
+    return cs;
+}
+
+CallDirection CallItem::direction() const
+{
+    TRACE;
+    return DIRECTION_NONE;
+}
+
+CallDisconnectReason CallItem::reason() const
+{
+    TRACE;
+    return DISCONNECT_NONE; 
+}
+
+int CallItem::duration() const
+{
+    TRACE;
+    return m_call->duration();
+}
+
+QDateTime CallItem::startTime() const
+{
+    TRACE;
+    return m_call->startTime();
+}
+
+CallProxy* CallItem::callProxy() const
+{
+    TRACE;
+    return m_call;
+}
+
+void CallItem::click()
+{
+    TRACE;
+
+    emit clicked();
+}
+
+void CallItem::silenceRingtone()
+{
+    TRACE;
+}
+
+void CallItem::callStateChanged()
+{
+    TRACE;
+    emit stateChanged();
+}
+
+void CallItem::callDataChanged()
+{
+    TRACE;
+}
+
+void CallItem::callDisconnected(const QString &reason)
+{
+    TRACE;
+    Q_UNUSED(reason);
+}
+
+
+bool CallItem::multiparty()
+{
+    TRACE; 
+    return false;   
+}
+
+void CallItem::callMultipartyChanged()
+{
+    TRACE;
+    emit multipartyChanged();
+}
+
+/* Local Variables:      */
+/* mode:c++              */
+/* c-basic-offset:4      */
+/* indent-tabs-mode: nil */
+/* End:                  */
diff --git a/src/callitem.h b/src/callitem.h
new file mode 100644 (file)
index 0000000..5b74c59
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * hfdialer - Hands Free Voice Call Manager
+ * Copyright (c) 2012, Intel Corporation.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0.  The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ */
+
+#ifndef CALLITEM_H
+#define CALLITEM_H
+
+#include <QString>
+#include <QDateTime>
+#include <QtDBus>
+#include <MGConfItem>
+#include "callproxy.h"
+
+enum CallState {
+    STATE_NONE = 0,
+    STATE_ACTIVE,
+    STATE_HELD,
+    STATE_DIALING,
+    STATE_ALERTING,
+    STATE_INCOMING,
+    STATE_WAITING,
+    STATE_DISCONNECTED,
+    STATE_LAST,
+};
+
+enum CallDirection {
+    DIRECTION_NONE = 0,
+    DIRECTION_IN,
+    DIRECTION_OUT,
+    DIRECTION_MISSED,
+    DIRECTION_LAST,
+};
+
+enum CallDisconnectReason {
+    DISCONNECT_NONE = 0,
+    DISCONNECT_LOCAL,
+    DISCONNECT_REMOTE,
+    DISCONNECT_NETWORK,
+    DISCONNECT_LAST,
+};
+
+class CallItem: public QObject 
+{
+    Q_OBJECT
+
+    Q_PROPERTY(QString path READ path WRITE setPath)
+        Q_PROPERTY(QString lineID READ lineID)
+        Q_PROPERTY(QString name READ name)
+        Q_PROPERTY(CallState state READ state)
+        Q_PROPERTY(CallDirection direction READ direction WRITE setDirection)
+        Q_PROPERTY(CallDisconnectReason reason READ reason)
+        Q_PROPERTY(int duration READ duration)
+        Q_PROPERTY(QDateTime startTime READ startTime)
+        Q_PROPERTY(bool multiparty READ multiparty)
+        Q_PROPERTY(CallProxy* callProxy READ callProxy)
+
+        public:
+        CallItem(const QString path = QString(), QObject *parent = 0);
+    virtual ~CallItem();
+
+    QString path() const;
+    QString lineID() const;
+    QString name() const;
+    CallState state() const;
+    CallDirection direction() const;
+    CallDisconnectReason reason() const;
+    int duration() const;
+    QDateTime startTime() const;
+    CallProxy *callProxy() const;
+    bool isValid();
+    bool isValid() const;
+    bool multiparty();
+
+public Q_SLOTS:
+    void init();
+    bool setPath(QString path);  // Setting this will create the CallProxy
+    void setDirection(CallDirection direction);
+    void click();
+
+    void silenceRingtone();
+
+Q_SIGNALS:
+    // TODO: handle tap-and-hold
+    void clicked();
+    void stateChanged();
+    void dataChanged();
+    void multipartyChanged();
+
+private Q_SLOTS:
+    void callStateChanged();
+    void callDataChanged();
+    void callDisconnected(const QString &reason);
+    void callMultipartyChanged();
+
+private:
+    QString               m_path;
+    MGConfItem           *m_rtKey;
+    bool                  m_isconnected;
+    QString               m_ringtonefile;
+    CallProxy           *m_call;
+
+    Q_DISABLE_COPY(CallItem)
+};
+
+#endif // CALLITEM_H
+
+/* Local Variables:      */
+/* mode:c++              */
+/* c-basic-offset:4      */
+/* indent-tabs-mode: nil */
+/* End:                  */
diff --git a/src/callmanager.cpp b/src/callmanager.cpp
new file mode 100644 (file)
index 0000000..01608e7
--- /dev/null
@@ -0,0 +1,481 @@
+/*
+ * hfdialer - Hands Free Voice Call Manager
+ * Copyright (c) 2012, Intel Corporation.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0.  The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ */
+
+#include "common.h"
+#include "callmanager.h"
+
+class CallManagerPrivate
+{
+public:
+    //ResourceProxy *resource;
+    QHash<QString, CallItem *>  callItems;
+};
+
+CallManager::CallManager(const QString &modemPath, QObject *parent)
+    : OfonoVoiceCallManager(OfonoModem::AutomaticSelect, modemPath, parent),
+      d(new CallManagerPrivate)
+{
+    TRACE;
+
+    // Transform existing calls list, into list of CallItems
+    updateCallItems();
+
+    // Begin tracking calls
+    connect(this, SIGNAL(callAdded(const QString)),
+            this, SLOT(addCall(const QString)));
+    connect(this, SIGNAL(callRemoved(const QString)),
+            this, SLOT(removeCall(const QString)));
+
+    // Hook into parent class signals
+    connect(this, SIGNAL(dialComplete(const bool)),
+            this, SLOT(dialFinished(const bool)));
+    connect(this, SIGNAL(swapCallsComplete(const bool)),
+            this, SLOT(swapFinished(const bool)));
+    connect(this, SIGNAL(hangupAllComplete(const bool)),
+            this, SLOT(hangupAllFinished(const bool)));
+    connect(this, SIGNAL(sendTonesComplete(const bool)),
+            this, SLOT(sendTonesFinished(const bool)));
+    connect(this, SIGNAL(holdAndAnswerComplete(const bool)),
+            this, SLOT(holdAndAnswerFinished(const bool)));
+    connect(this, SIGNAL(transferComplete(const bool)),
+            this, SLOT(transferFinished(const bool)));
+    connect(this, SIGNAL(releaseAndAnswerComplete(const bool)),
+            this, SLOT(releaseAndAnswerFinished(const bool)));
+    connect(this, SIGNAL(privateChatComplete(const bool)),
+            this, SLOT(privateChatFinished(const bool)));
+    connect(this, SIGNAL(createMultipartyComplete(const bool)),
+            this, SLOT(createMultipartyFinished(const bool)));
+    connect(this, SIGNAL(hangupMultipartyComplete(const bool)),
+            this, SLOT(hangupMultipartyFinished(const bool)));
+
+    connect(this,SIGNAL(callsChanged()),this,SLOT(callChangedSlot()));
+
+    connect(this, SIGNAL(validityChanged(bool)), this, SLOT(modemValidityChanged(bool)) );
+
+    if (isValid())
+        emit connected();
+}
+
+CallManager::~CallManager()
+{
+    TRACE;
+    // FIXME: Do something here!!!
+    qDebug() << QString("Destroying VoiceCallManager");
+    qDebug() << QString("Purging all CallItems");
+    foreach (CallItem *item, d->callItems) {
+        disconnect(item, SIGNAL(stateChanged()));
+        disconnect(item, SIGNAL(dataChanged()));
+        delete item;
+    }
+    if (d->callItems.size() > 0)
+        emit callsChanged();
+    d->callItems.clear();
+}
+
+void CallManager::modemValidityChanged(bool valid)
+{
+    TRACE;
+    if (valid)
+       emit connected();
+}
+
+QList<CallItem *> CallManager::getCallItems() const
+{
+    TRACE;
+    return d->callItems.values();
+}
+
+int CallManager::callCount() const
+{
+    TRACE;
+    qDebug()<<"call count is currently = "<<d->callItems.size();
+    return d->callItems.size();
+}
+
+int CallManager::multipartyCallCount() const
+{
+    TRACE;
+    int call_count = 0;
+    foreach (CallItem *c, d->callItems) {
+        if(c->multiparty()) {
+            call_count++;
+        }
+    }
+    return call_count;
+}
+
+CallItem *CallManager::activeCall() const
+{
+    TRACE;
+    if (d->callItems.size())
+        foreach (CallItem *c, d->callItems)
+            if (c->state() == STATE_ACTIVE)
+                return c;
+    return NULL;
+}
+
+CallItem *CallManager::heldCall() const
+{
+    TRACE;
+    if (d->callItems.size())
+        foreach (CallItem *c, d->callItems)
+            if (c->state() == STATE_HELD)
+                return c;
+    return NULL;
+}
+
+CallItem *CallManager::dialingCall() const
+{
+    TRACE;
+    if (d->callItems.size())
+        foreach (CallItem *c, d->callItems)
+            if (c->state() == STATE_DIALING)
+                return c;
+    return NULL;
+}
+
+CallItem *CallManager::incomingCall() const
+{
+    TRACE;
+    if (d->callItems.size())
+        foreach (CallItem *c, d->callItems)
+            if (c->state() == STATE_INCOMING)
+                return c;
+    return NULL;
+}
+
+CallItem *CallManager::waitingCall() const
+{
+    TRACE;
+    if (d->callItems.size())
+        foreach (CallItem *c, d->callItems)
+            if (c->state() == STATE_WAITING)
+                return c;
+    return NULL;
+}
+
+CallItem *CallManager::alertingCall() const
+{
+    TRACE;
+    if (d->callItems.size())
+        foreach (CallItem *c, d->callItems)
+            if (c->state() == STATE_ALERTING)
+                return c;
+    return NULL;
+}
+
+void CallManager::setActiveCall(const CallItem &call)
+{
+    TRACE;
+    swapCalls();
+}
+
+void CallManager::dial(const QString &number)
+{
+    TRACE;
+    // Nothing to do if the modem is not powered up
+
+    if(!modem()->powered()) {
+        emit callsChanged();
+        return;
+    }
+
+    // If not online (flight mode?), check if the requested number is
+    // one of the allowed EmergencyNumbers, in which case, continue.
+    // Otherwise, notify that only Emergency calls are permitted.
+    if(!modem()->online()) {
+        if(modem()->powered() && !emergencyNumbers().contains(number)) {
+            emit callsChanged();
+            emit onlyEmergencyCalls();
+            return;
+        }
+    }
+
+    proceedCallDial(number);
+}
+
+void CallManager::privateChat(const CallItem &call)
+{
+    TRACE;
+}
+
+/*
+ * Resource Policy Manager Handler slots
+ */
+void CallManager::deniedCallDial()
+{
+    TRACE;
+    qCritical() << QString("Denied: Dial resource");
+}
+
+void CallManager::lostCallDial()
+{
+    TRACE;
+    qCritical() << QString("Lost: Dial resource");
+    hangupAll();
+}
+
+void CallManager::proceedCallDial(const QString number)
+{
+    TRACE;
+    OfonoVoiceCallManager::dial(stripLineID(number), QString());
+}
+
+void CallManager::deniedCallAnswer()
+{
+    TRACE;
+    qCritical() << QString("Denied: Call resource");
+    hangupAll();
+}
+
+void CallManager::deniedIncomingCall(CallItem *call)
+{
+    TRACE;
+
+    qCritical() << QString("Denied: Incoming Call resource");
+    qDebug() << QString("Insert new CallItem %1").arg(call->path());
+    emit callsChanged();
+    emit incomingCall(call);
+}
+
+void CallManager::lostIncomingCall(CallItem *call)
+{
+    TRACE;
+    Q_UNUSED(call)
+        qCritical() << QString("Lost: Incoming Call resource");
+}
+
+void CallManager::proceedIncomingCall(CallItem *call)
+{
+    TRACE;
+    qDebug() << QString("Acquired: Incoming Call resource");
+    qDebug() << QString("Insert new CallItem %1").arg(call->path());
+    emit callsChanged();
+    emit incomingCall(call);
+}
+
+/*
+ * Private slots for async replies
+ */
+
+void CallManager::updateCallItems()
+{
+    TRACE;
+    bool changed = false;
+
+    // If ofono call list is empty (no calls), empty our CallItem list too.
+    if (getCalls().isEmpty() && !d->callItems.isEmpty()) {
+        qDebug() << QString("Purging all CallItems");
+        foreach (CallItem *item, d->callItems)
+            delete item;
+        d->callItems.clear();
+        emit callsChanged();
+        return;
+    }
+
+    // Remove CallItems that are not in the ofono "calls" list
+    QMutableHashIterator<QString, CallItem*> iter(d->callItems);
+    while (iter.hasNext()) {
+        CallItem *item = iter.next().value();
+        // This item is not in the ofono list, remove it
+        if (!getCalls().contains(item->path())) {
+            qDebug() << QString("Removing old CallItem %1").arg(item->path());
+            delete item;
+            iter.remove();
+            changed = true;
+        }
+    }
+
+    // Insert new CallItems for paths in the ofono "calls" list we are missing
+    foreach (QString path, getCalls()) {
+        // Insert a new CallItem
+        if (!d->callItems.contains(path)) {
+            qDebug() << QString("Inserting new CallItem %1").arg(path);
+            CallItem *call = new CallItem(path);
+            connect (call, SIGNAL(stateChanged()),
+                     this, SLOT(callStateChanged()));
+            connect (call, SIGNAL(multipartyChanged()),
+                     this, SLOT(callMultipartyChanged()));
+            d->callItems.insert(path, call);
+
+            // NOTE: Must explicity bubble this up since incoming and waiting
+            //       calls do not "changeState" unless they are handled or
+            //       timeout
+            if ((call->state() == STATE_INCOMING) ||
+                (call->state() == STATE_WAITING)) {
+                proceedIncomingCall(call);
+            } else {
+                changed = true;
+            }
+        }
+    }
+
+    if (changed)
+        emit callsChanged();
+}
+
+void CallManager::addCall(const QString &path)
+{
+    TRACE;
+    qDebug() << QString("CallAdded: \"%1\"").arg(path);
+    qDebug() <<"Call number is now "<< callCount();
+    updateCallItems();
+    emit callCountChanged(callCount());
+}
+
+void CallManager::removeCall(const QString &path)
+{
+    TRACE;
+    qDebug() << QString("CallRemoved: \"%1\"").arg(path);
+    qDebug() <<"Call number is now "<< callCount();
+    updateCallItems();
+    emit callCountChanged(callCount());
+}
+
+void CallManager::dialFinished(const bool status)
+{
+    TRACE;
+    qDebug() <<"Call number is now "<< callCount();
+    if (!status) {
+        qCritical() << QString("dial() Failed: %1 - %2")
+            .arg(errorName())
+            .arg(errorMessage());
+        // Fix BMC#10848:
+        // Notify that state of the call has changed when the dialing fails
+        emit callsChanged();
+    }
+}
+
+void CallManager::hangupAllFinished(const bool status)
+{
+    TRACE;
+    if (!status)
+        qCritical() << QString("hangupAll() Failed: %1 - %2")
+            .arg(errorName())
+            .arg(errorMessage());
+
+    //If there are still calls for some reason, delete them.
+    if (callCount() > 0)
+        {
+            foreach (CallItem *item, d->callItems) {
+                disconnect(item, SIGNAL(stateChanged()));
+                disconnect(item, SIGNAL(dataChanged()));
+                delete item;
+            }
+    
+            d->callItems.clear();
+            callCount();
+            emit callsChanged();
+        }
+    callCount();
+}
+
+void CallManager::swapFinished(const bool status)
+{
+    TRACE;
+    if (!status)
+        qCritical() << QString("swapCalls() Failed: %1 - %2")
+            .arg(errorName())
+            .arg(errorMessage());
+}
+
+void CallManager::holdAndAnswerFinished(const bool status)
+{
+    TRACE;
+    if (!status)
+        qCritical() << QString("HoldAndAnswer() Failed: %1 - %2")
+            .arg(errorName())
+            .arg(errorMessage());
+}
+
+void CallManager::transferFinished(const bool status)
+{
+    TRACE;
+    if (!status)
+        qCritical() << QString("Transfer() Failed: %1 - %2")
+            .arg(errorName())
+            .arg(errorMessage());
+}
+
+void CallManager::releaseAndAnswerFinished(const bool status)
+{
+    TRACE;
+    if (!status)
+        qCritical() << QString("ReleaseAndAnswer() Failed: %1 - %2")
+            .arg(errorName())
+            .arg(errorMessage());
+}
+
+void CallManager::privateChatFinished(const bool status)
+{
+    TRACE;
+    if (!status)
+        qCritical() << QString("PrivateChat() Failed: %1 - %2")
+            .arg(errorName())
+            .arg(errorMessage());
+}
+
+void CallManager::createMultipartyFinished(const bool status)
+{
+    TRACE;
+    if (!status)
+        qCritical() << QString("CreateMultiparty() Failed: %1 - %2")
+            .arg(errorName())
+            .arg(errorMessage());
+}
+
+void CallManager::hangupMultipartyFinished(const bool status)
+{
+    TRACE;
+    if (!status)
+        qCritical() << QString("HangupMultiparty() Failed: %1 - %2")
+            .arg(errorName())
+            .arg(errorMessage());
+}
+
+void CallManager::sendTonesFinished(const bool status)
+{
+    TRACE;
+    if (!status)
+        qCritical() << QString("SendTones() Failed: %1 - %2")
+            .arg(errorName())
+            .arg(errorMessage());
+}
+
+void CallManager::callStateChanged()
+{
+    CallItem *call = dynamic_cast<CallItem *>(sender());
+    qDebug() << QString("%1 (%2) state has changed to %3")
+        .arg(call->path())
+        .arg(call->lineID())
+        .arg(call->state());
+    qDebug() << "number of calls "<< callCount();
+    emit callsChanged();
+}
+
+void CallManager::callMultipartyChanged()
+{
+    TRACE;
+    emit callsChanged();
+    emit multipartyCallCountChanged(multipartyCallCount());
+}
+
+void CallManager::callChangedSlot()
+{
+    TRACE
+    qDebug()<<"callChanged called!";
+}
+
+/* Local Variables:      */
+/* mode:c++              */
+/* c-basic-offset:4      */
+/* indent-tabs-mode: nil */
+/* End:                  */
diff --git a/src/callmanager.h b/src/callmanager.h
new file mode 100644 (file)
index 0000000..5ec3362
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * hfdialer - Hands Free Voice Call Manager
+ * Copyright (c) 2012, Intel Corporation.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0.  The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ */
+
+#ifndef CALLMANAGER_H
+#define CALLMANAGER_H
+
+#include <ofonovoicecallmanager.h>
+
+#include "callitem.h"
+#include <QtDBus>
+
+class CallManager: public OfonoVoiceCallManager
+{
+    Q_OBJECT;
+
+    Q_PROPERTY(int multipartyCallCount READ multipartyCallCount NOTIFY multipartyCallCountChanged);
+    Q_PROPERTY(int callCount READ callCount NOTIFY callCountChanged);
+
+public:
+    explicit CallManager(const QString &modemPath="", QObject *parent=0);
+    virtual ~CallManager();
+
+    /* Properties */
+    int multipartyCallCount() const;
+    int callCount() const;
+
+    // Extended version of OfonoVoiceCallManager::getCalls() that
+    // returns QList of CallItems rather than strings
+    Q_INVOKABLE QList<CallItem *> getCallItems() const;
+
+    Q_INVOKABLE CallItem *activeCall() const;
+    Q_INVOKABLE CallItem *heldCall() const;
+    Q_INVOKABLE CallItem *dialingCall() const;
+    Q_INVOKABLE CallItem *incomingCall() const;
+    Q_INVOKABLE CallItem *waitingCall() const;
+    Q_INVOKABLE CallItem *alertingCall() const;
+
+public Q_SLOTS:
+    void setActiveCall(const CallItem &call);
+
+    // Overloaded version of OfonoVoiceCallManager::dial() that
+    // assumes CLIR == default
+    void dial(const QString &number);
+
+    // Overloaded version of OfonoVoiceCallManager::privateChat() that
+    // takes a CallItem rather than path string
+    void privateChat(const CallItem &call);
+
+    // Push denied answer signal to upper layers from call proxy
+    void deniedCallAnswer();
+
+Q_SIGNALS:
+    // Abstracts both callAdded() and callRemoved() into a single event
+    void callsChanged();
+
+    void incomingCall(CallItem *call);
+    void incomingCall(QString path);
+    void callDisconnected(const CallItem &call);
+    void onlyEmergencyCalls();
+    void connected();
+    void multipartyCallCountChanged(const int &count);
+    void callCountChanged(const int &count);
+
+private Q_SLOTS:
+    void callChangedSlot();
+    void updateCallItems();
+    void addCall(const QString &path);
+    void removeCall(const QString &path);
+    void dialFinished(const bool status);
+    void hangupAllFinished(const bool status);
+    void swapFinished(const bool status);
+    void holdAndAnswerFinished(const bool status);
+    void transferFinished(const bool status);
+    void releaseAndAnswerFinished(const bool status);
+    void privateChatFinished(const bool status);
+    void createMultipartyFinished(const bool status);
+    void hangupMultipartyFinished(const bool status);
+    void sendTonesFinished(const bool status);
+    void callStateChanged();
+    void callMultipartyChanged();
+    void modemValidityChanged(bool valid);
+
+    // Handlers for Resource Policy Manager states and conditions
+    void proceedCallDial(const QString number);
+    void deniedCallDial();
+    void lostCallDial();
+    void proceedIncomingCall(CallItem *call);
+    void deniedIncomingCall(CallItem *call);
+    void lostIncomingCall(CallItem *call);
+
+private:
+    class CallManagerPrivate *d;
+
+    Q_DISABLE_COPY(CallManager);
+};
+
+#endif // CALLMANAGER_H
+
+/* Local Variables:      */
+/* mode:c++              */
+/* c-basic-offset:4      */
+/* indent-tabs-mode: nil */
+/* End:                  */
diff --git a/src/callproxy.cpp b/src/callproxy.cpp
new file mode 100644 (file)
index 0000000..272de57
--- /dev/null
@@ -0,0 +1,327 @@
+/*
+ * hfdialer - Hands Free Voice Call Manager
+ * Copyright (c) 2012, Intel Corporation.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0.  The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ */
+
+#include <QDateTime>
+#include "common.h"
+#include "callproxy.h"
+#include "managerproxy.h"
+
+// Returns a valid QDateTime if parsable as such, otherwise the result
+// will be !isValid()
+static QDateTime qDateTimeFromOfono(const QString &val)
+{
+    TRACE;
+    QDateTime result;
+
+    if (val.isEmpty())
+        return result;
+
+    // NOTE: Ofono formats time to string with the following format spec:
+    //       %Y-%m-%dT%H:%M:%S%z (for example: "2001-10-19T10:32:30-05:00")
+
+    // Start by trying to parse this as an ISODate "YYYY-MM-DDTHH:MM:SSTZD"
+    result = QDateTime::fromString(val,Qt::ISODate);
+#ifdef VERBOSE
+    qDebug() << QString("Converted %1 with Qt::ISODate: %2")
+        .arg(val)
+        .arg(result.toString());
+#endif
+
+    if (!result.isValid()) {
+        // ISODate conversion has failed, fallback to manual method
+        // NOTE: QDateTime::fromString(val, Qt::ISODate) Fails since the date
+        //       format from Ofono is in RFC 822 form, but QDateTime can't parse it
+        struct tm time_tm;
+        QByteArray  bytes = val.toAscii();
+        const char *str = bytes.constData();
+        if (strptime(str, "%Y-%m-%dT%H:%M:%S%z", &time_tm) != NULL) {
+            time_t t = mktime(&time_tm);
+            if (t >= (time_t)(0)) {
+                result.setTime_t(t);
+#ifdef VERBOSE 
+                qDebug() << QString("Converted %1 with strptime: %2")
+                    .arg(val)
+                    .arg(result.toString());
+#endif
+            }
+        }
+
+        if (!result.isValid())
+            qCritical() << QString("Format error, unknown date/time: %1")
+                .arg(str);
+    }
+
+    return result;
+}
+
+CallProxy::CallProxy(const QString &callPath)
+    : org::ofono::VoiceCall(OFONO_SERVICE,
+                            callPath,
+                            QDBusConnection::systemBus()),
+      m_lineid(QString()),
+      m_state(QString()),
+      m_startTime(QDateTime()),
+      m_reason(QString()),
+      m_connected(false),
+      m_multiparty(false)
+{
+    TRACE;
+
+    if (!org::ofono::VoiceCall::isValid()) {
+        qCritical() << QString("Failed to connect to %1 for call %2:\n\t%3")
+            .arg(staticInterfaceName())
+            .arg(callPath)
+            .arg(lastError().message());
+    } else {
+        QDBusPendingReply<QVariantMap> reply;
+        QDBusPendingCallWatcher *watcher;
+
+        reply = GetProperties();
+        watcher = new QDBusPendingCallWatcher(reply);
+
+        // Force this to be sync to ensure we have initial properties
+        watcher->waitForFinished();
+        getPropertiesFinished(watcher);
+
+        if (isValid()) {
+            connect(this,
+                    SIGNAL(PropertyChanged(const QString&,const QDBusVariant&)),
+                    SLOT(propertyChanged(const QString&,const QDBusVariant&)));
+            connect(this, SIGNAL(DisconnectReason(const QString&)),
+                    SLOT(disconnectReason(const QString&)));
+        } else {
+            qCritical() << QString("Invalid CallProxy instance: state == %1")
+                .arg(m_state);
+        }
+    }
+}
+
+CallProxy::~CallProxy()
+{
+    TRACE;
+    // FIXME: Do something here!!!
+}
+
+bool CallProxy::isValid()
+{
+    TRACE;
+    return (org::ofono::VoiceCall::isValid() &&
+            m_connected &&
+            (m_state != "disconnected"));
+}
+
+QString CallProxy::lineID() const
+{
+    TRACE;
+    return m_lineid;
+}
+
+QString CallProxy::name() const
+{
+    TRACE;
+    return m_name;
+}
+
+QString CallProxy::state() const
+{
+    TRACE;
+    return m_state;
+}
+
+QDateTime CallProxy::startTime() const
+{
+    TRACE;
+    return m_startTime;
+}
+
+int CallProxy::duration() const
+{
+    TRACE;
+    if (m_startTime.isValid())
+        return m_startTime.secsTo(QDateTime::currentDateTime());
+    else
+        return 0;
+}
+
+QString CallProxy::reason() const
+{
+    TRACE;
+    return m_reason;
+}
+
+bool CallProxy::multiparty() const
+{
+    TRACE;
+    return m_multiparty;
+}
+
+void CallProxy::answer()
+{
+    TRACE;
+    proceedCallAnswer();
+}
+
+void CallProxy::proceedCallAnswer()
+{
+    TRACE;
+
+    QDBusPendingReply<QDBusObjectPath> reply;
+    QDBusPendingCallWatcher *watcher;
+
+    reply = Answer();
+    watcher = new QDBusPendingCallWatcher(reply);
+
+    connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
+            SLOT(answerFinished(QDBusPendingCallWatcher*)));
+}
+
+void CallProxy::deniedCallAnswer()
+{
+    TRACE;
+
+    // Hang up the incoming call, if resources to accept it are inavailabe
+    hangup();
+
+    emit ManagerProxy::instance()->callManager()->deniedCallAnswer();
+}
+
+void CallProxy::deflect(const QString toNumber)
+{
+    TRACE;
+
+    QDBusPendingReply<QDBusObjectPath> reply;
+    QDBusPendingCallWatcher *watcher;
+
+    reply = Deflect(toNumber);
+    watcher = new QDBusPendingCallWatcher(reply);
+
+    connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
+            SLOT(deflectFinished(QDBusPendingCallWatcher*)));
+}
+
+void CallProxy::hangup()
+{
+    TRACE;
+
+    QDBusPendingReply<> reply;
+    QDBusPendingCallWatcher *watcher;
+
+    reply = Hangup();
+    watcher = new QDBusPendingCallWatcher(reply);
+
+    connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
+            SLOT(hangupFinished(QDBusPendingCallWatcher*)));
+}
+
+void CallProxy::getPropertiesFinished(QDBusPendingCallWatcher *watcher)
+{
+    TRACE;
+
+    QDBusPendingReply<QVariantMap> reply = *watcher;
+
+    if (reply.isError()) {
+        qCritical() << QString("Failed to connect to %1 for call %2:\n\t%3")
+            .arg(staticInterfaceName())
+            .arg(path())
+            .arg(lastError().message());
+        return;
+    }
+
+    QVariantMap props = reply.value();
+
+    QString l_start;
+
+    m_lineid = qdbus_cast<QString>(props["LineIdentification"]);
+    m_name   = qdbus_cast<QString>(props["Name"]);
+    m_state  = qdbus_cast<QString>(props["State"]);
+    l_start  = qdbus_cast<QString>(props["StartTime"]);
+    m_multiparty  = qdbus_cast<bool>(props["Multiparty"]);
+
+    setStartTimeFromString(l_start);
+
+    // Indicate for this instance, that we've actually performed at least
+    // one round trip call to this VoiceCall and we are in sync with it
+    m_connected = true;
+}
+
+void CallProxy::answerFinished(QDBusPendingCallWatcher *watcher)
+{
+    TRACE;
+    QDBusPendingReply<QDBusObjectPath> reply = *watcher;
+    if (reply.isError())
+        qCritical() << QString("Answer() Failed: %1 - %2")
+            .arg(reply.error().name())
+            .arg(reply.error().message());
+}
+
+void CallProxy::deflectFinished(QDBusPendingCallWatcher *watcher)
+{
+    TRACE;
+    QDBusPendingReply<QDBusObjectPath> reply = *watcher;
+    if (reply.isError())
+        qCritical() << QString("Deflect() Failed: %1 - %2")
+            .arg(reply.error().name())
+            .arg(reply.error().message());
+}
+
+void CallProxy::hangupFinished(QDBusPendingCallWatcher *watcher)
+{
+    TRACE;
+    QDBusPendingReply<> reply = *watcher;
+    if (reply.isError())
+        qCritical() << QString("Hangup() Failed: %1 - %2")
+            .arg(reply.error().name())
+            .arg(reply.error().message());
+}
+
+void CallProxy::propertyChanged(const QString &in0, const QDBusVariant &in1)
+{
+    TRACE;
+
+    if (in0 == "LineIdentification") {
+        m_lineid = qdbus_cast<QString>(in1.variant());
+        emit dataChanged();
+    } else if (in0 == "State") {
+        m_state  = qdbus_cast<QString>(in1.variant());
+        emit stateChanged();
+    } else if (in0 == "StartTime") {
+        setStartTimeFromString(qdbus_cast<QString>(in1.variant()));
+    } else if (in0 == "Multiparty") {
+        m_multiparty = qdbus_cast<bool>(in1.variant());
+        emit multipartyChanged();
+    } else {
+        qDebug() << QString("Unexpected property \"%1\" changed...").arg(in0);
+    }
+}
+
+void CallProxy::disconnectReason(const QString &in0)
+{
+    TRACE;
+    m_reason = in0;
+    emit callDisconnected(in0);
+}
+
+void CallProxy::setStartTimeFromString(const QString &val)
+{
+    TRACE;
+    if (val.isEmpty())
+        return;
+
+    m_startTime = qDateTimeFromOfono(val);
+
+    if (!m_startTime.isValid())
+        m_startTime = QDateTime::QDateTime::currentDateTime();
+}
+
+/* Local Variables:      */
+/* mode:c++              */
+/* c-basic-offset:4      */
+/* indent-tabs-mode: nil */
+/* End:                  */
diff --git a/src/callproxy.h b/src/callproxy.h
new file mode 100644 (file)
index 0000000..492e7bb
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * hfdialer - Hands Free Voice Call Manager
+ * Copyright (c) 2012, Intel Corporation.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0.  The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ */
+
+#ifndef CALLPROXY_H
+#define CALLPROXY_H
+
+#include "voicecall_interface.h"
+#include <QtDBus>
+#include <QDebug>
+
+#define OFONO_SERVICE "org.ofono"
+#define OFONO_MANAGER_PATH "/"
+
+#define DEFAULT_CLIR "default"
+
+class CallProxy: public org::ofono::VoiceCall
+{
+    Q_OBJECT;
+
+    Q_PROPERTY(QString   lineID READ lineID);
+    Q_PROPERTY(QString   name READ name);
+    Q_PROPERTY(QString   state READ state);
+    Q_PROPERTY(QDateTime startTime READ startTime);
+    Q_PROPERTY(int       duration READ duration);
+    Q_PROPERTY(QString   reason READ reason);
+    Q_PROPERTY(bool      multiparty READ multiparty);
+
+public:
+    CallProxy(const QString &callPath);
+    virtual ~CallProxy();
+    bool isValid();
+
+    QString lineID() const;
+    QString name() const;
+    QString state() const;
+    QDateTime startTime() const;
+    int duration() const;
+    QString reason() const;
+    bool multiparty() const;
+
+public Q_SLOTS:
+    // Answers the incoming call
+    // NOTE: only valid if state is incoming
+    void answer();
+
+    // Deflects the incoming or waiting call to number provided.
+    // NOTE: only valid if state is incoming or waiting
+    void deflect(const QString toNumber);
+
+    // Hangs up the voice call
+    void hangup();
+
+Q_SIGNALS:
+    void callDisconnected(const QString &reason);
+    void stateChanged();
+    void dataChanged();
+    void multipartyChanged();
+
+private Q_SLOTS:
+    // Slots to handle asyncronous DBus replies
+    void getPropertiesFinished(QDBusPendingCallWatcher *watcher);
+    void answerFinished(QDBusPendingCallWatcher *watcher);
+    void deflectFinished(QDBusPendingCallWatcher *watcher);
+    void hangupFinished(QDBusPendingCallWatcher *watcher);
+
+    // Slots to handle DBus signals from ofono
+    void propertyChanged(const QString &in0, const QDBusVariant &in1);
+    void disconnectReason(const QString &in0);
+
+    void proceedCallAnswer();
+    void deniedCallAnswer();
+
+private:
+    void setStartTimeFromString(const QString &val);
+
+private:
+    QStringList        m_properties;
+    QString            m_lineid;
+    QString            m_name;
+    QString            m_state;
+    QDateTime          m_startTime;
+    QString            m_reason;
+    bool               m_connected;
+    bool               m_multiparty;
+
+    Q_DISABLE_COPY(CallProxy);
+};
+
+#endif // CALLPROXY_H
+
+/* Local Variables:      */
+/* mode:c++              */
+/* c-basic-offset:4      */
+/* indent-tabs-mode: nil */
+/* End:                  */
diff --git a/src/common.h b/src/common.h
new file mode 100644 (file)
index 0000000..453640d
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * hfdialer - Hands Free Voice Call Manager
+ * Copyright (c) 2012, Intel Corporation.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0.  The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ */
+
+#ifndef COMMON_H
+#define COMMON_H
+
+class QString;
+
+#ifdef VERBOSE 
+#include <QDebug>
+#define TRACE qDebug() << "[" << __FILE__ << "]" << __func__ << "():" << __LINE__;
+#else
+#define TRACE
+#endif
+
+QString stripLineID(QString lineid);
+
+#endif // COMMON_H
+
+/* Local Variables:      */
+/* mode:c++              */
+/* c-basic-offset:4      */
+/* indent-tabs-mode: nil */
+/* End:                  */
diff --git a/src/dbus/com.hfdialer.xml b/src/dbus/com.hfdialer.xml
new file mode 100644 (file)
index 0000000..e78a08e
--- /dev/null
@@ -0,0 +1,11 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node>
+       <interface name="com.hfdialer" >
+               <method name="call" >
+                       <arg direction="in" type="s" name="" />
+               </method>
+               <method name="accept"/>
+               <method name="raise"/>
+       </interface>
+</node>
diff --git a/src/dbus/org.ofono.history.xml b/src/dbus/org.ofono.history.xml
new file mode 100644 (file)
index 0000000..f495399
--- /dev/null
@@ -0,0 +1,14 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node name="">
+       <interface name="org.ofono.CallHistory">
+               <method name="GetVoiceHistory">
+                       <arg type="a(usqii)" direction="out"/>
+                       <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="QArrayOfHistoryEvent"/>
+               </method>
+               <method name="SetVoiceHistoryRead"/>
+               <signal name="VoiceHistoryChanged">
+                       <arg type="u"/>
+               </signal>
+       </interface>
+</node>
diff --git a/src/dbus/org.ofono.manager.xml b/src/dbus/org.ofono.manager.xml
new file mode 100644 (file)
index 0000000..dd11568
--- /dev/null
@@ -0,0 +1,18 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node name="">
+       <interface name="org.ofono.Manager">
+               <method name="GetModems">
+                       <arg type="a(oa{sv})" direction="out"/>
+                       <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="QArrayOfPathProperties"/>
+               </method>
+               <signal name="ModemAdded">
+                       <arg type="o"/>
+                       <arg type="a{sv}"/>
+                       <annotation name="com.trolltech.QtDBus.QtTypeName.In1" value="QVariantMap"/>
+               </signal>
+               <signal name="ModemRemoved">
+                       <arg type="o"/>
+               </signal>
+       </interface>
+</node>
diff --git a/src/dbus/org.ofono.modem.xml b/src/dbus/org.ofono.modem.xml
new file mode 100644 (file)
index 0000000..fee9d0c
--- /dev/null
@@ -0,0 +1,66 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node name="">
+       <interface name="org.ofono.Modem">
+               <method name="GetProperties">
+                       <arg type="a{sv}" direction="out"/>
+                       <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
+               </method>
+               <method name="SetProperty">
+                       <arg type="s" direction="in"/>
+                       <arg type="v" direction="in"/>
+               </method>
+               <signal name="PropertyChanged">
+                       <arg type="s"/>
+                       <arg type="v"/>
+               </signal>
+       </interface>
+       <interface name="org.ofono.MessageWaiting">
+               <method name="GetProperties">
+                       <arg type="a{sv}" direction="out"/>
+                       <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
+               </method>
+               <method name="SetProperty">
+                       <arg type="s" direction="in"/>
+                       <arg type="v" direction="in"/>
+               </method>
+               <signal name="PropertyChanged">
+                       <arg type="s"/>
+                       <arg type="v"/>
+               </signal>
+       </interface>
+       <interface name="org.ofono.CallVolume">
+               <method name="GetProperties">
+                       <arg type="a{sv}" direction="out"/>
+                       <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
+               </method>
+               <method name="SetProperty">
+                       <arg type="s" direction="in"/>
+                       <arg type="v" direction="in"/>
+               </method>
+               <signal name="PropertyChanged">
+                       <arg type="s"/>
+                       <arg type="v"/>
+               </signal>
+       </interface>
+       <interface name="org.ofono.NetworkRegistration">
+               <method name="GetProperties">
+                       <arg type="a{sv}" direction="out"/>
+                       <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
+               </method>
+               <method name="Register"/>
+               <method name="Deregister"/>
+               <method name="GetOperators">
+                       <arg type="a(oa{sv})" direction="out"/>
+                       <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="QArrayOfPathProperties"/>
+               </method>
+               <method name="Scan">
+                       <arg type="a(oa{sv})" direction="out"/>
+                       <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="QArrayOfPathProperties"/>
+               </method>
+               <signal name="PropertyChanged">
+                       <arg type="s"/>
+                       <arg type="v"/>
+               </signal>
+       </interface>
+</node>
diff --git a/src/dbus/org.ofono.operator.xml b/src/dbus/org.ofono.operator.xml
new file mode 100644 (file)
index 0000000..f8ff35e
--- /dev/null
@@ -0,0 +1,16 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node name="">
+       <interface name="org.ofono.NetworkOperator">
+               <method name="GetProperties">
+                       <arg type="a{sv}" direction="out"/>
+                       <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
+
+               </method>
+               <method name="Register"/>
+               <signal name="PropertyChanged">
+                       <arg type="s"/>
+                       <arg type="v"/>
+               </signal>
+       </interface>
+</node>
diff --git a/src/dbus/org.ofono.voicecall.xml b/src/dbus/org.ofono.voicecall.xml
new file mode 100644 (file)
index 0000000..7b1c710
--- /dev/null
@@ -0,0 +1,22 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node name="">
+       <interface name="org.ofono.VoiceCall">
+               <method name="GetProperties">
+                       <arg type="a{sv}" direction="out"/>
+                       <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
+               </method>
+               <method name="Deflect">
+                       <arg type="s" direction="in"/>
+               </method>
+               <method name="Hangup"/>
+               <method name="Answer"/>
+               <signal name="PropertyChanged">
+                       <arg type="s"/>
+                       <arg type="v"/>
+               </signal>
+               <signal name="DisconnectReason">
+                       <arg type="s"/>
+               </signal>
+       </interface>
+</node>
diff --git a/src/dbusdialeradapter.cpp b/src/dbusdialeradapter.cpp
new file mode 100644 (file)
index 0000000..7868615
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2011, Tom Swindell.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0.  The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ */
+
+#include "common.h"
+#include "dbusdialeradapter.h"
+#include "managerproxy.h"
+
+DBusDialerAdapter::DBusDialerAdapter(DialerApplication *application)
+    : QDBusAbstractAdaptor(application)
+{
+    TRACE;
+}
+
+DBusDialerAdapter::~DBusDialerAdapter()
+{
+    TRACE;
+}
+
+void DBusDialerAdapter::call(const QString &msisdn)
+{
+    TRACE;
+
+    if(!ManagerProxy::instance()->callManager()) return;
+    ManagerProxy::instance()->callManager()->dial(msisdn);
+}
+
+/* Local Variables:      */
+/* mode:c++              */
+/* c-basic-offset:4      */
+/* indent-tabs-mode: nil */
+/* End:                  */
diff --git a/src/dbusdialeradapter.h b/src/dbusdialeradapter.h
new file mode 100644 (file)
index 0000000..8c851e4
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2011, Tom Swindell.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0.  The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ */
+#ifndef DBUSDIALERADAPTER_H
+#define DBUSDIALERADAPTER_H
+
+#include "dialerapplication.h"
+#include <QDBusAbstractAdaptor>
+
+class DBusDialerAdapter : public QDBusAbstractAdaptor
+{
+    Q_OBJECT;
+    Q_CLASSINFO("D-Bus Interface", "com.hfdialer");
+
+public:
+    explicit DBusDialerAdapter(DialerApplication *application);
+    ~DBusDialerAdapter();
+
+Q_SIGNALS:
+
+public Q_SLOTS:
+    void call(const QString &msisdn);
+};
+
+#endif // DBUSDIALERADAPTER_H
+
+/* Local Variables:      */
+/* mode:c++              */
+/* c-basic-offset:4      */
+/* indent-tabs-mode: nil */
+/* End:                  */
diff --git a/src/dbustypes.cpp b/src/dbustypes.cpp
new file mode 100644 (file)
index 0000000..49808ec
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * hfdialer - Hands Free Voice Call Manager
+ * Copyright (c) 2012, Intel Corporation.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0.  The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ */
+
+#include "dbustypes.h"
+
+// Marshall the CallHistoryEvent data into a D-BUS argument
+QDBusArgument & operator << (QDBusArgument &argument,
+                             const CallHistoryEvent &d)
+{
+    argument.beginStructure();
+    argument << d.id << d.lineid << d.type << d.start << d.end;
+    argument.endStructure();
+    return argument;
+}
+
+// Retrieve the CallHistoryEvent data from the D-BUS argument
+const QDBusArgument & operator >> (const QDBusArgument &argument,
+                                   CallHistoryEvent &d)
+{
+    argument.beginStructure();
+    argument >> d.id >> d.lineid >> d.type >> d.start >> d.end;
+    argument.endStructure();
+    return argument;
+}
+
+// Marshall the OfonoPathProperties data into a D-BUS argument
+QDBusArgument & operator << (QDBusArgument &argument,
+                             const OfonoPathProperties &d)
+{
+    argument.beginStructure();
+    argument << d.path << d.properties;
+    argument.endStructure();
+    return argument;
+}
+
+// Retrieve the OfonoPathProperties data from the D-BUS argument
+const QDBusArgument & operator >> (const QDBusArgument &argument,
+                                   OfonoPathProperties &d)
+{
+    argument.beginStructure();
+    argument >> d.path >> d.properties;
+    argument.endStructure();
+    return argument;
+}
+
+/* Local Variables:      */
+/* mode:c++              */
+/* c-basic-offset:4      */
+/* indent-tabs-mode: nil */
+/* End:                  */
diff --git a/src/dbustypes.h b/src/dbustypes.h
new file mode 100644 (file)
index 0000000..6569a66
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * hfdialer - Hands Free Voice Call Manager
+ * Copyright (c) 2012, Intel Corporation.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0.  The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ */
+
+#ifndef DIALERDBUSTYPES_H
+#define DIALERDBUSTYPES_H
+
+#include <QtCore/QList>
+#include <QtCore/QMetaType>
+#include <QtDBus/QtDBus>
+
+struct CallHistoryEvent
+{
+    uint    id;
+    QString lineid;
+    ushort  type;
+    int     start;
+    int     end;
+};
+
+Q_DECLARE_METATYPE ( CallHistoryEvent )
+
+// Marshall the CallHistoryEvent data into a D-BUS argument
+QDBusArgument &operator<<(QDBusArgument &argument,
+                          const CallHistoryEvent &mystruct);
+
+// Retrieve the CallHistoryEvent data from the D-BUS argument
+const QDBusArgument &operator>>(const QDBusArgument &argument,
+                                CallHistoryEvent &mystruct);
+
+typedef QList< CallHistoryEvent > QArrayOfHistoryEvent;
+
+Q_DECLARE_METATYPE ( QArrayOfHistoryEvent )
+
+/*
+ * New DBus type needed for Ofono calls that expect an array of
+ * Object paths and that objects properties: "a(oa{sv})"
+ *
+ * Used in:
+ *     org.ofono.VoiceCallManager.GetCalls()
+ *     org.ofono.NetworkRegistraion.GetOperators()
+ *     org.ofono.NetworkRegistration.Scan()
+ *     org.ofono.ConnectionManager.GetContexts()
+ *     org.ofono.MessageManager.GetMessages()
+ */
+struct OfonoPathProperties
+{
+    QDBusObjectPath path;
+    QVariantMap     properties;
+};
+
+Q_DECLARE_METATYPE ( OfonoPathProperties )
+
+// Marshall the OfonoPathProperties data into a D-BUS argument
+QDBusArgument &operator<<(QDBusArgument &argument,
+                          const OfonoPathProperties &mystruct);
+
+// Retrieve the CallHistoryEvent data from the D-BUS argument
+const QDBusArgument &operator>>(const QDBusArgument &argument,
+                                OfonoPathProperties &mystruct);
+
+typedef QList< OfonoPathProperties > QArrayOfPathProperties;
+
+Q_DECLARE_METATYPE ( QArrayOfPathProperties )
+
+inline void registerMyDataTypes() {
+    qDBusRegisterMetaType< OfonoPathProperties >();
+    qDBusRegisterMetaType< QArrayOfPathProperties >();
+    qDBusRegisterMetaType< CallHistoryEvent >();
+    qDBusRegisterMetaType< QArrayOfHistoryEvent >();
+}
+
+#endif   //DIALERDBUSTYPES_H
+
+/* Local Variables:      */
+/* mode:c++              */
+/* c-basic-offset:4      */
+/* indent-tabs-mode: nil */
+/* End:                  */
diff --git a/src/dialerapplication.cpp b/src/dialerapplication.cpp
new file mode 100644 (file)
index 0000000..98d6793
--- /dev/null
@@ -0,0 +1,299 @@
+/*
+ * hfdialer - Hands Free Voice Call Manager
+ * Copyright (c) 2012, Intel Corporation.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0.  The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ */
+
+#include "common.h"
+#include "dbustypes.h"
+#include "dialerapplication.h"
+#include "dialercontext.h"
+#include "dbusdialeradapter.h"
+#include "hfdialer_adaptor.h"
+#include "pacontrol.h"
+#include "qmlmainwindow.h"
+#include <QtGui>
+#include <QDebug>
+#include <QApplication>
+
+#define OFONO_VOICECALLMANAGER_INTERFACE "org.ofono.VoiceCallManager"
+
+DialerApplication::DialerApplication(int &argc, char **argv)
+    : QApplication(argc, argv)
+{
+    TRACE;
+    init();
+}
+
+void DialerApplication::releasePrestart()
+{
+    TRACE;
+    // Now is the time for set up and display of information
+    // that needs to be done to allow the dialeror other
+    // pages to display correctly when opened. GenericPage has a
+    // activateWidgets() method for common setup and
+    // each Page type (dialer, people, favorites, etc) can also
+    // implement the method for Page specific setup and signal
+    // and slot connections
+
+    
+}
+
+void DialerApplication::restorePrestart()
+{
+    TRACE;
+    // Now is the time for clean up and resetting an information
+    // that needs to be done to allow the dialer pages to display
+    // correctly when reopened. GenericPage has a
+    // deactivateAndResetWidgets() method for common setup and
+    // each Page type (dialer, people, favorites, etc) can also
+    // implement the method for Page specific clean up
+
+    // Call the default implementation to hide the window.
+}
+
+void DialerApplication::connectAll()
+{
+    TRACE;
+
+    ManagerProxy *m_manager = ManagerProxy::instance();
+    if (m_manager->modem() &&
+        m_manager->modem()->isValid() &&
+        !m_manager->modem()->path().isEmpty())
+        {
+            qDebug() << QString("Connecting to CallManager....");
+            m_manager->setNetwork(m_manager->modem()->path());
+            m_manager->setCallManager(m_manager->modem()->path());
+            m_manager->setVolumeManager(m_manager->modem()->path());
+            m_manager->setVoicemail(m_manager->modem()->path());
+
+            connect(m_manager->network(), SIGNAL(connected()), this,
+                    SLOT(networkConnected()));
+            connect(m_manager->network(), SIGNAL(disconnected()), this,
+                    SLOT(networkDisconnected()));
+            connect(m_manager->callManager(), SIGNAL(connected()), this,
+                    SLOT(callManagerConnected()));
+            connect(m_manager->callManager(), SIGNAL(disconnected()), this,
+                    SLOT(callManagerDisconnected()));
+            connect(m_manager->callManager(), SIGNAL(callsChanged()), this,
+                    SLOT(onCallsChanged()));
+            connect(m_manager->voicemail(), SIGNAL(messagesWaitingChanged()), this,
+                    SLOT(messagesWaitingChanged()));
+            PAControl* paControl = PAControl::instance();
+            qDebug()<<"UBER DEBUG!!!  I can has connect with paControl onCallsChanged";
+            connect(m_manager->callManager(), SIGNAL(callsChanged()), paControl,
+                    SLOT(onCallsChanged()));
+        }
+}
+
+bool DialerApplication::isConnected()
+{
+    TRACE;
+    return m_connected;
+}
+
+bool DialerApplication::hasError() const
+{
+    TRACE;
+    return !m_lastError.isEmpty();
+}
+
+QString DialerApplication::lastError() const
+{
+    TRACE;
+    return m_lastError;
+}
+
+void DialerApplication::setError(const QString msg)
+{
+    TRACE;
+    m_lastError.clear();
+    m_lastError = QString(msg);
+}
+
+DialerApplication *DialerApplication::instance()
+{
+    TRACE;
+    return qobject_cast<DialerApplication *>(QApplication::instance());
+}
+
+void DialerApplication::init()
+{
+    TRACE;
+    m_connected = false;
+    m_lastError = QString();
+
+    // Notify Qt of our custom DBus MetaTypes
+    registerMyDataTypes();
+
+    m_manager = ManagerProxy::instance();
+    if (!m_manager || !m_manager->isValid())
+        //% "Failed to connect to org.ofono.Manager: is ofonod running?"
+        setError(qtTrId("xx_no_ofono_error"));
+    else
+        m_connected = true;
+
+    HfdialerAdaptor *adapter = new HfdialerAdaptor(this);
+    if(!adapter)
+    {
+        qWarning() << "DBus adapter instantiation failed.";
+    }
+
+    if(!QDBusConnection::systemBus().registerService("com.hfdialer"))
+    {
+        qCritical() << "Error registering on zee bus: " <<
+                       QDBusConnection::systemBus().lastError().message();
+    }
+
+    if(!QDBusConnection::systemBus().registerObject(DBUS_SERVICE_PATH, this))
+        {
+            qCritical() << "Error registering dbus object:" <<
+                QDBusConnection::systemBus().lastError().message();
+        }
+    connect(m_manager, SIGNAL(modemChanged()),
+            SLOT(modemChanged()));
+
+   this->connectAll();
+
+   m_mainWindow = QMLMainWindow::instance();
+   connect(m_mainWindow, SIGNAL(closeWindow()),this, SLOT(closeWindow()));
+}
+
+void DialerApplication::modemChanged()
+{
+    TRACE;
+    if (m_manager->modem() != NULL)
+        {
+            connect(m_manager->modem(), SIGNAL(connected()),
+                    SLOT(modemConnected()));
+            connect(m_manager->modem(), SIGNAL(disconnected()),
+                    SLOT(modemDisconnected()));
+    }
+    else
+    {
+        qDebug()<<"modem is null";
+    }
+}
+
+void DialerApplication::modemConnected()
+{
+    TRACE;
+    //TODO: Handle multiple modems
+    if (m_manager->modem() && m_manager->modem()->isValid())
+        {
+            m_modem = m_manager->modem();
+
+            m_modem->setPowered(true);
+       
+            qDebug() << QString("Modem connected");
+            connect(m_modem, SIGNAL(interfacesChanged(QStringList)), this,
+                    SLOT(modemInterfacesChanged(QStringList)));
+            connect(m_modem, SIGNAL(poweredChanged(bool)), this,
+                    SLOT(modemPowered(bool)));
+
+            if (m_modem->powered() &&
+                m_modem->interfaces().contains(OFONO_VOICECALLMANAGER_INTERFACE))
+                {
+                    /* connect all now, modem is enabled */
+                    this->connectAll();
+                }
+        }
+}
+
+void DialerApplication::modemDisconnected()
+{
+    TRACE;
+    //TODO: Handle multiple modems
+}
+
+void DialerApplication::modemInterfacesChanged(QStringList interfaces)
+{
+    TRACE;
+    qDebug() << QString("Modem Interfaces: ") << interfaces;
+
+    if (interfaces.contains(OFONO_VOICECALLMANAGER_INTERFACE) &&
+        m_manager->modem()->powered())
+        {
+            this->connectAll();
+        }
+}
+
+void DialerApplication::modemPowered(bool isPowered)
+{
+    TRACE;
+    qDebug() << QString("Modem Powered: ") << isPowered;
+
+    if (isPowered &&
+        m_manager->modem()->interfaces().contains(OFONO_VOICECALLMANAGER_INTERFACE))
+        {
+            this->connectAll();
+        }
+}
+
+void DialerApplication::networkConnected()
+{
+    TRACE;
+    if (m_manager->network() && m_manager->network()->isValid())
+        m_network = m_manager->network();
+}
+
+void DialerApplication::networkDisconnected()
+{
+    TRACE;
+}
+
+void DialerApplication::callManagerConnected()
+{
+    TRACE;
+    if (m_manager->callManager() && m_manager->callManager()->isValid())
+        m_callManager = m_manager->callManager();
+
+
+    qDebug() << QString("Disconnect calls changed signal");
+    disconnect(m_callManager, SIGNAL(callsChanged()));
+
+    qDebug() << QString("Disconnect incoming signal");
+    disconnect(m_callManager, SIGNAL(incomingCall(CallItem*)));
+
+    qDebug() << QString("Disconnect resource lost");
+    disconnect(m_callManager, SIGNAL(callResourceLost(const QString)));
+}
+
+void DialerApplication::callManagerDisconnected()
+{
+    TRACE;
+    qDebug() << QString("CallMgr disconnected");
+}
+
+void DialerApplication::messagesWaitingChanged()
+{
+    TRACE;
+}
+
+void DialerApplication::onCallsChanged()
+{
+    TRACE;
+    QMLMainWindow::instance()->tryToShow();
+}
+
+void DialerApplication::raise()
+{
+    TRACE;
+    QMLMainWindow::instance()->tryToShow();
+}
+
+void DialerApplication::closeWindow()
+{
+    TRACE;
+    m_mainWindow->hide();
+}
+
+/* Local Variables:      */
+/* mode:c++              */
+/* c-basic-offset:4      */
+/* indent-tabs-mode: nil */
+/* End:                  */
diff --git a/src/dialerapplication.h b/src/dialerapplication.h
new file mode 100644 (file)
index 0000000..756cb29
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * hfdialer - Hands Free Voice Call Manager
+ * Copyright (c) 2012, Intel Corporation.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0.  The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ */
+
+#ifndef DIALERAPPLICATION_h
+#define DIALERAPPLICATION_h
+
+#include "managerproxy.h"
+#include "qmlmainwindow.h"
+#include <QSortFilterProxyModel>
+#include <QApplication>
+
+class DialerApplication: public QApplication
+{
+    Q_OBJECT;
+
+    Q_PROPERTY(bool isConnected READ isConnected);
+    Q_PROPERTY(bool hasError READ hasError);
+    Q_PROPERTY(QString lastError READ lastError);
+
+public:
+    DialerApplication(int &argc, char **argv);
+
+    static DialerApplication* instance();
+
+    virtual void releasePrestart();
+    virtual void restorePrestart();
+
+    bool hasError() const;
+    QString lastError() const;
+    void setError(const QString msg);
+
+    bool isConnected();
+    
+Q_SIGNALS:
+    void showUi();
+    void hideUi();
+public Q_SLOTS:
+    void closeWindow();
+    void raise();
+private Q_SLOTS:
+    void connectAll();
+    void messagesWaitingChanged();
+
+    void modemChanged();
+    void modemConnected();
+    void modemDisconnected();
+    void modemInterfacesChanged(QStringList interfaces);
+    void modemPowered(bool isPowered);
+    void networkConnected();
+    void networkDisconnected();
+    void callManagerConnected();
+    void callManagerDisconnected();
+
+    void onCallsChanged();
+
+private:
+    void init();
+
+    ManagerProxy *m_manager;
+    ModemProxy   *m_modem;
+    NetworkProxy *m_network;
+    CallManager  *m_callManager;
+
+    bool          m_connected;
+    QString       m_lastError;
+    QMLMainWindow *m_mainWindow;
+    QDBusConnection *m_bus;
+    Q_DISABLE_COPY(DialerApplication);
+};
+
+#endif // DIALERAPPLICATION_H
+
+/* Local Variables:      */
+/* mode:c++              */
+/* c-basic-offset:4      */
+/* indent-tabs-mode: nil */
+/* End:                  */
diff --git a/src/dialercontext.cpp b/src/dialercontext.cpp
new file mode 100644 (file)
index 0000000..c6ea624
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * hfdialer - Hands Free Voice Call Manager
+ * Copyright (c) 2012, Intel Corporation.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0.  The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ */
+
+#include "common.h"
+#include "dialercontext.h"
+
+#define AUTOSELECT OfonoModem::AutomaticSelect
+
+#ifndef CONFIG_KEY_TARGET_MODE
+#define CONFIG_KEY_TARGET_MODE "/apps/dialer/mode"
+#endif
+
+#include <QDebug>
+
+DialerContext *DialerContext::gContext = 0;
+
+class DialerContextPrivate
+{
+public:
+    DialerContextPrivate()
+        : modemManager(0),
+          volumeManager(0),
+          voicemailManager(0),
+          callManager(0),
+          modesKey(CONFIG_KEY_TARGET_MODE)
+    { TRACE }
+
+    ~DialerContextPrivate() {
+        delete volumeManager;
+        volumeManager = 0;
+        delete voicemailManager;
+        voicemailManager = 0;
+        delete callManager;
+        callManager = 0;
+        delete modemManager;
+        modemManager = 0;
+    }
+
+    OfonoModemManager   *modemManager;
+    OfonoCallVolume     *volumeManager;
+    OfonoMessageWaiting *voicemailManager;
+    CallManager         *callManager;
+    QStringList          modes;
+    MGConfItem           modesKey;
+};
+
+
+DialerContext::DialerContext(QObject *parent)
+    : QObject(parent),
+      d(new DialerContextPrivate)
+{
+    if (gContext)
+        qFatal(__func__, ": There can be only one!");
+
+    // Read and configure default runtime modes
+    setModes(d->modesKey.value().toStringList());
+
+    // Create misc services
+    // TODO: We may not actually need this, since OfonoModem class
+    //       allows for "auto selection" and switching of modems
+    d->modemManager = new OfonoModemManager(parent);
+    d->volumeManager = new OfonoCallVolume(AUTOSELECT,"");
+    d->voicemailManager = new OfonoMessageWaiting(AUTOSELECT,"");
+    d->callManager = new CallManager();
+
+    // OfonoModemManager signals to monitor
+    connect(d->modemManager, SIGNAL(modemAdded(const QString&)),
+            SLOT(onModemAdded(const QString&)));
+    connect(d->modemManager, SIGNAL(modemRemoved(const QString&)),
+            SLOT(onModemRemoved(const QString&)));
+
+    // CallManager signals to monitor
+    connect(d->callManager, SIGNAL(validityChanged(bool)),
+            SLOT(onCallManagerValidityChanged(bool)));
+    connect(d->callManager, SIGNAL(callsChanged()), SLOT(onCallsChanged()));
+
+    // OfonoCallVolume signals to monitor
+    connect(d->volumeManager, SIGNAL(validityChanged(bool)),
+            SLOT(onCallVolumeValidityChanged(bool)));
+
+    // OfonoMessageWaiting signals to monitor
+    connect(d->voicemailManager, SIGNAL(validityChanged(bool)),
+            SLOT(onVoicemailValidityChanged(bool)));
+    connect(d->voicemailManager, SIGNAL(voicemailWaitingChanged(bool)),
+            SLOT(onVoicemailWaitingChanged(bool)));
+    connect(d->voicemailManager, SIGNAL(voicemailMessageCountChanged(int)),
+            SLOT(onVoicemailCountChanged(int)));
+
+    // GConf Key change signals to monitor
+    connect(&d->modesKey, SIGNAL(valueChanged()), SLOT(onModesChanged()));
+
+    if (d->callManager)
+        qDebug() << __func__ << ": Using modem - "
+                 << d->callManager->modem()->path();
+
+    gContext = this;
+}
+
+/*
+ * Public methods
+ */
+DialerContext::~DialerContext()
+{
+    delete d;
+    d = 0;
+    gContext=0;
+}
+
+DialerContext *DialerContext::instance()
+{
+    if (!gContext)
+        gContext = new DialerContext();
+    return gContext;
+}
+
+OfonoModemManager* DialerContext::modemManager() const
+{
+    return d->modemManager;
+}
+
+OfonoCallVolume* DialerContext::volumeManager() const
+{
+    return d->volumeManager;
+}
+
+OfonoMessageWaiting* DialerContext::voicemailManager() const
+{
+    return d->voicemailManager;
+}
+
+CallManager* DialerContext::callManager() const
+{
+    return d->callManager;
+}
+
+QStringList DialerContext::modes() const
+{
+    return d->modes;
+}
+
+void DialerContext::setModes(const QStringList &modelist)
+{
+    d->modes = modelist;
+    d->modes.removeDuplicates();
+    emit modesChanged();
+}
+
+/*
+ * Private methods/slots
+ */
+
+void DialerContext::onModemAdded(const QString &path)
+{
+    TRACE;
+    // TODO: Handle modem additions, maybe...
+    qWarning() << __func__ << ": Unhandled ModemAdded - " << path;
+}
+
+void DialerContext::onModemRemoved(const QString &path)
+{
+    TRACE;
+    // TODO: Handle modem removals, currently active for sure, others, maybe...
+    qWarning() << __func__ << ": Unhandled ModemAdded - " << path;
+}
+
+void DialerContext::onCallVolumeValidityChanged(bool valid)
+{
+    TRACE;
+    // TODO: Reset the volumeManager service reference
+    qWarning() << __func__ << ": valid? " << ((valid)?"true":"false");
+}
+
+void DialerContext::onVoicemailValidityChanged(bool valid)
+{
+    TRACE;
+    // TODO: Reset the voicemailManager service reference
+    qWarning() << __func__ << ": valid? " << ((valid)?"true":"false");
+}
+
+void DialerContext::onVoicemailWaitingChanged(bool waiting)
+{
+    TRACE;
+    // TODO: Send notifications (or bubble this up for UI to handle?)
+    qDebug() << __func__ << ": Messages? " << ((waiting)?"true":"false");
+}
+
+void DialerContext::onVoicemailCountChanged(int count)
+{
+    TRACE;
+    // TODO: Send notifications (or bubble this up for UI to handle?)
+    qDebug() << __func__ << ": Message count == " << count;
+}
+
+void DialerContext::onCallManagerValidityChanged(bool valid)
+{
+    TRACE;
+    // TODO: Reset the callManager service reference
+    qWarning() << __func__ << ": valid? " << ((valid)?"true":"false");
+}
+
+void DialerContext::onCallsChanged()
+{
+    TRACE;
+    // TODO: Send notifications (or bubble this up for UI to handle?)
+    qDebug() << __func__ << ": Calls count == "
+             << d->callManager->getCalls().count();
+}
+
+void DialerContext::onModesChanged()
+{
+    TRACE;
+    setModes(d->modesKey.value().toStringList());
+    // Send notification of change
+    emit modesChanged();
+    qDebug() << __func__ << ": New modes == " << d->modes.join(", ");
+}
+
+/* Local Variables:      */
+/* mode:c++              */
+/* c-basic-offset:4      */
+/* indent-tabs-mode: nil */
+/* End:                  */
diff --git a/src/dialercontext.h b/src/dialercontext.h
new file mode 100644 (file)
index 0000000..634d0a2
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * hfdialer - Hands Free Voice Call Manager
+ * Copyright (c) 2012, Intel Corporation.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0.  The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ */
+
+#ifndef DIALERCONTEXT_H
+#define DIALERCONTEXT_H
+
+// libofono-qt headers
+#include <ofonomodemmanager.h>
+#include <ofonocallvolume.h>
+#include <ofonomessagewaiting.h>
+
+// local headers
+#include "callmanager.h"
+
+// Convienence Macro for access to Class instance
+#define DC DialerContext::instance()
+
+class DialerContext: public QObject
+{
+    Q_OBJECT;
+
+    Q_PROPERTY(OfonoModemManager* modemManager READ modemManager);
+    Q_PROPERTY(OfonoCallVolume* volumeManager READ volumeManager);
+    Q_PROPERTY(OfonoMessageWaiting* voicemailManager READ voicemailManager);
+    Q_PROPERTY(CallManager* callManager READ callManager);
+    Q_PROPERTY(QStringList modes READ modes WRITE setModes);
+
+public:
+    virtual ~DialerContext();
+
+    static DialerContext *instance();
+
+    OfonoModemManager*   modemManager() const;
+    OfonoCallVolume*     volumeManager() const;
+    OfonoMessageWaiting* voicemailManager() const;
+    CallManager*         callManager() const;
+    QStringList          modes() const;
+
+public slots:
+    // Slot to set current mode at runtime
+    void setModes(const QStringList &modeList);
+
+Q_SIGNALS:
+    void modesChanged();
+
+private Q_SLOTS:
+
+    // Slots to handle signals from Manager oFono service
+    void onModemAdded(const QString &path);
+    void onModemRemoved(const QString &path);
+
+    // Slots to handle signals from CallVolume oFono service
+    void onCallVolumeValidityChanged(bool valid);
+
+    // Slots to handle signals from MessageWaiting oFono service
+    void onVoicemailValidityChanged(bool valid);
+    void onVoicemailWaitingChanged(bool waiting);
+    void onVoicemailCountChanged(int count);
+
+    // Slots to handle signals from CallManager oFono service
+    void onCallManagerValidityChanged(bool valid);
+    void onCallsChanged();
+
+    // Slot to handle runtime mode changes in GConf key
+    void onModesChanged();
+
+protected:
+    DialerContext(QObject *parent = 0);
+
+private:
+    DialerContext(const DialerContext&);
+    DialerContext& operator= (DialerContext&);
+
+    class DialerContextPrivate *d;
+
+    static DialerContext *gContext;
+};
+
+#endif // DIALERCONTEXT_H
+
+/* Local Variables:      */
+/* mode:c++              */
+/* c-basic-offset:4      */
+/* indent-tabs-mode: nil */
+/* End:                  */
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644 (file)
index 0000000..dfe2f0b
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * hfdialer - Hands Free Voice Call Manager
+ * Copyright (c) 2012, Intel Corporation.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0.  The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ */
+
+#include "dialercontext.h"
+#include "dialerapplication.h"
+#include "qmlmainwindow.h"
+#include "common.h"
+
+#include <QtGui>
+#include <QApplication>
+#include <QDeclarativeView>
+#include <QFile>
+
+int main(int argc, char *argv[])
+{
+    TRACE;
+    QDBusConnection bus = QDBusConnection::systemBus();
+    QStringList serviceNames = bus.interface()->registeredServiceNames();
+       
+    if (serviceNames.contains("com.hfdialer"))
+    {
+        QDBusMessage message = QDBusMessage::createMethodCall("com.hfdialer","/com/dialer","com.hfdialer", "raise");
+       bus.call(message,QDBus::NoBlock);
+       
+       return 0;
+    }
+
+    DialerApplication app(argc, argv);  
+
+    QMLMainWindow *qmw = QMLMainWindow::instance();
+    
+    QString argString(argv[1]); 
+
+    if (argString != "noshow")
+       qmw->tryToShow();
+
+    return app.exec();
+}
+
+QString stripLineID(QString lineid)
+{
+    TRACE;
+    static QRegExp rx = QRegExp("([^0-9*#])");
+
+    if (lineid.indexOf('+') == 0) {
+        lineid.replace(rx, "");
+        return lineid.insert(0,"+");
+    } else {
+        return lineid.replace(rx, "");
+    }
+}
+
+/* Local Variables:      */
+/* mode:c++              */
+/* c-basic-offset:4      */
+/* indent-tabs-mode: nil */
+/* End:                  */
diff --git a/src/managerproxy.cpp b/src/managerproxy.cpp
new file mode 100644 (file)
index 0000000..3f94a10
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+ * hfdialer - Hands Free Voice Call Manager
+ * Copyright (c) 2012, Intel Corporation.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0.  The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ */
+
+#include "managerproxy.h"
+#include "manager_interface.h"
+#include "dialerapplication.h"
+#include <QDebug>
+
+ManagerProxy *ManagerProxy::gManager = 0;
+
+ManagerProxy::ManagerProxy(const QString &service,
+                           const QString &path,
+                           const QDBusConnection &connection,
+                           QObject *parent)
+    : org::ofono::Manager(service, path, connection, parent),
+      m_modemPath (""),
+      m_modem(0),
+      m_network(0),
+      m_callManager(0),
+      m_volumeManager(0),
+      m_voicemail(0)
+{
+    TRACE;
+    if (gManager)
+        qFatal("ManagerProxy: There can be only one!");
+
+    if (!isValid()) {
+        qDebug() << "Failed to connect to Ofono: \n\t" << lastError().message();
+    } else {
+        QDBusPendingReply<QArrayOfPathProperties> reply;
+        QDBusPendingCallWatcher * watcher;
+
+        reply = GetModems();
+        watcher = new QDBusPendingCallWatcher(reply);
+
+        // Force this to be sync to ensure we have initial properties
+        watcher->waitForFinished();
+        managerDBusGetModemsDone(watcher);
+
+        connect(this,
+                SIGNAL(ModemAdded(const QDBusObjectPath&, const QVariantMap&)),
+                SLOT(modemAdded(const QDBusObjectPath&, const QVariantMap&)));
+        connect(this,
+                SIGNAL(ModemRemoved(const QDBusObjectPath&)),
+                SLOT(modemRemoved(const QDBusObjectPath&)));
+
+    }
+
+    gManager = this;
+
+    if (m_modem && m_modem->isValid() && !m_modem->powered())
+       m_modem->setPowered(true);
+}
+
+ManagerProxy::~ManagerProxy()
+{
+    TRACE;
+    if (m_volumeManager)
+        delete m_volumeManager;
+    m_volumeManager = 0;
+
+    if (m_voicemail)
+        delete m_voicemail;
+    m_voicemail = 0;
+
+    if (m_callManager)
+        delete m_callManager;
+    m_callManager = 0;
+
+    if (m_network)
+        delete m_network;
+    m_network = 0;
+
+    if (m_modem)
+        delete m_modem;
+    m_modem = 0;
+
+    gManager=0;
+}
+
+void ManagerProxy::managerDBusGetModemsDone(QDBusPendingCallWatcher *call)
+{
+    QDBusPendingReply<QArrayOfPathProperties> reply = *call;
+    TRACE;
+    if (reply.isError()) {
+        // TODO: Handle this properly, by setting states, or disabling features
+        qWarning() << "org.ofono.Manager.GetModems() failed: " <<
+            reply.error().message();
+    } else {
+        QArrayOfPathProperties modems = reply.value();
+        if (modems.count() >= 1) {
+            // FIXME: Handle multiple modems...
+            foreach (OfonoPathProperties p, modems)
+                {
+                    qDebug() << "modem: " << p.path.path();
+                    m_modemList << QString(p.path.path());
+                }
+
+            OfonoPathProperties p = modems[0];
+            if (m_modemPath.isNull() || m_modemPath.isEmpty()) {
+                qDebug() << QString("\n======\nUsing modem: \"%1\"\n======").arg(p.path.path());
+                m_modemPath = QString(p.path.path());
+                setModem(m_modemPath);
+                setNetwork(m_modemPath);
+                setCallManager(m_modemPath);
+                setVolumeManager(m_modemPath);
+                setVoicemail(m_modemPath);
+                // TODO: Connect to service proxies as available/needed here
+            }
+        }
+    }
+}
+
+void ManagerProxy::modemAdded(const QDBusObjectPath &in0,const QVariantMap &in1)
+{
+    Q_UNUSED(in1)
+        TRACE;
+
+    // TODO: Handle modem additions, maybe...
+    qWarning() << QString("Unhandled ModemAdded event: \"%1\"")
+        .arg(in0.path());
+
+    qDebug() << QString("modem added: %1").arg(in0.path());
+    m_modemList << QString(in0.path());
+    m_modemList.removeDuplicates();
+
+    setModem(in0.path());
+    setCallManager(m_modemPath);
+}
+
+void ManagerProxy::modemRemoved(const QDBusObjectPath &in0)
+{
+    TRACE;
+
+    // TODO: Handle modem removals, currently active for sure, others, maybe...
+    qWarning() << QString("Unhandled ModemRemoved event: \"%1\"")
+        .arg(in0.path());
+
+    qDebug() << QString("modem removed: ").arg(in0.path());
+    m_modemList.removeOne(QString(in0.path()));
+}
+
+ManagerProxy *ManagerProxy::instance()
+{
+    if (!gManager)
+        gManager = new ManagerProxy();
+
+    return gManager;
+}
+
+ModemProxy* ManagerProxy::modem() const
+{
+    return m_modem;
+}
+
+NetworkProxy* ManagerProxy::network() const
+{
+    return m_network;
+}
+
+CallManager* ManagerProxy::callManager() const
+{
+    return m_callManager;
+}
+
+VolumeManager* ManagerProxy::volumeManager() const
+{
+    return m_volumeManager;
+}
+
+VoicemailProxy* ManagerProxy::voicemail() const
+{
+    return m_voicemail;
+}
+
+QStringList ManagerProxy::getModemList()
+{
+    return m_modemList;
+}
+
+void ManagerProxy::setModem(QString modemPath)
+{
+    if (m_modem &&
+        m_modem->isValid() &&
+        m_modem->path() == modemPath)
+    {
+       //If we have a modem, it's valid, but not powered, power it up.
+       if (!m_modem->powered())
+               m_modem->setPowered(true);
+
+        return;
+    }
+
+    if (m_modem)
+        {
+            if (m_modemList.contains(m_modem->path()))
+                {
+                    m_modemList.removeAll(m_modem->path());
+                }
+            delete m_modem;
+            m_modem = NULL;
+        }
+
+    if (m_modemList.contains(modemPath)) {
+        m_modem = new ModemProxy(modemPath);
+        emit modemChanged();
+    }
+}
+
+void ManagerProxy::setNetwork(QString modempath)
+{
+    if (!m_modem || !m_modem->isValid())
+        return;
+
+    if (modempath == m_modem->path()) {
+        if (m_network && m_network->isValid()) {
+            return;
+        }
+        else {
+            delete m_network;
+            m_network = new NetworkProxy(modempath);
+            emit networkChanged();
+        }
+    }
+    else {
+        if(m_network || !m_network->isValid()) {
+            delete m_network;
+            m_network = new NetworkProxy(modempath);
+            emit networkChanged();
+        }
+    }
+}
+
+void ManagerProxy::setCallManager(QString modempath)
+{
+    TRACE
+    if (!m_modem || !m_modem->isValid())
+        return;
+
+    if (modempath == m_modem->path()) {
+        if (m_callManager && m_callManager->isValid()) {
+            return;
+        }
+        else {
+            delete m_callManager;
+            m_callManager = new CallManager(modempath);
+            emit callManagerChanged();
+        }
+    }
+    else {
+        
+        if(m_callManager)
+            delete m_callManager;        
+        
+        m_callManager = new CallManager(modempath);
+        connect(m_callManager, SIGNAL(connected()), this, SIGNAL(callManagerChanged()));
+         emit callManagerChanged();
+    }
+}
+
+void ManagerProxy::setVolumeManager(QString modempath)
+{
+    if (!m_modem || !m_modem->isValid())
+        return;
+
+    if (modempath == m_modem->path()) {
+        if (m_volumeManager && m_volumeManager->isValid()) {
+            return;
+        }
+        else {
+            delete m_volumeManager;
+            m_volumeManager = new VolumeManager(modempath);
+            emit volumeManagerChanged();
+        }
+    }
+    else {
+        if(m_volumeManager || !m_volumeManager->isValid()) {
+            delete m_volumeManager;
+            m_volumeManager = new VolumeManager(modempath);
+            emit volumeManagerChanged();
+        }
+    }
+}
+
+void ManagerProxy::setVoicemail(QString modempath)
+{
+    if (!m_modem || !m_modem->isValid())
+        return;
+
+    if (modempath == m_modem->path()) {
+        if (m_voicemail && m_voicemail->isValid()) {
+            return;
+        }
+        else {
+            delete m_voicemail;
+            m_voicemail = new VoicemailProxy(modempath);
+            emit voicemailChanged();
+        }
+    }
+    else {
+        if(m_voicemail || !m_voicemail->isValid()) {
+            delete m_voicemail;
+            m_voicemail = new VoicemailProxy(modempath);
+            emit voicemailChanged();
+        }
+    }
+}
+
+/* Local Variables:      */
+/* mode:c++              */
+/* c-basic-offset:4      */
+/* indent-tabs-mode: nil */
+/* End:                  */
diff --git a/src/managerproxy.h b/src/managerproxy.h
new file mode 100644 (file)
index 0000000..f27ea6e
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * hfdialer - Hands Free Voice Call Manager
+ * Copyright (c) 2012, Intel Corporation.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0.  The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ */
+
+#ifndef MANAGERPROXY_H
+#define MANAGERPROXY_H
+
+#include "manager_interface.h"
+#include "modemproxy.h"
+#include "networkproxy.h"
+#include "callmanager.h"
+#include "common.h"
+#include <QtDBus>
+#include <QDebug>
+
+#define OFONO_SERVICE "org.ofono"
+#define OFONO_MANAGER_PATH "/"
+
+class ManagerProxy: public org::ofono::Manager
+{
+    Q_OBJECT;
+    Q_PROPERTY(ModemProxy* modem READ modem);
+    Q_PROPERTY(NetworkProxy* network READ network);
+
+public:
+    virtual ~ManagerProxy();
+
+    static ManagerProxy *instance();
+    QStringList getModemList();
+    void setModem(QString modempath);
+    void setNetwork(QString modempath);
+    void setCallManager(QString modempath);
+    void setVolumeManager(QString modempath);
+    void setVoicemail(QString modempath);
+
+    ModemProxy* modem() const;
+    NetworkProxy* network() const;
+    CallManager* callManager() const;
+    VolumeManager* volumeManager() const;
+    VoicemailProxy* voicemail() const;
+
+public slots:
+    void managerDBusGetModemsDone(QDBusPendingCallWatcher *call);
+
+Q_SIGNALS:
+    void modemChanged();
+    void networkChanged();
+    void callManagerChanged();
+    void volumeManagerChanged();
+    void voicemailChanged();
+
+private Q_SLOTS:
+    void modemAdded(const QDBusObjectPath &in0, const QVariantMap &in1);
+    void modemRemoved(const QDBusObjectPath &in0);
+
+protected:
+    ManagerProxy(const QString &service=OFONO_SERVICE,
+                 const QString &path=OFONO_MANAGER_PATH,
+                 const QDBusConnection &connection=QDBusConnection::systemBus(),
+                 QObject *parent = 0);
+
+private:
+    ManagerProxy(const ManagerProxy&);
+    ManagerProxy& operator= (ManagerProxy&);
+
+    QString       m_modemPath;
+    ModemProxy   *m_modem;
+    NetworkProxy *m_network;
+    CallManager  *m_callManager;
+    VolumeManager *m_volumeManager;
+    VoicemailProxy *m_voicemail;
+    QStringList m_modemList;
+
+    static ManagerProxy *gManager;
+};
+
+#endif
+
+/* Local Variables:      */
+/* mode:c++              */
+/* c-basic-offset:4      */
+/* indent-tabs-mode: nil */
+/* End:                  */
diff --git a/src/modemproxy.cpp b/src/modemproxy.cpp
new file mode 100644 (file)
index 0000000..b150463
--- /dev/null
@@ -0,0 +1,374 @@
+/*
+ * hfdialer - Hands Free Voice Call Manager
+ * Copyright (c) 2012, Intel Corporation.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0.  The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ */
+
+#include "modemproxy.h"
+#include <QDebug>
+#include "common.h"
+
+ModemProxy::ModemProxy(const QString &objectPath)
+    : org::ofono::Modem(OFONO_SERVICE,
+                        objectPath,
+                        QDBusConnection::systemBus()),
+      m_interfaces(0)
+{
+    TRACE;
+    if (!isValid()) {
+        qDebug() << "Failed to connect to Ofono: \n\t" << lastError().message();
+    } else {
+        m_path = objectPath;
+        QDBusPendingReply<QVariantMap> reply;
+        QDBusPendingCallWatcher * watcher;
+
+        reply = GetProperties();
+        watcher = new QDBusPendingCallWatcher(reply);
+
+        connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
+                this, SLOT(modemDBusGetPropDone(QDBusPendingCallWatcher*)));
+
+        connect(this,
+                SIGNAL(PropertyChanged(const QString&,const QDBusVariant&)),
+                SLOT(propertyChanged(const QString&,const QDBusVariant&)));
+    }
+}
+
+ModemProxy::~ModemProxy()
+{
+    TRACE;
+}
+
+QStringList ModemProxy::interfaces() const { return m_interfaces; }
+QString ModemProxy::path() const { return m_path; }
+QString ModemProxy::manufacturer() const { return m_manufacturer; }
+QString ModemProxy::model() const { return m_model; }
+QString ModemProxy::revision() const { return m_revision; }
+QString ModemProxy::serial() const { return m_serial; }
+bool    ModemProxy::powered() const { return m_powered; }
+bool    ModemProxy::online() const { return m_online; }
+
+void ModemProxy::setPowered(bool is_powered)
+{
+    TRACE;
+    if (m_powered == is_powered)
+        return;
+
+    QVariant powered(is_powered);
+
+    QDBusPendingReply<QVariantMap> reply;
+    reply = SetProperty("Powered", QDBusVariant(powered));
+
+    if (reply.isError())
+        qCritical() << "SetProperty \"Powered\" failed!";
+}
+
+void ModemProxy::setOnline(bool is_online)
+{
+    TRACE;
+    if (m_online == is_online)
+        return;
+
+    QDBusPendingReply<QVariantMap> reply;
+    reply = SetProperty("Online", QDBusVariant(m_online?"true":"false"));
+    if (reply.isError())
+        qCritical() << "SetProperty \"Powered\" failed!";
+    else
+        m_online = is_online;
+}
+
+void ModemProxy::modemDBusGetPropDone(QDBusPendingCallWatcher *call)
+{
+    TRACE;
+    QDBusPendingReply<QVariantMap> reply = *call;
+
+    if (reply.isError()) {
+        // TODO: Handle this properly, by setting states, or disabling features...
+        qDebug() << "org.ofono.ModemProxy.getProperties() failed: " <<
+            reply.error().message();
+    } else {
+        QVariantMap properties = reply.value();
+        m_interfaces = qdbus_cast<QStringList >(properties["Interfaces"]);
+        m_manufacturer = qdbus_cast<QString>(properties["Manufacturer"]);
+        m_model = qdbus_cast<QString>(properties["Model"]);
+        m_powered = qdbus_cast<bool>(properties["Powered"]);
+        m_revision = qdbus_cast<QString>(properties["Revision"]);
+        m_serial = qdbus_cast<QString>(properties["Serial"]);
+        m_online = qdbus_cast<bool>(properties["Online"]);
+
+        // First sucessfull GetProperties == connected
+        if (!m_connected) {
+            m_connected = true;
+            emit connected();
+        }
+    }
+}
+
+void ModemProxy::propertyChanged(const QString &in0, const QDBusVariant &in1)
+{
+    TRACE;
+    qDebug() << "org.ofono.ModemProxy.propertyChanged()"
+             << in0 << ": " << in1.variant();
+    if (in0 == "Interfaces") {
+        m_interfaces = qdbus_cast<QStringList>(in1.variant());
+        emit interfacesChanged(m_interfaces);
+    }
+    else if (in0 == "Powered") {
+        m_powered = qdbus_cast<bool>(in1.variant());
+        emit poweredChanged(m_powered);
+    } else if (in0 == "Online") {
+        m_online = qdbus_cast<bool>(in1.variant());
+        emit onlineChanged(m_online);
+    } else {
+        qDebug() << QString("Unhandled property \"%1\" changed...").arg(in0);
+    }
+}
+
+/*
+ * VoicemailProxy (aka MessageWaiting) implementation
+ */
+
+VoicemailProxy::VoicemailProxy(const QString &objectPath)
+    : org::ofono::MessageWaiting(OFONO_SERVICE,
+                                 objectPath,
+                                 QDBusConnection::systemBus()),
+      m_connected(false)
+{
+    TRACE;
+    if (!isValid()) {
+        qDebug() << "Failed to connect to Ofono: \n\t" << lastError().message();
+    } else {
+        m_path = objectPath;
+        QDBusPendingReply<QVariantMap> reply;
+        QDBusPendingCallWatcher * watcher;
+
+        reply = GetProperties();
+        watcher = new QDBusPendingCallWatcher(reply);
+
+        connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
+                this, SLOT(voicemailDBusGetPropDone(QDBusPendingCallWatcher*)));
+        connect(this, SIGNAL(PropertyChanged(const QString&, const QDBusVariant&)),
+                SLOT(voicemailPropertyChanged(const QString&, const QDBusVariant&)));
+    }
+}
+
+VoicemailProxy::~VoicemailProxy()
+{
+    TRACE;
+}
+
+bool    VoicemailProxy::isConnected() const { return m_connected; }
+QString VoicemailProxy::path() const { return m_path; }
+QString VoicemailProxy::mailbox() const { return m_mailbox; }
+int     VoicemailProxy::count() const { return m_count; }
+bool    VoicemailProxy::waiting() const { return m_waiting; }
+
+void VoicemailProxy::setMailbox(QString lineid)
+{
+    TRACE;
+    if (lineid.isEmpty() || (m_mailbox == lineid))
+        return;
+
+    QDBusPendingReply<> reply;
+    reply = SetProperty("VoicemailMailboxNumber", QDBusVariant(lineid));
+    reply.waitForFinished();
+
+    if (reply.isError())
+        qCritical() << "SetProperty \"VoicemailMailboxNumber\" failed: " <<
+            reply.error().message();
+    else
+        m_mailbox = lineid;
+}
+
+void VoicemailProxy::voicemailDBusGetPropDone(QDBusPendingCallWatcher *call)
+{
+    TRACE;
+    QDBusPendingReply<QVariantMap> reply = *call;
+
+    if (reply.isError()) {
+        // TODO: Handle this properly, by setting states, or disabling features...
+        qDebug() << "org.ofono.MessageWaiting.getProperties() failed: " <<
+            reply.error().message();
+    } else {
+        QVariantMap properties = reply.value();
+        bool waiting = qdbus_cast<bool>(properties["VoicemailWaiting"]);
+        int count = qdbus_cast<int>(properties["VoicemailMessageCount"]);
+        QString mailbox = qdbus_cast<QString>(properties["VoicemailMailboxNumber"]);
+
+        if (count != m_count) {
+            m_count = count;
+            emit messagesWaitingChanged();
+        }
+        if (waiting != m_waiting) {
+            m_waiting = waiting;
+            emit messagesWaitingChanged();
+        }
+        if (!mailbox.isEmpty() && (mailbox != m_mailbox)) {
+            m_mailbox = mailbox;
+            emit mailboxChanged();
+        }
+
+        // First sucessfull GetProperties == connected
+        if (!m_connected) {
+            m_connected = true;
+            emit connected();
+        }
+    }
+}
+
+void VoicemailProxy::voicemailPropertyChanged(const QString &in0, const QDBusVariant &in1)
+{
+    TRACE;
+    qDebug() << QString("Property \"%1\" changed...").arg(in0);
+    bool waiting;
+    int count;
+    QString mailbox;
+    if (in0 == "VoicemailWaiting") {
+        waiting = qdbus_cast<bool>(in1.variant());
+    } else if (in0 == "VoicemailMessageCount") {
+        count = qdbus_cast<int>(in1.variant());
+    } else if (in0 == "VoicemailMailboxNumber") {
+        mailbox = qdbus_cast<QString>(in1.variant());
+    } else
+        qDebug() << QString("Unexpected property changed...");
+
+    if ((count != m_count) || (waiting != m_waiting)) {
+        m_count = count;
+        m_waiting = waiting;
+        emit messagesWaitingChanged();
+    }
+    if (!mailbox.isEmpty() && (mailbox != m_mailbox)) {
+        m_mailbox = mailbox;
+        emit mailboxChanged();
+    }
+}
+
+/*
+ * CallVolume Manager implementation
+ */
+
+VolumeManager::VolumeManager(const QString &objectPath)
+    : org::ofono::CallVolume(OFONO_SERVICE,
+                             objectPath,
+                             QDBusConnection::systemBus())
+{
+    TRACE;
+    if (!isValid()) {
+        qDebug() << "Failed to connect to Ofono: \n\t" << lastError().message();
+    } else {
+        m_path = objectPath;
+        QDBusPendingReply<QVariantMap> reply;
+        QDBusPendingCallWatcher * watcher;
+
+        reply = GetProperties();
+        watcher = new QDBusPendingCallWatcher(reply);
+
+        connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
+                this, SLOT(volumeDBusGetPropDone(QDBusPendingCallWatcher*)));
+    }
+}
+
+VolumeManager::~VolumeManager()
+{
+    TRACE;
+}
+
+QString VolumeManager::path() const { return m_path; }
+int     VolumeManager::speakerVolume() const { return m_speakerVolume; }
+int     VolumeManager::micVolume() const { return m_micVolume; }
+bool    VolumeManager::muted() const { return m_muted; }
+bool    VolumeManager::isConnected() const { return m_connected; }
+
+void VolumeManager::setSpeakerVolume(int volume)
+{
+    TRACE;
+    if (m_speakerVolume == volume)
+        return;
+
+    if ((volume < 0) || (volume > 100)) {
+        qWarning() << "SpeakerVolume value out of range (0<>100)";
+        return;
+    }
+
+    QDBusPendingReply<> reply;
+    reply = SetProperty("SpeakerVolume", QDBusVariant(volume));
+    reply.waitForFinished();
+
+    if (reply.isError())
+        qCritical() << "SetProperty \"SpeakerVolume\" failed: " <<
+            reply.error().message();
+    else
+        m_speakerVolume = volume;
+}
+
+void VolumeManager::setMicVolume(int volume)
+{
+    TRACE;
+    if (m_micVolume == volume)
+        return;
+
+    if ((volume < 0) || (volume > 100)) {
+        qWarning() << "MicrophoneVolume value out of range (0<>100)";
+        return;
+    }
+
+    QDBusPendingReply<> reply;
+    reply = SetProperty("MicrophoneVolume", QDBusVariant(volume));
+    reply.waitForFinished();
+
+    if (reply.isError())
+        qCritical() << "SetProperty \"MicrophoneVolume\" failed: " <<
+            reply.error().message();
+    else
+        m_micVolume = volume;
+}
+
+void VolumeManager::setMuted(bool is_muted)
+{
+    TRACE;
+    if (m_muted == is_muted)
+        return;
+
+    QDBusPendingReply<> reply;
+    reply = SetProperty("Muted", QDBusVariant(is_muted));
+    reply.waitForFinished();
+
+    if (reply.isError())
+        qCritical() << "SetProperty \"Muted\" failed: " <<
+            reply.error().message();
+    else
+        m_muted = is_muted;
+}
+
+void VolumeManager::volumeDBusGetPropDone(QDBusPendingCallWatcher *call)
+{
+    TRACE;
+    QDBusPendingReply<QVariantMap> reply = *call;
+
+    if (reply.isError()) {
+        // TODO: Handle this properly, by setting states, or disabling features...
+        qDebug() << "org.ofono.CallVolume.getProperties() failed: " <<
+            reply.error().message();
+    } else {
+        QVariantMap properties = reply.value();
+        m_speakerVolume = qdbus_cast<int>(properties["SpeakerVolume"]);
+        m_micVolume = qdbus_cast<int>(properties["MicrophoneVolume"]);
+        m_muted = qdbus_cast<bool>(properties["Muted"]);
+
+        // First sucessfull GetProperties == connected
+        if (!m_connected) {
+            m_connected = true;
+            emit connected();
+        }
+    }
+}
+
+/* Local Variables:      */
+/* mode:c++              */
+/* c-basic-offset:4      */
+/* indent-tabs-mode: nil */
+/* End:                  */
diff --git a/src/modemproxy.h b/src/modemproxy.h
new file mode 100644 (file)
index 0000000..d7c8e28
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * hfdialer - Hands Free Voice Call Manager
+ * Copyright (c) 2012, Intel Corporation.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0.  The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ */
+
+#ifndef MODEMPROXY_H
+#define MODEMPROXY_H
+
+#include "modem_interface.h"
+#include <QtDBus>
+#include <QDebug>
+
+#define OFONO_SERVICE "org.ofono"
+#define OFONO_MANAGER_PATH "/"
+
+class ModemProxy: public org::ofono::Modem
+{
+    Q_OBJECT;
+    Q_PROPERTY(QStringList interfaces READ interfaces);
+    Q_PROPERTY(QString path READ path);
+    Q_PROPERTY(QString manufacturer READ manufacturer);
+    Q_PROPERTY(QString model READ model);
+    Q_PROPERTY(QString revision READ revision);
+    Q_PROPERTY(QString serial READ serial);
+    Q_PROPERTY(bool powered READ powered WRITE setPowered);
+    Q_PROPERTY(bool online READ online WRITE setOnline);
+
+public:
+    ModemProxy(const QString &objectPath);
+    virtual ~ModemProxy();
+
+    QStringList interfaces() const;
+    QString path() const;
+    QString manufacturer() const;
+    QString model() const;
+    QString revision() const;
+    QString serial() const;
+    bool powered() const;
+    bool online() const;
+
+public slots:
+    void setPowered(bool is_powered);
+    void setOnline(bool is_online);
+
+    void modemDBusGetPropDone(QDBusPendingCallWatcher *call);
+
+Q_SIGNALS:
+    void interfacesChanged(QStringList interfaces);
+    void poweredChanged(bool powered);
+    void onlineChanged(bool powered);
+    void connected();
+    void disconnected();
+
+private Q_SLOTS:
+    // Slots to handle DBus signals from ofono
+    void propertyChanged(const QString &in0, const QDBusVariant &in1);
+
+private:
+    QStringList m_properties; // raw return from GetProperties
+    QStringList m_interfaces;
+    QString     m_path;
+    QString     m_manufacturer;
+    QString     m_model;
+    QString     m_revision;
+    QString     m_serial;
+    bool        m_powered;
+    bool        m_online;
+    bool        m_connected;
+};
+
+class VoicemailProxy: public org::ofono::MessageWaiting
+{
+    Q_OBJECT;
+
+    Q_PROPERTY(bool isConnected READ isConnected NOTIFY connected);
+    Q_PROPERTY(bool waiting READ waiting);
+    Q_PROPERTY(int count  READ count);
+    Q_PROPERTY(QString mailbox READ mailbox WRITE setMailbox);
+
+public:
+    VoicemailProxy(const QString &objectPath);
+    virtual ~VoicemailProxy();
+
+    bool isConnected() const;
+
+    QString  path() const;
+    bool     waiting() const;
+    int      count() const;
+    QString  mailbox() const;
+
+public slots:
+    void setMailbox(QString lineid);
+
+Q_SIGNALS:
+    void messagesWaitingChanged();
+    void mailboxChanged();
+    void connected();
+    void disconnected();
+
+private slots:
+    void voicemailDBusGetPropDone(QDBusPendingCallWatcher *call);
+    void voicemailPropertyChanged(const QString &in0, const QDBusVariant &in1);
+
+private:
+    QStringList m_properties; // raw return from GetProperties
+    QString     m_path;
+    bool        m_waiting;
+    int         m_count;
+    QString     m_mailbox;
+    bool        m_connected;
+};
+
+class VolumeManager: public org::ofono::CallVolume
+{
+    Q_OBJECT;
+    Q_PROPERTY(int speakerVolume READ speakerVolume WRITE setSpeakerVolume);
+    Q_PROPERTY(int micVolume READ micVolume WRITE setMicVolume);
+    Q_PROPERTY(bool muted READ muted WRITE setMuted);
+    Q_PROPERTY(bool isConnected READ isConnected);
+
+public:
+    VolumeManager(const QString &objectPath);
+    virtual ~VolumeManager();
+
+    QString path() const;
+    int  speakerVolume() const;
+    int  micVolume() const;
+    bool muted() const;
+    bool isConnected() const;
+
+public slots:
+    void setSpeakerVolume(int volume);
+    void setMicVolume(int volume);
+    void setMuted(bool is_muted);
+    void volumeDBusGetPropDone(QDBusPendingCallWatcher *call);
+
+Q_SIGNALS:
+    void speakerVolumeChanged(int volume);
+    void micVolumeChanged(int volume);
+    void muteChanged(bool muted);
+    void connected();
+    void disconnected();
+
+private:
+    QStringList m_properties; // raw return from GetProperties
+    QString     m_path;
+    int         m_speakerVolume;
+    int         m_micVolume;
+    bool        m_muted;
+    bool        m_connected;
+};
+
+#endif
+
+/* Local Variables:      */
+/* mode:c++              */
+/* c-basic-offset:4      */
+/* indent-tabs-mode: nil */
+/* End:                  */
diff --git a/src/networkproxy.cpp b/src/networkproxy.cpp
new file mode 100644 (file)
index 0000000..59b042c
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * hfdialer - Hands Free Voice Call Manager
+ * Copyright (c) 2012, Intel Corporation.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0.  The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ */
+
+#include "networkproxy.h"
+#include <QDebug>
+
+/* **************************************************************
+ * Network Operator Class
+ * **************************************************************/
+
+OperatorProxy::OperatorProxy(const QString &operatorPath)
+    : org::ofono::NetworkOperator(OFONO_SERVICE,
+                                  operatorPath,
+                                  QDBusConnection::systemBus()),
+      m_path(operatorPath), m_countryCode(""),
+      m_networkCode(""), m_name(""), m_status(""), m_technologies("")
+{
+    if (!isValid()) {
+        qCritical() << org::ofono::NetworkOperator::staticInterfaceName() <<
+            " connection failed: " << lastError().message();
+    } else {
+        QDBusPendingReply<QVariantMap> reply;
+        QDBusPendingCallWatcher * watcher;
+
+        reply = GetProperties();
+        watcher = new QDBusPendingCallWatcher(reply);
+
+        connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
+                this, SLOT(operatorDBusGetPropDone(QDBusPendingCallWatcher*)));
+    }
+}
+
+OperatorProxy::~OperatorProxy()
+{
+}
+
+QString OperatorProxy::path() const { return m_path; }
+QString OperatorProxy::countryCode() const { return m_countryCode; }
+QString OperatorProxy::networkCode() const { return m_networkCode; }
+QString OperatorProxy::name() const { return m_name; }
+QString OperatorProxy::status() const { return m_status; }
+QStringList OperatorProxy::technologies() const { return m_technologies; }
+
+void OperatorProxy::operatorDBusGetPropDone(QDBusPendingCallWatcher *call)
+{
+    QDBusPendingReply<QVariantMap> reply = *call;
+
+    if (reply.isError()) {
+        // TODO: Handle this properly
+        qCritical() << org::ofono::NetworkOperator::staticInterfaceName() <<
+            ".GetProperties() failed: " << reply.error().message();
+    } else {
+        QVariantMap properties = reply.value();
+        m_countryCode  = qdbus_cast<QString>(properties["MobileCountryCode"]);
+        m_networkCode  = qdbus_cast<QString>(properties["MobileNetworkCode"]);
+        m_name         = qdbus_cast<QString>(properties["Name"]);
+        m_status       = qdbus_cast<QString>(properties["Status"]);
+        m_technologies = qdbus_cast<QStringList>(properties["Technologies"]);
+    }
+}
+
+/* **************************************************************
+ * Network Registration Class
+ * **************************************************************/
+NetworkProxy::NetworkProxy(const QString &modemPath)
+    : org::ofono::NetworkRegistration(OFONO_SERVICE,
+                                      modemPath,
+                                      QDBusConnection::systemBus()),
+      m_mode(""), m_name(""), m_status(""), m_connected(false)
+{
+    if (!isValid()) {
+        qCritical() << org::ofono::NetworkRegistration::staticInterfaceName() <<
+            " connection failed: " << lastError().message();
+    } else {
+        QDBusPendingReply<QVariantMap> reply;
+        QDBusPendingCallWatcher * watcher;
+
+        reply = GetProperties();
+        watcher = new QDBusPendingCallWatcher(reply);
+
+        connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
+                this, SLOT(networkDBusGetPropDone(QDBusPendingCallWatcher*)));
+    }
+}
+
+NetworkProxy::~NetworkProxy()
+{
+}
+
+QList<OperatorProxy*> NetworkProxy::operators() const { return m_operators; }
+OperatorProxy* NetworkProxy::currentOperator() const
+{
+    return m_currentOperator;
+}
+QString NetworkProxy::mode() const { return m_mode; }
+QString NetworkProxy::name() const { return m_name; }
+QString NetworkProxy::status() const { return m_status; }
+
+void NetworkProxy::networkDBusGetPropDone(QDBusPendingCallWatcher *call)
+{
+    QDBusPendingReply<QVariantMap> reply = *call;
+
+    if (reply.isError()) {
+        // TODO: Handle this properly
+        qCritical() << org::ofono::NetworkRegistration::staticInterfaceName() <<
+            ".GetProperties() failed: " << reply.error().message();
+    } else {
+        QVariantMap properties = reply.value();
+        QList<QDBusObjectPath> paths =
+            qdbus_cast<QList<QDBusObjectPath> >(properties["AvailableOperators"]);
+
+        foreach (QDBusObjectPath p, paths) {
+            QString path = QString(p.path());
+            OperatorProxy *op = new OperatorProxy(path);
+
+            m_operatorPaths.append(path);
+            m_operators.append(op);
+
+        }
+        m_mode   = qdbus_cast<QString>(properties["Mode"]);
+        m_name   = qdbus_cast<QString>(properties["Operator"]);
+        m_status = qdbus_cast<QString>(properties["Status"]);
+
+        // First sucessfull GetProperties == connected
+        if (!m_connected) {
+            m_connected = true;
+            emit connected();
+        }
+    }
+}
+
+/* Local Variables:      */
+/* mode:c++              */
+/* c-basic-offset:4      */
+/* indent-tabs-mode: nil */
+/* End:                  */
diff --git a/src/networkproxy.h b/src/networkproxy.h
new file mode 100644 (file)
index 0000000..186984d
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * hfdialer - Hands Free Voice Call Manager
+ * Copyright (c) 2012, Intel Corporation.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0.  The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ */
+
+#ifndef NETWORKPROXY_H
+#define NETWORKPROXY_H
+
+#include "modem_interface.h"
+#include "operator_interface.h"
+#include <QtDBus>
+#include <QDebug>
+
+#define OFONO_SERVICE "org.ofono"
+#define OFONO_MANAGER_PATH "/"
+
+/* **************************************************************
+ * Network Operator Class
+ * **************************************************************/
+class OperatorProxy: public org::ofono::NetworkOperator
+{
+    Q_OBJECT;
+    Q_PROPERTY(QString path READ path);
+    Q_PROPERTY(QString countryCode READ countryCode);
+    Q_PROPERTY(QString networkCode READ networkCode);
+    Q_PROPERTY(QString name READ name);
+    Q_PROPERTY(QString status READ status);
+    Q_PROPERTY(QStringList technologies READ technologies);
+
+public:
+    OperatorProxy(const QString &objectPath);
+    virtual ~OperatorProxy();
+
+    QString path() const;
+    QString countryCode() const;
+    QString networkCode() const;
+    QString name() const;
+    QString status() const;
+    QStringList technologies() const;
+
+public slots:
+    void operatorDBusGetPropDone(QDBusPendingCallWatcher *call);
+
+Q_SIGNALS:
+    void propertyChanged();
+
+private:
+    QStringList m_properties; // raw return from GetProperties
+    QString     m_path;
+    QString     m_countryCode;
+    QString     m_networkCode;
+    QString     m_name;
+    QString     m_status;
+    QStringList m_technologies;
+};
+
+/* **************************************************************
+ * Network Registration Class
+ * **************************************************************/
+class NetworkProxy: public org::ofono::NetworkRegistration
+{
+    Q_OBJECT;
+    Q_PROPERTY(QList<OperatorProxy*> operators READ operators);
+    Q_PROPERTY(OperatorProxy currentOperator READ currentOperator);
+    Q_PROPERTY(QString mode READ mode);
+    Q_PROPERTY(QString name READ name);
+    Q_PROPERTY(QString status READ status);
+
+public:
+    NetworkProxy(const QString &objectPath);
+    virtual ~NetworkProxy();
+
+    QList<OperatorProxy*> operators() const;
+    OperatorProxy* currentOperator() const;
+    QString mode() const;
+    QString name() const;
+    QString status() const;
+
+public slots:
+    void networkDBusGetPropDone(QDBusPendingCallWatcher *call);
+
+Q_SIGNALS:
+    void propertyChanged();
+    void connected();
+    void disconnected();
+
+private:
+    OperatorProxy *m_currentOperator;
+
+    QStringList m_properties; // raw return from GetProperties
+    QStringList m_operatorPaths;
+    QList<OperatorProxy*> m_operators;
+    QString     m_mode;
+    QString     m_name;
+    QString     m_status;
+    bool        m_connected;
+};
+
+#endif
+
+/* Local Variables:      */
+/* mode:c++              */
+/* c-basic-offset:4      */
+/* indent-tabs-mode: nil */
+/* End:                  */
diff --git a/src/pacontrol.cpp b/src/pacontrol.cpp
new file mode 100644 (file)
index 0000000..60a158d
--- /dev/null
@@ -0,0 +1,710 @@
+/*
+ * hfdialer - Hands Free Voice Call Manager
+ * Copyright (c) 2012, Intel Corporation.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0.  The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ */
+
+#include "pacontrol.h"
+#include "managerproxy.h"
+#include "callmanager.h"
+#include <string.h>
+#include <QStringBuilder>
+#include <QList>
+#include <QDebug>
+
+// Define our pulse audio loop and connection variables
+static PAControl* paControl = new PAControl;
+// Create a mainloop API and connection to the default server
+static pa_glib_mainloop *pa_ml = NULL;
+
+static void pa_subscribed_events_cb(pa_context *c, enum pa_subscription_event_type t, uint32_t , void *);
+
+static void operation_callback(pa_context *c, int success, void *userdata) {
+    Q_UNUSED(c);
+    Q_UNUSED(userdata);
+    if (!success) {
+        qDebug() << QString("Operation Failed");
+        paControl->setErrorMsg(QString("Operation Failed"));
+    }
+}
+
+static void module_callback(pa_context *c, uint32_t index, void *userdata) {
+    Q_UNUSED(c);
+    Q_UNUSED(userdata);
+    if (index == PA_INVALID_INDEX) {
+        qDebug() << QString("Load module failed");
+        paControl->setErrorMsg(QString("Load module failed"));
+    }
+}
+
+static void pa_sourcelist_cb(pa_context *c, const pa_source_info *l, int is_last, void *userdata) {
+    Q_UNUSED(c);
+    Q_UNUSED(userdata);
+    PADevice *source;
+
+    if (is_last > 0) {
+        //end of the list
+        paControl->release();
+        return;
+    }
+
+    //qDebug() << "pa_sourcelist_cb() Source added: " << l->name;
+    source = new PADevice();
+    source->index = l->index;
+    if(l->name != NULL)
+        source->name = l->name;
+    if(l->description != NULL)
+        source->description = l->description;
+    paControl->addSource(source);
+}
+
+static void pa_sinklist_cb(pa_context *c, const pa_sink_info *l, int is_last, void *userdata) {
+    Q_UNUSED(c);
+    Q_UNUSED(userdata);
+    PADevice *sink;
+
+    if (is_last > 0) {
+        //end of the list
+        paControl->release();
+        return;
+    }
+
+    sink = new PADevice();
+    sink->index = l->index;
+    if(l->name != NULL)
+        sink->name = l->name;
+    if(l->description != NULL)
+        sink->description = l->description;
+    paControl->addSink(sink);
+}
+
+static void pa_modulelist_cb(pa_context *c, const pa_module_info *i, int is_last, void *userdata) {
+    Q_UNUSED(c);
+    Q_UNUSED(userdata);
+    PAModule *module;
+
+    if (is_last > 0) {
+        //end of the list
+        paControl->release();
+        return;
+    }
+
+    module = new PAModule();
+    module->index = i->index;
+    if(i->name != NULL)
+        module->name = i->name;
+    if(i->argument != NULL)
+        module->argument = i->argument;
+    paControl->addModule(module);
+}
+
+static void pa_state_cb(pa_context *c, void *) {
+
+    pa_context_state_t state = pa_context_get_state(c);
+    if(state == PA_CONTEXT_READY)
+        {
+            paControl->setState(true);
+            pa_context_set_subscribe_callback(c, pa_subscribed_events_cb, NULL);
+            pa_operation *o;
+            if (!(o = pa_context_subscribe(c, (pa_subscription_mask_t)
+                                           (PA_SUBSCRIPTION_MASK_MODULE|
+                                            PA_SUBSCRIPTION_MASK_SINK|
+                                            PA_SUBSCRIPTION_MASK_SOURCE|
+                                            PA_SUBSCRIPTION_MASK_SINK_INPUT|
+                                            PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT), NULL, NULL))) {
+                qWarning("pa_context_subscribe() failed");
+            }
+            if(o) pa_operation_unref(o);
+            ///Get an initial list of sinks, sources and modules.
+            paControl->addRef();
+            pa_context_get_sink_info_list(c, pa_sinklist_cb, NULL);
+            paControl->addRef();
+            pa_context_get_source_info_list(c, pa_sourcelist_cb, NULL);
+            paControl->addRef();
+            pa_context_get_module_info_list(c, pa_modulelist_cb, NULL);
+        }
+    else if(state == PA_CONTEXT_FAILED)
+        {
+            ///Pulseaudio crashed?
+            paControl->setState(false);
+        }
+    else
+        {
+            qDebug()<<"PA state: "<<(int) state;
+        }
+}
+
+static void pa_subscribed_events_cb(pa_context *c, enum pa_subscription_event_type t, uint32_t , void *)
+{
+    switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK)
+        {
+        case PA_SUBSCRIPTION_EVENT_SINK:
+            qDebug("PA_SUBSCRIPTION_EVENT_SINK event triggered");
+            foreach(PADevice* dev, paControl->sinkList)
+                {
+                    delete dev;
+                }
+            paControl->sinkList.clear();
+            paControl->addRef();
+            pa_context_get_sink_info_list(c, pa_sinklist_cb, NULL);
+            break;
+        case PA_SUBSCRIPTION_EVENT_SOURCE:
+            qDebug("PA_SUBSCRIPTION_EVENT_SOURCE event triggered");
+            foreach(PADevice* dev, paControl->sourceList)
+                {
+                    delete dev;
+                }
+            paControl->sourceList.clear();
+            paControl->addRef();
+            pa_context_get_source_info_list(c, pa_sourcelist_cb, NULL);
+            break;
+        case PA_SUBSCRIPTION_EVENT_MODULE:
+            qDebug("PA_SUBSCRIPTION_EVENT_MODULE event triggered");
+            foreach(PAModule* dev, paControl->moduleList)
+                {
+                    delete dev;
+                }
+            paControl->moduleList.clear();
+            paControl->addRef();
+            pa_context_get_module_info_list(c, pa_modulelist_cb, NULL);
+            break;
+        }
+}
+
+PAControl::PAControl(QObject *parent)
+    :QObject(parent) {
+    paControl = this;
+    status = SUCCESS;
+    m_paState=false;
+
+    paInit();
+}
+
+PAControl::~PAControl()
+{
+    paCleanup();
+
+    foreach (PADevice *source, sourceList) {
+        qDebug() << QString("delete source");
+        delete source;
+    }
+    foreach (PADevice *sink, sinkList) {
+        qDebug() << QString("delete sink");
+        delete sink;
+    }
+    foreach (PAModule *module, moduleList) {
+        qDebug() << QString("delete module");
+        delete module;
+    }
+
+    qDebug() << QString("~PAControl()");
+    paControl = NULL;
+}
+
+PAControl* PAControl::instance()
+{
+    return paControl;
+}
+
+void PAControl::paInit() {
+    qDebug() << "paInit()";
+
+    // Create a mainloop API and connection to the default server
+    if(!pa_ml)
+        pa_ml = pa_glib_mainloop_new(NULL);
+    pa_ctx = pa_context_new(
+                            pa_glib_mainloop_get_api(pa_ml),
+                            "com.tizen.hfp");
+
+    // This function connects to the pulse server
+    if (pa_context_connect(pa_ctx,
+                           NULL,
+                           PA_CONTEXT_NOFAIL, NULL) < 0)
+        {
+            qCritical("PulseAudioService: pa_context_connect() failed");
+            paCleanup();
+            return;
+        }
+
+    m_refCounter = 0;
+    m_connected = false;
+    m_audioRouted = false;
+    m_btSourceReady =false;
+    m_btSinkReady = false;
+
+    pa_context_set_state_callback(pa_ctx, pa_state_cb, NULL);
+}
+
+void PAControl::paCleanup() {
+    qDebug() << "paCleanup()";
+    if(pa_ctx)
+        pa_context_disconnect(pa_ctx);
+    if(pa_ctx)
+        pa_context_unref(pa_ctx);
+}
+
+void PAControl::setState(bool state)
+{
+    m_paState = state;
+    if(state == false)
+        {
+            emit paFailed();
+        }
+}
+
+void PAControl::addRef()
+{
+    m_refCounter++;
+}
+
+void PAControl::release()
+{
+    m_refCounter--;
+    Q_ASSERT(m_refCounter >= 0);
+}
+
+void PAControl::reconnect() {
+    qDebug() << "Pulseaudio: reconnect()";
+    if(paControl)
+        delete paControl;
+    paControl = new PAControl();
+}
+
+
+
+PADevice* PAControl::findBluezSource() {
+
+    if (sourceList.size() == 0)
+        {
+            addRef();
+            pa_op = pa_context_get_source_info_list(pa_ctx, pa_sourcelist_cb, NULL);
+            if(pa_op) pa_operation_unref(pa_op);
+
+            return NULL;
+        }
+
+    foreach (PADevice *source, sourceList) {
+        QString name = source->name;
+
+        if (name.startsWith(QString("bluez_source."), Qt::CaseSensitive)) {
+            qDebug() << QString("   Matched Bluez source: ") << name;
+            return source;
+        }
+    }
+
+    qDebug() << QString("Bluez source: none found");
+    return NULL;
+}
+
+PADevice*  PAControl::findBluezSink() {
+
+    if (sinkList.size() == 0)
+        {
+            addRef();
+            pa_op = pa_context_get_sink_info_list(pa_ctx, pa_sinklist_cb, NULL);
+            if(pa_op) pa_operation_unref(pa_op);
+
+            return NULL;
+        }
+
+    foreach (PADevice *sink, sinkList) {
+        QString name = sink->name;
+
+        if (name.startsWith(QString("bluez_sink."), Qt::CaseSensitive)) {
+            qDebug() << QString("   Matched Bluez sink: ") << name;
+            return sink;
+        }
+    }
+
+    qDebug() << QString("Bluez sink: none found");
+    return NULL;
+}
+
+PADevice* PAControl::findAlsaSource(QString alsasource) {
+
+    if (sourceList.size() == 0)
+        {
+            addRef();
+            pa_op = pa_context_get_source_info_list(pa_ctx, pa_sourcelist_cb, NULL);
+            if(pa_op) pa_operation_unref(pa_op);
+
+            return NULL;
+        }
+
+    foreach (PADevice *source, sourceList) {
+        qDebug() << QString("Alsa source: ") << source->name;
+        QString name = source->name;
+
+        if (!alsasource.isNull() && !alsasource.isEmpty())
+            {
+                // if alsa source name is provided
+                if (alsasource == name)
+                    {
+                        qDebug() << QString("   Matched Alsa source: ") << name;
+                        return source;
+                    }
+            } else if (name.startsWith(QString("alsa_input."), Qt::CaseSensitive) &&
+                       name.endsWith(QString("analog-stereo"), Qt::CaseSensitive) &&
+                       !name.contains(QString("timb"))) {
+            // this is default behavior, it will try to look up one
+            qDebug() << QString("   Matched Alsa source: ") << name;
+            return source;
+        }
+    }
+
+    qDebug() << QString("Alsa source: none found");
+    return NULL;
+}
+
+PADevice*  PAControl::findAlsaSink(QString alsasink) {
+
+    if (sinkList.size() == 0)
+        {
+            addRef();
+            pa_op = pa_context_get_sink_info_list(pa_ctx, pa_sinklist_cb, NULL);
+            if(pa_op) pa_operation_unref(pa_op);
+
+            return NULL;
+        }
+
+    foreach (PADevice *sink, sinkList) {
+        qDebug() << QString("Alsa sink: ") << sink->name;
+        QString name = sink->name;
+
+        if (!alsasink.isNull() && !alsasink.isEmpty())
+            {
+                // if alsa sink name is provided
+                if (alsasink == name)
+                    {
+                        qDebug() << QString("   Matched Alsa sink: ") << name;
+                        return sink;
+                    }
+            } else if (name.startsWith(QString("alsa_output."), Qt::CaseSensitive) &&
+                       name.endsWith(QString("analog-stereo"), Qt::CaseSensitive) &&
+                       !name.contains(QString("timb"))) {
+            // this is default behavior, it will try to look up one
+            qDebug() << QString("   Matched Alsa sink: ") << name;
+            return sink;
+        }
+    }
+
+    qDebug() << QString("Alsa sink: none found");
+    return NULL;
+}
+
+PAModule*  PAControl::findModule(QString name, QString pattern) {
+
+    if (moduleList.size() == 0)
+        {
+            addRef();
+            pa_op = pa_context_get_module_info_list(pa_ctx, pa_modulelist_cb, NULL);
+            if(pa_op) pa_operation_unref(pa_op);
+
+            return NULL;
+        }
+
+    foreach (PAModule *module, moduleList) {
+        if (module->name.contains(name) && module->argument.contains(pattern)) {
+            qDebug() << QString("   Matched module: ") << module->name;
+            qDebug() << QString("   argument: ") << module->argument;
+            return module;
+        }
+    }
+
+    qDebug() << QString("Module: none found");
+    return NULL;
+}
+
+QList<PAModule*> PAControl::getAllModules()
+{
+    if (moduleList.size() == 0)
+        {
+            addRef();
+            pa_op = pa_context_get_module_info_list(pa_ctx, pa_modulelist_cb, NULL);
+            if(pa_op) pa_operation_unref(pa_op);
+        }
+
+    return moduleList;
+}
+
+void PAControl::addSource(PADevice* device)
+{
+    foreach(PADevice* dev, sourceList)
+        {
+            if(dev->name == device->name)
+                {
+                    delete device;
+                    return; /// already exists
+                }
+        }
+
+    sourceList.append(device);
+    emit sourceAppeared(device);
+}
+
+void PAControl::addSink(PADevice* device)
+{
+    foreach(PADevice* dev, sinkList)
+        {
+            if(dev->name == device->name)
+                {
+                    delete device;
+                    return; /// already exists
+                }
+        }
+
+    sinkList.append(device);
+    emit sinkAppeared(device);
+}
+
+void PAControl::addModule(PAModule *module)
+{
+    foreach(PAModule* dev, moduleList)
+        {
+            if(dev->name == module->name && dev->index == module->index)
+                {
+                    delete module;
+                    return; /// already exists
+                }
+        }
+
+    moduleList.append(module);
+    emit moduleAppeared(module);
+}
+
+void PAControl::routeSourceWithSink(PADevice *source, PADevice *sink) {
+    qDebug() << "Routing from " << source->name << " to " << sink->name;
+
+    if (source != NULL && sink != NULL) {
+        QString arg = "source=\"" % source->name % "\" sink=\"" % sink->name % "\"";
+
+        pa_op = pa_context_load_module(pa_ctx, "module-loopback", arg.toAscii().data(), module_callback, NULL);
+        if(pa_op) pa_operation_unref(pa_op);
+
+        qDebug() << QString("load-module module-loopback ") << arg;        
+    }
+}
+
+void PAControl::toggleMuteSource(PADevice *source, bool isMute) {
+
+    if (source != NULL) {
+        pa_op =pa_context_set_source_mute_by_name(pa_ctx, source->name.toAscii().data(), isMute, operation_callback, NULL);
+        if(pa_op) pa_operation_unref(pa_op);
+
+        qDebug() << QString("set source mute ") << source->name << QString(" to ") << isMute;
+    }
+}
+
+void  PAControl::unloadModule(PAModule* module) {
+
+    if (module != NULL && module->index >= 0) {
+        pa_op = pa_context_unload_module(pa_ctx, module->index, operation_callback, NULL);
+        if(pa_op) pa_operation_unref(pa_op);
+        qDebug() << QString("unload-module module-loopback ") <<  QString(module->name) << QString(" at index ") << module->index;
+    }
+}
+
+PAStatus PAControl::getStatus() {
+    return this->status;
+}
+
+void PAControl::setErrorMsg(QString msg) {
+    if (msg != NULL)
+        {
+            this->status = ERROR;
+            this->errorMsg = msg;
+        }
+}
+
+QString PAControl::getErrorMsg() {
+    return this->errorMsg;
+}
+
+void PAControl::onSourceAppeared(PADevice* device) {
+
+    CallManager *cm = ManagerProxy::instance()->callManager();
+    if (!cm || !cm->isValid())
+        return;
+
+    if(cm->callCount() == 0)
+        {
+            qDebug() << "no calls active, ignore";
+            return;
+        }
+
+    if(device->name.contains("bluez_source"))
+        {
+            m_btSourceReady = true;
+        }
+
+    if(!m_audioRouted && m_btSourceReady && m_btSinkReady)
+        {
+            qDebug() << QString("Route microphone and speakers");
+            routeAudio();
+        }
+}
+
+void PAControl::onSinkAppeared(PADevice* device) {
+    CallManager *cm = ManagerProxy::instance()->callManager();
+    if (!cm || !cm->isValid())
+        return;
+
+    if(cm->callCount() == 0)
+        {
+            qDebug() << "no calls active, ignore";
+            return;
+        }
+
+    if((device)->name.contains("bluez_sink"))
+        {
+            m_btSinkReady = true;
+        }
+
+    if(!m_audioRouted && m_btSourceReady && m_btSinkReady)
+        {
+            qDebug() << QString("Route microphone and speakers");
+            routeAudio();
+        }
+}
+
+void PAControl::routeAudio()
+{
+    PADevice* source;
+    PADevice* sink;
+    PADevice* mic;
+    PADevice* speaker;
+
+    if (m_audioRouted)
+        {
+            qDebug() << QString("Audio already routed");
+            return;
+        }
+
+    if (m_refCounter > 0)
+        {
+            qDebug() << "PA callback not finished, retry";
+            QTimer::singleShot(1000, this, SLOT(routeAudio()));
+            return;
+        }
+
+    qDebug() << QString("Route audio");
+    source = paControl->findBluezSource();
+    sink = paControl->findBluezSink();
+
+    if(source == NULL || sink == NULL) {
+        qDebug() << QString("Bluez source or speaker not found");
+        return;
+    }
+
+    QString alsaSourceName = MGConfItem(QString("/apps/dialer/alsasource")).value().toString();
+    QString alsaSinkName = MGConfItem(QString("/apps/dialer/alsasink")).value().toString();
+
+    mic = paControl->findAlsaSource(alsaSourceName);
+    speaker = paControl->findAlsaSink(alsaSinkName);
+
+    if (mic != NULL and speaker != NULL)
+        {
+            paControl->routeSourceWithSink(source, speaker);
+            paControl->routeSourceWithSink(mic, sink);
+            qDebug() << QString("Create loopback modules successful");
+        }
+    else {
+        qDebug() << QString("Alsa source and speaker not found");
+    }
+
+    m_audioRouted = true;
+    disconnect(this, SIGNAL(sourceAppeared(PADevice*)));
+    disconnect(this, SIGNAL(sinkAppeared(PADevice*)));
+}
+
+void PAControl::unrouteAudio()
+{
+    qDebug() << QString("Unroute audio");
+    PAControl* paControl = PAControl::instance();
+
+    QList<PAModule*> mlist = paControl->getAllModules();
+    foreach(PAModule *module, mlist)
+        {
+            if (module->name.contains("module-loopback") &&
+                module->argument.contains("bluez") &&
+                module->argument.contains("alsa")) {
+                qDebug() << QString("Found loopback module, index: ") << module->index;
+                paControl->unloadModule(module);
+                qDebug() << QString("Remove loopback module successful");
+            }
+        }
+
+    m_audioRouted = false;
+    m_btSourceReady = false;
+    m_btSinkReady = false;
+}
+
+void PAControl::onCallsChanged()
+{
+    TRACE;
+
+    CallManager *cm = ManagerProxy::instance()->callManager();
+    if (!cm || !cm->isValid())
+        {
+        qDebug("no call manager.  Aborting");
+            return;
+        }
+
+    if (cm->dialingCall() || cm->activeCall() || cm->callCount() > 1)
+        {
+            // new call is dialing or phone is picked up
+            qDebug() << "PAControl: new call in progress";
+
+            if(m_audioRouted)
+                {
+                    qDebug() << QString("Audio already routed");
+                    return;
+                }
+
+            if(m_btSourceReady && m_btSinkReady)
+                {
+                    qDebug() << QString("Route microphone and speakers");
+                    routeAudio();
+                }
+            else
+                {
+                    if(this->findBluezSource() != NULL && this->findBluezSink() != NULL)
+                        {
+                            // bt source and sink exists
+                            m_btSourceReady = true;
+                            m_btSinkReady = true;
+                            qDebug() << QString("Route microphone and speakers");
+                            routeAudio();
+                        }
+                    else
+                        {
+                            //no bt source or sink yet, let's wait until source and sink appears
+                            m_btSourceReady = false;
+                            m_btSinkReady = false;
+                            connect(this, SIGNAL(sourceAppeared(PADevice*)), this, SLOT(onSourceAppeared(PADevice*)));
+                            connect(this, SIGNAL(sinkAppeared(PADevice*)), this, SLOT(onSinkAppeared(PADevice*)));
+                            qDebug() << QString("Audio not routed yet, wait for bt source and sinks");
+                        }
+                }
+        }
+    else if (cm->callCount() <= 0)
+        {
+            qDebug() << QString("no more ofono calls");
+            if(m_audioRouted)
+                {
+                    qDebug() << QString("Unroute microphone and speakers");
+                    unrouteAudio();
+                }
+        }
+}
+
+/* Local Variables:      */
+/* mode:c++              */
+/* c-basic-offset:4      */
+/* indent-tabs-mode: nil */
+/* End:                  */
+
diff --git a/src/pacontrol.h b/src/pacontrol.h
new file mode 100644 (file)
index 0000000..1ae7d18
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * hfdialer - Hands Free Voice Call Manager
+ * Copyright (c) 2012, Intel Corporation.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0.  The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ */
+
+#ifndef PACONTROL_H
+#define PACONTROL_H
+#include <pulse/context.h>
+#include <pulse/pulseaudio.h>
+#include <pulse/glib-mainloop.h>
+#include <QObject>
+
+class PADevice {
+public:
+    QString name;
+    int index;
+    QString description;
+};
+
+class PAModule {
+public:
+    QString name;
+    int index;
+    QString argument;
+};
+
+enum PAStatus {
+    SUCCESS = 0,
+    ERROR = 1,
+};
+
+class PAControl : public QObject
+{
+    Q_OBJECT;
+public:
+    PAControl(QObject *parent = 0);
+    ~PAControl();
+
+    static PAControl* instance();
+
+    void reconnect();
+    PADevice* findBluezSource();
+    PADevice* findBluezSink();
+    PADevice* findAlsaSource(QString alsasource);
+    PADevice* findAlsaSink(QString alsasink);
+    PAModule* findModule(QString name, QString pattern);
+    QList<PAModule*> getAllModules();
+    void routeSourceWithSink(PADevice *source, PADevice *sink);
+
+    void unloadModule(PAModule* module);
+    void toggleMuteSource(PADevice *source, bool isMute);
+
+    PAStatus getStatus();
+    void setErrorMsg(QString msg);
+    QString getErrorMsg();
+
+    void setState(bool state);
+    void addRef();
+    void release();
+
+    void addSource(PADevice* device);
+    void addSink(PADevice* device);
+    void addModule(PAModule* module);
+
+    QList<PADevice*> sourceList;
+    QList<PADevice*> sinkList;
+    QList<PAModule*> moduleList;
+
+public Q_SLOTS:
+    void routeAudio();
+    void unrouteAudio();
+
+Q_SIGNALS:
+    void sourceAppeared(PADevice* device);
+    void sinkAppeared(PADevice* device);
+    void moduleAppeared(PAModule* device);
+    void paFailed();
+
+private Q_SLOTS:
+    void onSourceAppeared(PADevice* device);
+    void onSinkAppeared(PADevice* device);
+    void onCallsChanged();
+
+private:
+    pa_operation *pa_op;
+    pa_context *pa_ctx;
+    PAStatus status;
+    QString errorMsg;
+
+    void paInit();
+    void paCleanup();
+
+
+    bool m_paState;
+    int  m_refCounter;
+    bool m_connected;
+    bool m_audioRouted;
+    bool m_btSourceReady;
+    bool m_btSinkReady;
+};
+
+#endif // PACONTROL_H
+
+/* Local Variables:      */
+/* mode:c++              */
+/* c-basic-offset:4      */
+/* indent-tabs-mode: nil */
+/* End:                  */
diff --git a/src/qmlcallitem.cpp b/src/qmlcallitem.cpp
new file mode 100644 (file)
index 0000000..67355e9
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * dialer - Declarative Dialer UX Main Window.
+ * Copyright (c) 2011, Tom Swindell.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0.  The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ */
+
+#include "common.h"
+#include "qmlcallitem.h"
+
+class QMLCallItemPrivate
+{
+public:
+    CallItem *proxy;
+};
+
+QMLCallItem::QMLCallItem(CallItem *proxy, QObject *parent)
+    : QObject(parent), d(new QMLCallItemPrivate)
+{
+    TRACE;
+    d->proxy = proxy;
+    
+    QObject::connect(proxy->callProxy(), SIGNAL(stateChanged()), SLOT(onStateChanged()));
+}
+
+QMLCallItem::~QMLCallItem()
+{
+    TRACE;
+    delete this->d;
+}
+
+CallItem* QMLCallItem::proxy() const
+{
+    TRACE;
+    return d->proxy;
+}
+
+QString QMLCallItem::msisdn() const
+{
+    TRACE;
+    if (d->proxy->callProxy())
+        return d->proxy->callProxy()->lineID();
+    return QString();
+}
+
+int QMLCallItem::numberLen() const
+{
+    TRACE;
+    QString number = msisdn();
+    return number.size();
+}
+
+QString QMLCallItem::name() const
+{
+    TRACE;
+    if (d->proxy->callProxy())
+        return d->proxy->callProxy()->name();
+    return QString();
+}
+
+QString QMLCallItem::state() const
+{
+    TRACE;
+    if (d->proxy->callProxy())
+        return d->proxy->callProxy()->state();
+    return QString();
+}
+
+QString QMLCallItem::reason() const
+{
+    TRACE;
+    if (d->proxy->callProxy())
+        return d->proxy->callProxy()->reason();
+    return QString();
+}
+
+QDateTime QMLCallItem::startedAt() const
+{
+    TRACE;
+    if (d->proxy->callProxy())
+        return d->proxy->callProxy()->startTime();
+    return QDateTime();
+}
+
+int QMLCallItem::duration() const
+{
+    TRACE;
+
+    if (d->proxy)
+    {
+        if (d->proxy->callProxy())
+               return d->proxy->callProxy()->duration();
+    }
+    return 0;
+}
+
+bool QMLCallItem::isMultiparty() const
+{
+    TRACE;
+    if (d->proxy->callProxy())
+        return d->proxy->callProxy()->multiparty();
+    return false;
+}
+
+void QMLCallItem::answer()
+{
+    TRACE;
+    if (d->proxy->callProxy())
+        d->proxy->callProxy()->answer();
+}
+
+void QMLCallItem::deflect(const QString &msisdn)
+{
+    TRACE;
+    if (d->proxy->callProxy())
+        d->proxy->callProxy()->deflect(msisdn);
+}
+
+void QMLCallItem::hangup()
+{
+    TRACE;
+    if (d->proxy->callProxy())
+        d->proxy->callProxy()->hangup();
+}
+
+void QMLCallItem::onStateChanged()
+{
+    TRACE;
+    emit this->stateChanged(d->proxy->callProxy()->state());
+}
+
+/* Local Variables:      */
+/* mode:c++              */
+/* c-basic-offset:4      */
+/* indent-tabs-mode: nil */
+/* End:                  */
diff --git a/src/qmlcallitem.h b/src/qmlcallitem.h
new file mode 100644 (file)
index 0000000..7ccea73
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * dialer - CallItem Declarative Proxy Implementation.
+ * Copyright (c) 2011, Tom Swindell.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0.  The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ */
+
+#ifndef QMLCALLITEM_H
+#define QMLCALLITEM_H
+
+#include "callitem.h"
+
+#include <QObject>
+#include <QDateTime>
+
+class QMLCallItem : public QObject
+{
+    Q_OBJECT;
+
+    Q_PROPERTY(QString msisdn READ msisdn);
+    Q_PROPERTY(QString name READ name);
+    Q_PROPERTY(QString state READ state NOTIFY stateChanged);
+    Q_PROPERTY(QString reason READ reason);
+    Q_PROPERTY(int numberLen READ numberLen);
+    Q_PROPERTY(QDateTime startedAt READ startedAt);
+    Q_PROPERTY(int duration READ duration);
+    Q_PROPERTY(bool isMultiparty READ isMultiparty);
+
+public:
+    explicit QMLCallItem(CallItem *proxy, QObject *parent = 0);
+    ~QMLCallItem();
+
+    QString      msisdn         () const;
+    int                numberLen       () const;
+    QString      name           () const;
+    QString      state          () const;
+
+    QDateTime    startedAt      () const;
+    int          duration       () const;
+
+    QString      reason         () const;
+    bool         isMultiparty   () const;
+
+    CallItem*    proxy          () const;
+
+Q_SIGNALS:
+    void stateChanged   (const QString &state);
+
+public Q_SLOTS:
+    void answer         ();
+    void deflect        (const QString &msisdn);
+    void hangup         ();
+
+protected Q_SLOTS:
+    void onStateChanged ();
+
+private:
+    class QMLCallItemPrivate *d;
+
+    Q_DISABLE_COPY(QMLCallItem);
+};
+
+#endif // QMLCALLITEM_H
+
+/* Local Variables:      */
+/* mode:c++              */
+/* c-basic-offset:4      */
+/* indent-tabs-mode: nil */
+/* End:                  */
diff --git a/src/qmldialer.cpp b/src/qmldialer.cpp
new file mode 100644 (file)
index 0000000..84d117c
--- /dev/null
@@ -0,0 +1,285 @@
+/*
+ * dialer - Declarative Dialer UX Main Window.
+ * Copyright (c) 2011, Tom Swindell.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0.  The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ */
+
+#include "common.h"
+#include "qmldialer.h"
+#include "dialerapplication.h"
+#include "dialercontext.h"
+#include "callmanager.h"
+#include "managerproxy.h"
+
+#define CONFIG_KEY_VOICEMAIL_NUMBER "/apps/dialer/voicemail/number"
+
+class QMLDialerPrivate
+{
+public:
+    QMLDialerPrivate()
+        : currentCall(NULL)
+    { TRACE; }
+
+    QMLCallItem *currentCall;
+};
+
+QMLDialer::QMLDialer(QObject *parent)
+    : QObject(parent), d(new QMLDialerPrivate)
+{
+    TRACE;
+    CallManager *cm = ManagerProxy::instance()->callManager();
+
+    this->connectAll();
+    connect(ManagerProxy::instance(), SIGNAL(callManagerChanged()), SLOT(onCallManagerChanged()));
+    connect(cm, SIGNAL(callCountChanged()), SIGNAL(callCountChanged(cm->callCount())));    
+
+    if(cm && cm->activeCall()) d->currentCall = new QMLCallItem(cm->activeCall(), this);
+}
+
+QMLDialer::~QMLDialer()
+{
+    TRACE;
+    delete this->d;
+}
+
+QString QMLDialer::mailbox() const
+{
+    TRACE;
+
+    if(ManagerProxy::instance()->voicemail()->isConnected())
+        {
+            return ManagerProxy::instance()->voicemail()->mailbox();
+        }
+
+    // Fall back to GConf voicemail setting.
+    return MGConfItem(CONFIG_KEY_VOICEMAIL_NUMBER).value().toString();
+}
+
+bool QMLDialer::modemOnline()
+{
+    if(ManagerProxy::instance()->modem() &&
+       ManagerProxy::instance()->modem()->isValid())
+        {
+            return ManagerProxy::instance()->modem()->powered();
+        }
+
+    return false;
+}
+
+void QMLDialer::setMailbox(const QString &number)
+{
+    TRACE;
+
+    if(ManagerProxy::instance()->voicemail()->isConnected())
+        {
+            ManagerProxy::instance()->voicemail()->setMailbox(number);
+            return;
+        }
+
+    // Fall back to GConf voicemail setting.
+    MGConfItem(CONFIG_KEY_VOICEMAIL_NUMBER).set(number);
+}
+
+void QMLDialer::setModemOnline(bool online)
+{
+    if (ManagerProxy::instance() && ManagerProxy::instance()->modem())
+        {
+            if(ManagerProxy::instance()->modem()->isValid())
+                {
+                    ManagerProxy::instance()->modem()->setPowered(online);
+                    return;
+                }
+        }
+}
+
+QString QMLDialer::speedDial(int index) const
+{
+    TRACE;
+    return MGConfItem(QString("/apps/dialer/speeddial/%1").arg(index)).value().toString();
+}
+
+void QMLDialer::setSpeedDial(int index, const QString &number)
+{
+    TRACE;
+    MGConfItem(QString("/apps/dialer/speeddial/%1").arg(index)).set(number);
+}
+
+QMLCallItem* QMLDialer::currentCall() const
+{
+    TRACE;
+    return d->currentCall;
+}
+
+int QMLDialer::callCount()
+{
+    TRACE;
+    CallManager *cm = ManagerProxy::instance()->callManager();
+    return cm->callCount(); 
+}
+
+
+void QMLDialer::dial(const QString &msisdn)
+{
+    TRACE;
+    CallManager *cm = ManagerProxy::instance()->callManager();
+    if (cm && cm->isValid())
+        {
+            cm->dial(msisdn);
+        }
+       
+}
+
+void QMLDialer::hangupAll()
+{
+    TRACE;
+    CallManager *cm = ManagerProxy::instance()->callManager();
+    if ((cm && cm->isValid()))
+        { 
+            cm->hangupAll();
+        }
+}
+
+void QMLDialer::silenceRingtone()
+{
+    if(ManagerProxy::instance()->volumeManager()->isConnected())
+        {
+            qDebug() << "Attempting to mute call with volume manager.";
+            ManagerProxy::instance()->volumeManager()->setMuted(true);
+        }
+    else if(d->currentCall)
+        {
+            qDebug() << "Attempting to mute call with call item signaller.";
+            d->currentCall->proxy()->silenceRingtone();
+        }
+    else
+        {
+            qDebug() << "Couldn't decide how to mute ringtone!";
+        }
+}
+
+void QMLDialer::sendTones(const QString &tones)
+{
+    TRACE;
+    CallManager *cm = ManagerProxy::instance()->callManager();
+    if (cm && cm->isValid())
+        cm->sendTones(tones);
+}
+
+void QMLDialer::transfer()
+{
+    TRACE;
+    CallManager *cm = ManagerProxy::instance()->callManager();
+    if (cm && cm->isValid())
+        cm->transfer();
+}
+
+void QMLDialer::swapCalls()
+{
+    TRACE;
+    CallManager *cm = ManagerProxy::instance()->callManager();
+    if (cm && cm->isValid())
+        cm->swapCalls();
+}
+
+void QMLDialer::releaseAndAnswer()
+{
+    TRACE;
+    CallManager *cm = ManagerProxy::instance()->callManager();
+    if (cm && cm->isValid())
+        cm->releaseAndAnswer();
+}
+
+void QMLDialer::holdAndAnswer()
+{
+    TRACE;
+    CallManager *cm = ManagerProxy::instance()->callManager();
+    if (cm && cm->isValid())
+        cm->holdAndAnswer();
+}
+
+void QMLDialer::createMultiparty()
+{
+}
+
+void QMLDialer::hangupMultiparty()
+{
+}
+
+void QMLDialer::privateChat(const QMLCallItem &call)
+{
+    TRACE;
+    CallManager *cm = ManagerProxy::instance()->callManager();
+    if (cm && cm->isValid())
+        cm->privateChat(*call.proxy());
+}
+
+void QMLDialer::onCallsChanged()
+{
+    TRACE;
+    CallManager *cm = ManagerProxy::instance()->callManager();
+
+    if(cm->activeCall())
+        {
+            this->onIncomingCall(cm->activeCall());
+        }
+    else
+        {      
+            delete d->currentCall;
+            d->currentCall = NULL;
+           emit callCountChanged(cm->callCount());
+        }
+
+}
+
+void QMLDialer::onIncomingCall(CallItem *callitem)
+{
+    TRACE;
+
+    d->currentCall = new QMLCallItem(callitem, this);
+    emit this->incomingCall();
+}
+
+void QMLDialer::connectAll()
+{
+    TRACE;
+    CallManager *cm = ManagerProxy::instance()->callManager();
+
+     if (ManagerProxy::instance()->modem() && ManagerProxy::instance()->modem()->isValid())
+     {
+        connect(ManagerProxy::instance()->modem(), SIGNAL(poweredChanged(bool)), this, SIGNAL(modemOnlineChanged(bool)));
+     }
+
+    if (cm && cm->isValid())
+        {
+            disconnect(cm, SIGNAL(callsChanged()));
+            disconnect(cm, SIGNAL(incomingCall(CallItem*)));
+            connect(cm, SIGNAL(callsChanged()), this, SLOT(onCallsChanged()));
+            connect(cm, SIGNAL(incomingCall(CallItem*)), SLOT(onIncomingCall(CallItem*)));
+            qDebug() << QString("CallMgr is connected");
+        }
+    else if (cm)
+        {
+            disconnect(cm, SIGNAL(connected()));
+            connect(cm, SIGNAL(connected()), this, SLOT(connectAll()));
+            qDebug() << QString("CallMgr is not yet valid");
+        }
+}
+
+void QMLDialer::onCallManagerChanged()
+{
+    TRACE;
+
+    CallManager *cm = ManagerProxy::instance()->callManager();
+    this->connectAll();
+    if(cm && cm->activeCall()) d->currentCall = new QMLCallItem(cm->activeCall(), this);
+}
+
+/* Local Variables:      */
+/* mode:c++              */
+/* c-basic-offset:4      */
+/* indent-tabs-mode: nil */
+/* End:                  */
diff --git a/src/qmldialer.h b/src/qmldialer.h
new file mode 100644 (file)
index 0000000..c7a93fa
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * dialer - Declarative Dialer Adapter.
+ * Copyright (c) 2011, Tom Swindell.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0.  The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ */
+
+#ifndef QMLDIALER_H
+#define QMLDIALER_H
+
+#include <QObject>
+
+#include "qmlcallitem.h"
+
+class QMLDialer : public QObject
+{
+    Q_OBJECT;
+
+    Q_PROPERTY(QString mailbox READ mailbox WRITE setMailbox);
+    Q_PROPERTY(QMLCallItem* currentCall READ currentCall);
+    Q_PROPERTY(bool modemOnline READ modemOnline WRITE setModemOnline NOTIFY modemOnlineChanged);
+    Q_PROPERTY(int callCount READ callCount NOTIFY callCountChanged);
+
+public:
+    explicit QMLDialer(QObject *parent = 0);
+    ~QMLDialer();
+
+    QString      mailbox        () const;
+    QMLCallItem* currentCall    () const;
+    bool         modemOnline    ();
+    int         callCount      ();
+
+Q_SIGNALS:
+    void incomingCall();
+    void outgoingCall();
+    void callCountChanged(int callCount); 
+    void modemOnlineChanged(bool powered);
+
+public Q_SLOTS:
+    void setMailbox(const QString &number);
+    void setModemOnline(bool online);
+    QString speedDial(int index) const;
+    void setSpeedDial(int index, const QString &number);
+    void dial(const QString &msisdn);
+    void hangupAll();
+    void silenceRingtone();
+    void sendTones(const QString &tones);
+    void transfer();
+    void swapCalls();
+    void releaseAndAnswer();
+    void holdAndAnswer();
+    void createMultiparty();
+    void hangupMultiparty();
+    void privateChat(const QMLCallItem &callitem);
+
+protected Q_SLOTS:
+    void connectAll();
+    void onCallsChanged();
+    void onIncomingCall(CallItem *callitem);
+    void onCallManagerChanged();
+
+private:
+    class QMLDialerPrivate *d;
+};
+
+#endif // QMLDIALER_H
+
+/* Local Variables:      */
+/* mode:c++              */
+/* c-basic-offset:4      */
+/* indent-tabs-mode: nil */
+/* End:                  */
diff --git a/src/qmlmainwindow.cpp b/src/qmlmainwindow.cpp
new file mode 100644 (file)
index 0000000..fbdf401
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * dialer - Declarative Dialer UX Main Window.
+ * Copyright (c) 2011, Tom Swindell.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0.  The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ */
+
+#include "common.h"
+#include "dialerapplication.h"
+
+#include "qmlcallitem.h"
+#include "qmldialer.h"
+
+#include "qmlmainwindow.h"
+
+#include <QtDeclarative>
+
+#define CONFIG_KEY_QML_LOAD_URL "/apps/dialer/qml/url"
+
+#define DEFAULT_QML_LOAD_URL "file:///usr/share/hfdialer/qml/main.qml"
+
+class QMLMainWindowPrivate
+{
+public:
+    QMLMainWindowPrivate()
+        : adapter(NULL),
+          engine(NULL),
+          component(NULL),
+          item(NULL)
+    { TRACE; }
+
+    QMLDialer               *adapter;
+    QDeclarativeEngine      *engine;
+    QDeclarativeView        *qdv; 
+    
+    QDeclarativeComponent   *component;
+    QDeclarativeItem        *item;
+};
+
+static void registerDataTypes()
+{
+    TRACE;
+    qmlRegisterType<QMLDialer>("com.hfdialer", 1, 0, "Dialer");
+
+    qmlRegisterUncreatableType<QMLCallItem>("com.hfdialer", 1, 0, "CallItem", "");
+}
+
+QMLMainWindow::QMLMainWindow(QWidget *parent)
+    : QDeclarativeView(parent),
+      d(new QMLMainWindowPrivate)
+{
+    TRACE;
+    DialerApplication *da = DialerApplication::instance();
+    CallManager *cm = ManagerProxy::instance()->callManager();
+
+    setResizeMode(QDeclarativeView::SizeRootObjectToView);
+
+    this->setWindowTitle(qtTrId("xx_window"));
+
+    this->setupUi();
+
+    connect(this->engine(), SIGNAL(quit()), this, SLOT(closeEvent()));
+}
+
+QMLMainWindow::~QMLMainWindow()
+{
+    TRACE;
+    delete this->d;
+}
+
+QMLMainWindow* QMLMainWindow::instance()
+{
+    TRACE;
+    static QMLMainWindow *_instance = NULL;
+
+    if(_instance == NULL)
+        {
+            registerDataTypes();
+            _instance = new QMLMainWindow;
+        }
+
+    return _instance;
+}
+
+
+QMLMainWindow* QMLMainWindow::instanceP(QWidget* parent)
+{
+    TRACE;
+    static QMLMainWindow *_instance = NULL;
+
+    if(_instance == NULL)
+        {
+            registerDataTypes();
+            _instance = new QMLMainWindow(parent);
+        }
+
+    return _instance;
+}
+
+void QMLMainWindow::setupUi()
+{
+    TRACE;
+    MGConfItem qmlUrl(CONFIG_KEY_QML_LOAD_URL);
+
+    d->engine = new QDeclarativeEngine(this);
+
+    d->engine->rootContext()->setContextProperty("controller", this); //TODO: Remove
+    this->setSource(QUrl::fromLocalFile("/usr/share/hfdialer/qml/main.qml"));
+    d->component = new QDeclarativeComponent(d->engine, this);
+    d->component->loadUrl(qmlUrl.value(DEFAULT_QML_LOAD_URL).toString());
+
+    if(d->component->isError())
+        {
+            qCritical() << "Failed to load QML Component:" << d->component->errorString();
+            return;
+        }
+
+    d->item = qobject_cast<QDeclarativeItem*>(d->component->create());
+    if(!d->item)
+        {
+            qCritical() << "Failed to create item from component!";
+            return;
+        }
+}
+
+void QMLMainWindow::tryToShow()
+{
+    TRACE;
+     
+    if (d->component->isReady())
+        {
+            DialerApplication *da = DialerApplication::instance();
+           da->setActiveWindow(this);
+            da->activeWindow()->show();
+            da->activeWindow()->activateWindow();
+            this->show();
+        }
+}
+void QMLMainWindow::closeEvent() 
+{
+    TRACE;
+    emit closeWindow();
+}
+
+void QMLMainWindow::onGeometryChanged()
+{
+    TRACE;
+}
+
+void QMLMainWindow::setAdapter(QMLDialer *adapter)
+{
+    TRACE;
+    d->adapter = adapter;
+}
+
+/* Local Variables:      */
+/* mode:c++              */
+/* c-basic-offset:4      */
+/* indent-tabs-mode: nil */
+/* End:                  */
diff --git a/src/qmlmainwindow.h b/src/qmlmainwindow.h
new file mode 100644 (file)
index 0000000..62a07b8
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * dialer - Declarative Dialer UX Main Window.
+ * Copyright (c) 2011, Tom Swindell.
+ *
+ * This program is licensed under the terms and conditions of the
+ * Apache License, version 2.0.  The full text of the Apache License is at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ */
+
+#ifndef QMLMAINWINDOW_H
+#define QMLMAINWINDOW_H
+
+#include <QDeclarativeView>
+#include <QDeclarativeComponent>
+#include "qmldialer.h"
+#include "callitem.h"
+
+class QMLMainWindowPrivate;
+
+class QMLMainWindow : public QDeclarativeView 
+{
+    Q_OBJECT;
+
+public:
+    static   QMLMainWindow* instance();
+    static   QMLMainWindow* instanceP(QWidget* parent);
+    ~QMLMainWindow();
+
+Q_SIGNALS:
+    void closeWindow();
+
+public Q_SLOTS:
+    void tryToShow();
+    void closeEvent(); 
+    void setAdapter(QMLDialer *adapter); //TODO: Refactor out
+
+protected Q_SLOTS:
+    void setupUi();
+
+    void onGeometryChanged();
+
+private:
+    explicit QMLMainWindow(QWidget *parent = 0);
+    QMLMainWindowPrivate *d;
+    QDeclarativeView qv;
+    Q_DISABLE_COPY(QMLMainWindow)
+};
+
+#endif // QMLMAINWINDOW_H
+
+/* Local Variables:      */
+/* mode:c++              */
+/* c-basic-offset:4      */
+/* indent-tabs-mode: nil */
+/* End:                  */
diff --git a/src/src.pro b/src/src.pro
new file mode 100644 (file)
index 0000000..23d6e89
--- /dev/null
@@ -0,0 +1,90 @@
+TARGET = dialer
+TEMPLATE = app
+QT += dbus declarative
+CONFIG += qdbus mobility qt-mobility link_pkgconfig network
+PKGCONFIG += libpulse-mainloop-glib
+MOBILITY += contacts multimedia
+MOC_DIR = .moc
+OBJECTS_DIR = .obj
+MGEN_OUTDIR = .gen
+
+DEFINES += DBUS_SERVICE_PATH=\\\"/com/${QMAKE_TARGET}\\\"
+DEFINES += DBUS_SERVICE=\\\"com.${QMAKE_TARGET}\\\"
+
+verbose {
+    DEFINES += VERBOSE 
+}
+
+wayland {
+    PKGCONFIG += mlite-wayland ofono-qt-wayland
+}
+xlib{
+    PKGCONFIG += mlite-xlib ofono-qt-xlib
+}
+!xlib:!wayland{
+    PKGCONFIG += mlite ofono-qt
+}
+
+target.path += $$INSTALL_ROOT/usr/bin 
+
+SOURCES += main.cpp \
+    dialercontext.cpp \
+    dialerapplication.cpp \
+    managerproxy.cpp \
+    modemproxy.cpp \
+    networkproxy.cpp \
+    callitem.cpp \
+    callproxy.cpp \
+    callmanager.cpp \
+    dbustypes.cpp \
+    pacontrol.cpp \
+    qmlmainwindow.cpp \
+    qmldialer.cpp \
+    qmlcallitem.cpp \
+       dbusdialeradapter.cpp \
+       voicecall_interface.cpp \
+       operator_interface.cpp \
+       hfdialer_adaptor.cpp \
+       manager_interface.cpp \
+       modem_interface.cpp
+
+HEADERS += \
+    common.h \
+    dialercontext.h \
+    dialerapplication.h \
+    managerproxy.h \
+    modemproxy.h \
+    networkproxy.h \
+    callitem.h \ 
+    callproxy.h \
+    callmanager.h \
+    dbustypes.h \
+    pacontrol.h \
+    $$MODEL_HEADERS \
+    $$STYLE_HEADERS \
+       voicecall_interface.h \
+       operator_interface.h \
+       hfdialer_adaptor.h \
+       manager_interface.h \
+       modem_interface.h \
+    qmlmainwindow.h \
+    qmldialer.h \
+    qmlcallitem.h \
+    dbusdialeradapter.h
+
+
+
+system(qdbusxml2cpp -p voicecall_interface dbus/org.ofono.voicecall.xml)
+system(qdbusxml2cpp -p operator_interface dbus/org.ofono.operator.xml)
+system(qdbusxml2cpp -a hfdialer_adaptor dbus/com.hfdialer.xml)
+system(qdbusxml2cpp -i dbustypes.h -p manager_interface dbus/org.ofono.manager.xml)
+system(qdbusxml2cpp -i dbustypes.h -p modem_interface dbus/org.ofono.modem.xml)
+
+MAKE_CLEAN += $$OBJECTS_DIR/*.o
+MAKE_DISTCLEAN += \
+    $$MOC_DIR/* $$MOC_DIR \
+    $$OBJECTS_DIR/* $$OBJECTS_DIR \
+    $$MGEN_OUTDIR/* $$MGEN_OUTDIR \
+
+# Install
+INSTALLS += target