initial commit
authorBrian Jones <brian.j.jones@intel.com>
Tue, 27 Mar 2012 23:54:16 +0000 (16:54 -0700)
committerBrian Jones <brian.j.jones@intel.com>
Tue, 27 Mar 2012 23:54:16 +0000 (16:54 -0700)
95 files changed:
LICENSE [new file with mode: 0644]
README [new file with mode: 0644]
common.pri [new file with mode: 0644]
dialer-keepalive.sh [new file with mode: 0755]
dialer.desktop [new file with mode: 0644]
dialer.service [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-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]
makedist [new file with mode: 0755]
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.tizen.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/policy/audio-resource.h [new file with mode: 0644]
src/policy/resource-set.h [new file with mode: 0644]
src/policy/resource.h [new file with mode: 0644]
src/policy/resources.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/common.pri b/common.pri
new file mode 100644 (file)
index 0000000..e7f4f13
--- /dev/null
@@ -0,0 +1,49 @@
+VERSION = 0.2.5
+TARGET = dialer
+CONFIG += link_pkgconfig network opengl debug
+
+# DEFINES += WANT_DEBUG
+
+# Build configuration
+
+!win32-msvc*:QMAKE_CXXFLAGS += -g
+
+# Features
+DEFINES += DBUS_SERVICE_PATH=\\\"/com/tizen/${QMAKE_TARGET}\\\"
+DEFINES += DBUS_SERVICE=\\\"com.tizen.${QMAKE_TARGET}\\\"
+
+# Sound theme base dir
+DEFINES += SOUNDS_DIR=\\\"\"$$M_INSTALL_DATA/sounds\"\\\"
+
+M_DBUS_SERVICES_DIR = $$M_INSTALL_DATA/dbus-1/services
+
+# Defines for directories, for use in source code.
+# They work cross-platform like this.
+{
+    # APPLET_LIBS determines the location where all applet binaries are
+    DEFINES += APPLET_LIBS=\\\"\"$$M_APPLET_DIR\"\\\"
+
+    # APPLET_DATA determines where the .desktop files are located
+    DEFINES += APPLET_DATA=\\\"\"$$M_APPLET_DATA_DIR\"\\\"
+
+    # APPLET_SETTINGS_DIR determines where the applet global and instance settings files are located
+    DEFINES += APPLET_SETTINGS_DIR=\\\"\"$$M_APPLET_SETTINGS_DIR\"\\\"
+
+    # TRANSLATION_DIR determines the default translation path
+    DEFINES += TRANSLATION_DIR=\\\"\"$$M_TRANSLATION_DIR\"\\\"
+
+    # M_THEME_PRELOAD_DIR and M_THEME_POST_PRELOAD_DIR defines from where
+    # to get lists of images to be preloaded
+    DEFINES += M_THEME_PRELOAD_DIR=\\\"\"$$M_THEME_PRELOAD_DIR\"\\\"
+    DEFINES += M_THEME_POST_PRELOAD_DIR=\\\"\"$$M_THEME_POST_PRELOAD_DIR\"\\\"
+    DEFINES += M_DBUS_SERVICES_DIR=\\\"\"$$M_DBUS_SERVICES_DIR\"\\\"
+    DEFINES += M_XDG_DIR=\\\"\"$$M_XDG_DIR\"\\\"
+}
+
+# defines for dependencies
+!win32:!macx{
+    DEFINES += HAVE_CONTEXTSUBSCRIBER
+    DEFINES += HAVE_ICU
+    DEFINES += HAVE_GCONF
+    DEFINES += HAVE_GSTREAMER
+}
diff --git a/dialer-keepalive.sh b/dialer-keepalive.sh
new file mode 100755 (executable)
index 0000000..6af29c1
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+# Until we have working systemd and are integrated with it
+# we are defering to crude hackery like this instead of relying
+# on applifed, which is rumored to be going the way of the dodo.
+
+# Call this script with any parameters supported by dialer (or
+# any Qt std args), for example:
+#
+#   dialer-keepalive.sh -prestart -output-level debug
+
+while true
+do
+       /usr/bin/dialer "$@"
+done
diff --git a/dialer.desktop b/dialer.desktop
new file mode 100644 (file)
index 0000000..d8b400b
--- /dev/null
@@ -0,0 +1,7 @@
+[Desktop Entry]
+Type=Application
+Name=Dialer
+Icon=icons-Applications-dialer
+Exec=dialer
+Comment=Tizen voice call application
+X-Desktop-File-Install-Version=0.16
diff --git a/dialer.service b/dialer.service
new file mode 100644 (file)
index 0000000..8352dfd
--- /dev/null
@@ -0,0 +1,3 @@
+[D-BUS Service]
+Name=com.tizen.hfdialer
+Exec=/usr/bin/dialer -prestart
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-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/makedist b/makedist
new file mode 100755 (executable)
index 0000000..b215f37
--- /dev/null
+++ b/makedist
@@ -0,0 +1,61 @@
+#!/bin/bash
+
+# Determine project name based on current directory
+#PROJECT=$(basename $PWD)
+PROJECT="tizen-handset-dialer"
+
+# NOTE: Don't like this?  Then uncomment one of the following as appropriate
+#
+# Just set it explictly to whatever you like:
+# PROJECT=libseaside
+#
+# Parse it from any Qt *.pro or *.pri files in CWD:
+# PROJECT=$(grep -E "TARGET ?= ?" *.pr[io]|cut -d' ' -f3)
+
+# Grab most recent tag from git
+TAG=$(git describe --tags --abbrev=0)
+
+# If arg1 is provided, use it as commit/tag/tree-ish id to start
+# the archive creation from...
+[ "${1}z" != "z" ] && {
+       TAG=${1}
+       echo "Creating release starting from: ${TAG}"
+}
+
+VERSION=$(git describe --tags ${1})
+VERSION=${VERSION//version-/}
+VERSION=${VERSION//-g/+}
+VERSION=${VERSION//-/+git}
+
+# Set name of toplevel directory for the archive
+BASE_PREFIX="${PROJECT}-${VERSION}/"
+BRANDING_PREFIX="${PROJECT}-branding-tizen-${VERSION}/"
+
+# Set name of resulting release archive file
+BASE_ARCHIVE=${PROJECT}-${VERSION}.tar.bz2
+BRANDING_ARCHIVE=${PROJECT}-branding-tizen-${VERSION}.tar.bz2
+
+# Clean up any existing base package for this version
+[ -e ${BASE_ARCHIVE} ] && rm -rf ${BASE_ARCHIVE} &&
+       echo "Removed: ${BASE_ARCHIVE}"
+
+# Generate the base package release tar ball
+# NOTE: Becuase I used a git attribute that ignores the tizen theme dir
+#       this archive will not include it... that's intentional!
+git archive --prefix=${BASE_PREFIX} ${TAG} | bzip2 -c -- > ${BASE_ARCHIVE} && {
+       echo "Created: ${BASE_ARCHIVE}"
+} || {
+       echo "Creation of release archive ${BASE_ARCHIVE} failed.  Reason unknown."
+}
+
+# Clean up any existing branding package for this version
+[ -e ${BRANDING_ARCHIVE} ] && rm -rf ${BRANDING_ARCHIVE} &&
+       echo "Removed: ${BRANDING_ARCHIVE}"
+# Generate the branding package release tar ball
+pushd themes > /dev/null
+git archive --prefix=${BRANDING_PREFIX} ${TAG} tizen/ themes.pro | bzip2 -c -- > ../${BRANDING_ARCHIVE} && {
+       echo "Created: ${BRANDING_ARCHIVE}"
+} || {
+       echo "Creation of release archive ${BRANDING_ARCHIVE} failed.  Reason unknown."
+}
+popd > /dev/null
diff --git a/projects.pro b/projects.pro
new file mode 100644 (file)
index 0000000..cef2ba8
--- /dev/null
@@ -0,0 +1,40 @@
+include (common.pri)
+TEMPLATE = subdirs
+CONFIG += ordered debug
+SUBDIRS = src qml dialerassets sounds
+
+#OTHER_FILES += dialer.service
+OTHER_FILES += *.service *.desktop *.sh
+M_INSTALL_BIN = /usr/bin
+M_INSATLL_DATA = /usr/share
+# Keepalive script
+keepalive_script.files = dialer-keepalive.sh
+keepalive_script.path += $$INSTALL_ROOT/usr/bin
+keepalive_script.CONFIG += no_check_exist
+
+# XDG Autostart
+#autostart_entry.files = dialer.desktop
+autostart_entry.files = dialer-prestart.desktop
+autostart_entry.path += /etc/xdg/autostart
+autostart_entry.CONFIG += no_check_exist
+
+# 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$$M_DBUS_SERVICES_DIR
+
+# Documentation
+documentation.files = AUTHORS ChangeLog LICENSE README TODO
+documentation.path  = $$INSTALL_ROOT/usr/share/hfdialer/
+
+INSTALLS += \
+    keepalive_script \
+    autostart_entry \
+    desktop_entry \
+    dbus_service \
+    documentation \
+
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..2b96510
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * 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);
+  }
+
+  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;
+     });
+    }
+    else
+    {
+       console.log("*** call.stateChanged doesn't exist.. setting state to disconnect");
+       //      root.state = 'disconnected';
+    }
+    }
+    else
+       console.log("*** call doesn't exist.. setting to disconnect");
+       //root.state = 'disconnected';
+  }
+
+  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..372af39
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+ * 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: 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: 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: 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: 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..b10730e
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * 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}
+
+        Text {
+            id: mainText
+
+            anchors {fill: parent; leftMargin: 15}
+            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..8a3aca1
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * 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}
+
+        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: "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..c94272c
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * 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
+       
+    height: parent.height
+    property real buttonHeight: (parent.height / 5) - 41;
+
+    function insertText(text)
+    {
+        entry.appendChar(text)
+    }
+
+    function show()
+    {
+        height = 72 * 5 + 4;
+        numPadShown = true;
+    }
+
+    function hide()
+    {
+        height = 72;
+        numPadShown = false;
+    }
+
+    function toggle()
+    {
+        if(numPadShown == true) {hide()} else {show()}
+    }
+
+    Behavior on height {PropertyAnimation {duration: 500; easing.type: Easing.OutBounce}}
+
+    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(entry.textInput.text == entry.placeHolderText)
+                         return;
+                       
+                       entry.textInput.text = entry.textInput.text.substring(0, entry.textInput.text.length -1);
+                  }
+                
+                  onPressAndHold: entry.clear();
+
+               }
+           }
+            
+           Image {
+                id: bCall;
+
+               height: parent.height
+                width: parent.width - bDelete.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(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();
+                    }
+                }
+               }
+            }
+         }
+       }
+   }
+}
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..e5d8342
--- /dev/null
@@ -0,0 +1,379 @@
+/*
+ * 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'
+    }
+
+    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
+                        delegate: DeviceDelegateActive {
+
+                            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: {
+                                    console.log("device CONNECTED, attempting to hook up audio")
+                                    // device.connectAudio()
+                                    // device.connectAudioSrc()
+                                    // device.connectInput()
+                                }
+                            }
+
+                            onClose: {
+                                console.log("unparing ...");
+                                device.unpair();
+                            }
+                        }
+                    }
+                }
+            }
+
+            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..9b68063
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * 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
+
+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
+
+        TextEdit {
+            id: textInputField           
+            anchors.centerIn: parent
+            width: parent.width
+            height: parent.height * 0.75
+            font.pixelSize: 24
+            color: "black"
+            text: replyValue
+            horizontalAlignment: Text.AlignHCenter
+        }
+    }
+
+    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)
+            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)
+            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..6184b56
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * 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
+
+
+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
+
+        TextEdit {
+            id: textInputField           
+            anchors.centerIn: parent
+            width: parent.width
+            height: parent.height * 0.75
+            font.pixelSize: 24
+            color: "black"
+            text: replyValue
+            horizontalAlignment: Text.AlignHCenter
+        }
+    }
+
+   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: {
+            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..c8cfddd
--- /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.tizen.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..13e8128
--- /dev/null
@@ -0,0 +1,7 @@
+TEMPLATE = subdirs
+CONFIG += ordered
+
+qml.files = *.qml javascripts
+qml.path  = $${installPrefix}/usr/share/hfdialer/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..33d92f8
--- /dev/null
@@ -0,0 +1,402 @@
+/*
+ * 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)//,
+      //m_ringtonefile("")
+{
+    TRACE
+    
+   /*  QString l_ringtoneFile = QString("%1/%2/stereo/%3")
+                                     .arg(SOUNDS_DIR)
+                                     .arg("tizen")
+                                     .arg(DEFAULT_RINGTONE);
+    */
+
+    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()) {
+        /*
+       m_ringtonefile = l_ringtoneFile;
+        qDebug() << QString("CallItem: %1 using ringtone: %2")
+                           .arg(m_path)
+                           .arg(m_ringtonefile);
+       */
+    } else {
+        qWarning() << QString("CallItem: %1 ringtone not found: %2")
+                           .arg(m_path)
+                           .arg(l_rtKeyValue);
+    }
+
+    //m_ringtone->setMedia(QMediaContent(QUrl::fromLocalFile(m_ringtonefile)));
+    //m_ringtone->setVolume(100);
+
+    if (isValid())
+        init();
+}
+
+CallItem::~CallItem()
+{
+    TRACE
+/*
+    if (m_ringtone) {
+        disconnect(m_ringtone, SIGNAL(positionChanged(qint64)));
+        m_ringtone->stop();
+        delete m_ringtone;
+        m_ringtone = 0;
+    }
+*/
+   PAControl::instance()->unrouteAudio();
+   
+    if (m_rtKey)
+        delete m_rtKey;
+    m_rtKey = 0;
+/*
+    if (m_peopleItem)
+        delete m_peopleItem;
+    m_peopleItem = 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!");
+
+    //populatePeopleItem();
+
+    if (state() == STATE_INCOMING ||
+        state() == STATE_WAITING)
+    {
+   /*
+        // Start ringing
+        if (!m_isconnected && m_ringtone) {
+           connect(m_ringtone, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)),
+                               SLOT(ringtoneStatusChanged(QMediaPlayer::MediaStatus)));
+           m_isconnected = TRUE;
+           m_ringtone->play();
+        }
+*/
+    }
+}
+
+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 
+  //  dynamic_cast<CallItemModel*>(model())->setDirection(direction);
+}
+
+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;
+        //return dynamic_cast<const CallItemModel*>(model())->direction();
+}
+
+CallDisconnectReason CallItem::reason() const
+{
+    TRACE
+    return DISCONNECT_NONE; 
+    //return dynamic_cast<const CallItemModel*>(model())->reasonType();
+}
+
+int CallItem::duration() const
+{
+    TRACE
+    return m_call->duration();
+}
+
+QDateTime CallItem::startTime() const
+{
+    TRACE
+    return m_call->startTime();
+}
+/*
+PeopleItem * CallItem::peopleItem() const
+{
+    TRACE
+    return m_peopleItem;
+}
+*/
+CallProxy* CallItem::callProxy() const
+{
+    TRACE
+ /*
+   if (model())
+     return dynamic_cast<const CallItemModel*>(model())->call();
+    else
+       return NULL;
+*/
+return m_call;
+}
+/*
+void CallItem::setPeopleItem(PeopleItem *person)
+{
+    TRACE
+    if (m_peopleItem)
+        delete m_peopleItem;
+    m_peopleItem = person;
+}
+*/
+void CallItem::click()
+{
+    TRACE
+
+    emit clicked();
+}
+
+void CallItem::silenceRingtone()
+{
+    TRACE
+/*
+    if(m_ringtone)
+    {
+        m_ringtone->stop();
+    }
+*/
+}
+
+void CallItem::callStateChanged()
+{
+    TRACE
+   /*
+    if (state() == STATE_INCOMING ||
+        state() == STATE_WAITING)
+    {
+        // Start ringing
+        if (!m_isconnected && m_ringtone) {
+            connect(m_ringtone, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)),
+                                SLOT(ringtoneStatusChanged(QMediaPlayer::MediaStatus)));
+            m_isconnected = TRUE;
+            m_ringtone->play();
+        }
+    } else {
+        // Stop ringing
+        if (m_ringtone) {
+            disconnect(m_ringtone, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)));
+            m_isconnected = FALSE;
+            m_ringtone->stop();
+        }
+    }*/
+    emit stateChanged();
+}
+
+void CallItem::callDataChanged()
+{
+    TRACE
+   // populatePeopleItem();
+}
+
+void CallItem::callDisconnected(const QString &reason)
+{
+    TRACE
+    Q_UNUSED(reason);
+}
+
+/*
+QVariant CallItem::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &val)
+{
+    TRACE
+    if (change == QGraphicsItem::ItemSelectedHasChanged)
+        dynamic_cast<const CallItemModel*>(model())->setSelected(val.toBool());
+    return QGraphicsItem::itemChange(change, val);
+}
+*/
+/*
+void CallItem::populatePeopleItem()
+{
+    TRACE
+
+    QModelIndexList matches;
+    matches.clear();
+    int role = Seaside::SearchRole;
+    int hits = -1;
+
+    //% "Unknown Caller"
+    QString pi_name   = qtTrId("xx_unknown_caller");
+    QString pi_photo  = "icon-m-content-avatar-placeholder";
+    //% "Private"
+    QString pi_lineid = qtTrId("xx_private");
+
+    if (!lineID().isEmpty()) {
+        pi_lineid = stripLineID(lineID());
+        SeasideSyncModel *contacts = DA_SEASIDEMODEL;
+        QModelIndex first = contacts->index(0,Seaside::ColumnPhoneNumbers);
+        matches = contacts->match(first, role, QVariant(pi_lineid), hits);
+
+        QString firstName = QString();
+        QString lastName = QString();
+
+        if (!matches.isEmpty()) {
+            QModelIndex person = matches.at(0); //First match is all we look at
+            SEASIDE_SHORTCUTS
+            SEASIDE_SET_MODEL_AND_ROW(person.model(), person.row());
+
+            firstName = SEASIDE_FIELD(FirstName, String);
+            lastName = SEASIDE_FIELD(LastName, String);
+            pi_photo = SEASIDE_FIELD(Avatar, String);
+        } else if (!name().isEmpty()) {
+            // We don't have a contact, but we have a callerid name, let's use it
+            firstName = name();
+        }
+
+        if (lastName.isEmpty() && !firstName.isEmpty())
+            // Contacts first (common) name
+            //% "%1"
+            pi_name = qtTrId("xx_first_name").arg(firstName);
+        else if (firstName.isEmpty() && !lastName.isEmpty())
+            // BMC# 8079 - NW
+            // Contacts last (sur) name
+            //% "%1"
+            pi_name = qtTrId("xx_last_name").arg(lastName);
+        else if (!firstName.isEmpty() && !lastName.isEmpty())
+            // Contacts full, sortable name, is "Firstname Lastname"
+            //% "%1 %2"
+            pi_name = qtTrId("xx_first_last_name").arg(firstName)
+                .arg(lastName);
+
+    } else {
+        //% "Unavailable"
+        pi_lineid = qtTrId("xx_unavailable");
+    }
+
+    if (m_peopleItem != NULL)
+        delete m_peopleItem;
+    m_peopleItem = new PeopleItem();
+
+    m_peopleItem->setName(pi_name);
+    m_peopleItem->setPhoto(pi_photo);
+    m_peopleItem->setPhone(pi_lineid);
+}
+*/
+/*
+void CallItem::ringtoneStatusChanged(QMediaPlayer::MediaStatus status)
+{
+    TRACE
+    if (status == QMediaPlayer::EndOfMedia)
+    {
+      m_ringtone->setMedia(QMediaContent(QUrl::fromLocalFile(m_ringtonefile)));
+      m_ringtone->play();
+    }
+}
+*/
+bool CallItem::multiparty()
+{
+    TRACE 
+    return false;   
+ //  return (isValid())?dynamic_cast<const CallItemModel*>(model())->multiparty():false;
+}
+
+void CallItem::callMultipartyChanged()
+{
+    TRACE
+    emit multipartyChanged();
+}
diff --git a/src/callitem.h b/src/callitem.h
new file mode 100644 (file)
index 0000000..6ec1f74
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * 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 <QMediaPlayer>
+#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(PeopleItem* peopleItem READ peopleItem WRITE setPeopleItem)
+    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;
+    //PeopleItem *peopleItem() const;
+    CallProxy *callProxy() const;
+    bool isValid();
+    bool isValid() const;
+    bool multiparty();
+
+public Q_SLOTS:
+    void init();
+    //void setPeopleItem(PeopleItem *person);
+    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 ringtoneStatusChanged(QMediaPlayer::MediaStatus status);
+    void callMultipartyChanged();
+
+private:
+    //QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &val);
+   // void populatePeopleItem();
+
+    QString               m_path;
+    //PeopleItem           *m_peopleItem;
+    //QMediaPlayer         *m_ringtone;
+    MGConfItem           *m_rtKey;
+    bool                  m_isconnected;
+    QString               m_ringtonefile;
+    CallProxy           *m_call;
+
+    Q_DISABLE_COPY(CallItem)
+};
+
+#endif // CALLITEM_H
diff --git a/src/callmanager.cpp b/src/callmanager.cpp
new file mode 100644 (file)
index 0000000..2674333
--- /dev/null
@@ -0,0 +1,494 @@
+/*
+ * 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"
+//#include "resourceproxy.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
+
+//    d->resource = ResourceProxy::instance();
+
+    // Resource proxy binding
+//    if (d->resource) {
+//        connect(d->resource, SIGNAL(incomingResourceAcquired(CallItem *)),
+//                SLOT(proceedIncomingCall(CallItem *)));
+//        connect(d->resource, SIGNAL(incomingResourceDenied(CallItem *)),
+//                SLOT(deniedIncomingCall(CallItem *)));
+//        connect(d->resource, SIGNAL(incomingResourceLost(CallItem *)),
+//                SLOT(lostIncomingCall(CallItem *)));
+
+//        connect(d->resource, SIGNAL(dialResourceAcquired(const QString)),
+//                SLOT(proceedCallDial(const QString)));
+//        connect(d->resource, SIGNAL(dialResourceDenied()),
+//                SLOT(deniedCallDial()));
+//        connect(d->resource, SIGNAL(callResourceLost()),
+//                SLOT(lostCallDial()));
+  //  }
+
+    // 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)));
+
+    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();
+}
+
+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
+    //if (!call.isActive())
+        swapCalls();
+}
+/*
+void CallManager::dial(const PeopleItem *person)
+{
+    TRACE
+    dial(person->phone());
+}
+*/
+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;
+        }
+    }
+
+//    if (d->resource)
+//        d->resource->acquireDialResource(number);
+       proceedCallDial(number);
+}
+
+void CallManager::privateChat(const CallItem &call)
+{
+    //TRACE
+    //OfonoVoiceCallManager::privateChat(call.path());
+}
+
+/*
+ * 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();
+
+//        if (d->resource)
+//            d->resource->releaseResources();
+
+        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)) {
+//                if (d->resource)
+//                    d->resource->acquireIncomingResource(call);
+               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());
+}
diff --git a/src/callmanager.h b/src/callmanager.h
new file mode 100644 (file)
index 0000000..9a55423
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * 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
+    // takes a PeopleItem rather than number string and uses default
+    // as CLIR value
+  //  void dial(const PeopleItem *person);
+
+    // 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 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();
+
+    // 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
diff --git a/src/callproxy.cpp b/src/callproxy.cpp
new file mode 100644 (file)
index 0000000..870ce73
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ * 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 "callproxy.h"
+#include "managerproxy.h"
+//#include "resourceproxy.h"
+
+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);
+
+/*
+        connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
+                         SLOT(getPropertiesFinished(QDBusPendingCallWatcher*)));
+*/
+
+        // 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
+
+//    ResourceProxy *resource = ResourceProxy::instance();
+
+//    connect(resource, SIGNAL(answerResourceAcquired()), SLOT(proceedCallAnswer()));
+//    connect(resource, SIGNAL(answerResourceDenied()), SLOT(deniedCallAnswer()));
+
+//    resource->acquireAnswerResource();
+
+proceedCallAnswer();
+}
+
+void CallProxy::proceedCallAnswer()
+{
+    TRACE
+
+//    ResourceProxy *resource = ResourceProxy::instance();
+    QDBusPendingReply<QDBusObjectPath> reply;
+    QDBusPendingCallWatcher *watcher;
+
+ //   disconnect(resource, SIGNAL(answerResourceAcquired()));
+ //   disconnect(resource, SIGNAL(answerResourceDenied()));
+
+    reply = Answer();
+    watcher = new QDBusPendingCallWatcher(reply);
+
+    connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
+                     SLOT(answerFinished(QDBusPendingCallWatcher*)));
+}
+
+void CallProxy::deniedCallAnswer()
+{
+    TRACE
+
+//    ResourceProxy *resource = ResourceProxy::instance();
+
+//    disconnect(resource, SIGNAL(answerResourceAcquired()));
+//    disconnect(resource, SIGNAL(answerResourceDenied()));
+
+    // 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();
+}
+
diff --git a/src/callproxy.h b/src/callproxy.h
new file mode 100644 (file)
index 0000000..83c35b7
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * 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
diff --git a/src/common.h b/src/common.h
new file mode 100644 (file)
index 0000000..ff3c3c9
--- /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
+ *
+ */
+
+#ifndef COMMON_H
+#define COMMON_H
+
+#ifndef WANT_DEBUG
+#define TRACE
+#else
+#include <QDebug>
+#define TRACE qDebug()<<QString("[%1] %2(): %3").arg(__FILE__).arg(__func__).arg(__LINE__);
+#endif
+
+/*
+ * Commonly used QRegExp expressions
+ */
+#include <QRegExp>
+#define MATCH_ANY(p) QRegExp(p,Qt::CaseInsensitive,QRegExp::FixedString)
+#define MATCH_ALL QRegExp()
+
+/*
+ * Commonly used values for MNotifications
+ */
+#define DEFAULT_AVATAR_ICON "icon-m-content-avatar-placeholder"
+#define NOTIFICATION_CALL_EVENT "x-nokia.call"
+
+/*
+ * Convienence macro for showing TBD message
+ */
+#define SHOW_TBD \
+    MainWindow *w = dynamic_cast<MainWindow *>(DialerApplication::instance()->activeApplicationWindow()); \
+    if (w) \
+       w->showTBD();
+
+/*
+ * Convience macro for checking available dialer modes
+ */
+#define CONFIG_KEY_TARGET_MODE "/apps/dialer/mode"
+#define MODE_HFP_STR "hfp"
+#define MODE_HANDSET_STR "handset"
+#define MODE_HFP_ENABLED DC->modes().contains(MODE_HFP_STR)
+#define MODE_HANDSET_ENABLED DC->modes().contains(MODE_HANDSET_STR)
+QString stripLineID(QString lineid);
+
+bool currentPageIs(int pagenum);
+
+#include <QDateTime>
+QDateTime qDateTimeFromOfono(const QString &val);
+
+#endif // COMMON_H
diff --git a/src/dbus/com.tizen.hfdialer.xml b/src/dbus/com.tizen.hfdialer.xml
new file mode 100644 (file)
index 0000000..70a08a7
--- /dev/null
@@ -0,0 +1,10 @@
+<!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.tizen.hfdialer" >
+               <method name="call" >
+                       <arg direction="in" type="s" name="" />
+               </method>
+               <method name="accept"/>
+       </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..6dc77b8
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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);
+}
diff --git a/src/dbusdialeradapter.h b/src/dbusdialeradapter.h
new file mode 100644 (file)
index 0000000..23876d9
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * 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.tizen.hfdialer")
+
+public:
+    explicit DBusDialerAdapter(DialerApplication *application);
+            ~DBusDialerAdapter();
+
+Q_SIGNALS:
+
+public Q_SLOTS:
+    void call(const QString &msisdn);
+};
+
+#endif // DBUSDIALERADAPTER_H
diff --git a/src/dbustypes.cpp b/src/dbustypes.cpp
new file mode 100644 (file)
index 0000000..1fd46f3
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * 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;
+}
diff --git a/src/dbustypes.h b/src/dbustypes.h
new file mode 100644 (file)
index 0000000..401c604
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * 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
diff --git a/src/dialerapplication.cpp b/src/dialerapplication.cpp
new file mode 100644 (file)
index 0000000..441ed81
--- /dev/null
@@ -0,0 +1,393 @@
+/*
+ * 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 "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()));
+        if (!MODE_HANDSET_ENABLED)
+        {
+            PAControl* paControl = PAControl::instance();
+            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());
+}
+/*
+SeasideSyncModel *DialerApplication::seasideModel()
+{
+    TRACE
+    return m_seasideModel;
+}
+
+SeasideProxyModel *DialerApplication::seasideProxy()
+{
+    TRACE
+    return m_seasideProxy;
+}
+*/
+/*
+HistoryTableModel *DialerApplication::historyModel()
+{
+    TRACE
+ //   return m_historyModel;
+}
+
+QSortFilterProxyModel *DialerApplication::historyProxy()
+{
+    TRACE
+    return m_historyProxy;
+}
+*/
+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;
+
+    DBusDialerAdapter *adapter = new DBusDialerAdapter(this);
+    if(!adapter)
+    {
+        qWarning() << "DBus adapter instantiation failed.";
+    }
+
+    if(!QDBusConnection::sessionBus().registerObject(DBUS_SERVICE_PATH, this))
+    {
+        qCritical() << "Error registering dbus object:" <<
+                       QDBusConnection::sessionBus().lastError().message();
+    }
+  /*
+    m_seasideModel = new SeasideSyncModel();
+    m_seasideProxy = new SeasideProxyModel();
+    m_seasideProxy->setSourceModel(m_seasideModel);
+    m_seasideProxy->setDynamicSortFilter(true);
+    m_seasideProxy->setFilterKeyColumn(-1);
+    m_seasideProxy->setFilterRegExp(MATCH_ALL);
+    m_seasideProxy->sort(Seaside::ColumnLastName, Qt::AscendingOrder);
+  */
+    //m_historyModel = new HistoryTableModel();
+  //  m_historyProxy = new QSortFilterProxyModel();
+   // m_historyProxy->setSourceModel(m_historyModel);
+   // m_historyProxy->setDynamicSortFilter(true);
+  //  m_historyProxy->setFilterKeyColumn(HistoryTableModel::COLUMN_LINEID);
+  //  m_historyProxy->sort(HistoryTableModel::COLUMN_CALLSTART,
+  //                       Qt::DescendingOrder);
+
+   /*
+    connect(m_manager->modem(), SIGNAL(connected()),
+                                SLOT(modemConnected()));
+    connect(m_manager->modem(), SIGNAL(disconnected()),
+                                SLOT(modemDisconnected()));
+   */
+   connect(m_manager, SIGNAL(modemChanged()),
+                                SLOT(modemChanged()));
+
+}
+
+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()));
+    }
+}
+
+void DialerApplication::modemConnected()
+{
+    TRACE
+    //TODO: Handle multiple modems
+    if (m_manager->modem() && m_manager->modem()->isValid())
+    {
+        m_modem = m_manager->modem();
+
+        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
+/*
+    static MNotification *vmail = NULL;
+
+    if (!m_manager->voicemail() || !m_manager->voicemail()->isValid()) {
+        qDebug() << QString("Voicemail proxy is invalid, ignoring");
+        return;
+    }
+
+
+    if (!vmail) {
+        bool found = false;
+        foreach (MNotification *notice, MNotification::notifications()) {
+            if (notice->eventType() == MNotification::MessageArrivedEvent) {
+                // If we've already found a MessageArrived notification,
+                // we must delete others since we only want one
+                if (found) {
+                    qDebug() << QString("Removing duplicate voicemail notice");
+                    notice->remove();
+                    delete notice;
+                }
+                else {
+                    vmail = notice;
+                    found = true;
+                }
+            }
+            else {
+                // We're only interested in MessageArrived events, all others
+                // can need to be deleted here since they are copies
+                delete notice;
+            }
+        }
+
+        if (!found) {
+            if (!m_manager->voicemail()->waiting()) {
+                qDebug() << QString("No waiting Voicemail messages");
+                return;
+            }
+            else {
+                // This is the first instance of a MessageArrived event
+                qDebug() << QString("Creating new voicemail notice instance");
+                vmail = new MNotification(MNotification::MessageArrivedEvent);
+                vmail->setCount(0);
+            }
+        }
+        else {
+            if (!m_manager->voicemail()->waiting()) {
+                qDebug() << QString("No waiting Voicemail messages");
+                vmail->remove();
+                return;
+            }
+        }
+    }
+
+    // We've got a valid notification and we have messages waiting...
+    int vCount = m_manager->voicemail()->count();
+    int nCount = vmail->count();
+
+    if (vCount < 0) vCount = 0;
+    if (nCount < 0) nCount = 0;
+
+    qDebug() << QString("Voicemails: %1").arg(QString::number(vCount));
+    qDebug() << QString("Notices:    %1").arg(QString::number(nCount));
+
+    // No more Voicemail messages waiting, remove notification
+    if (vCount <= 0) {
+        qDebug() << QString("No Voicemails waiting, removing notification");
+        vmail->remove();
+        return;
+    }
+
+    // The waiting voicemail count has changed, update and [re]publish it
+    //% "You have %1 voice messages"
+    vmail->setSummary(qtTrId("xx_messages_waiting").arg(vCount));
+    vmail->setImage("icon-m-telephony-voicemail");
+    vmail->setCount(vCount);
+    qDebug() << QString("Voicemail count changed, publishing notification");
+    vmail->publish();
+*/
+}
+
+void DialerApplication::onCallsChanged()
+{
+    TRACE
+    QMLMainWindow::instance()->tryToShow();
+}
diff --git a/src/dialerapplication.h b/src/dialerapplication.h
new file mode 100644 (file)
index 0000000..866b87e
--- /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 DIALERAPPLICATION_h
+#define DIALERAPPLICATION_h
+
+#include "managerproxy.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();
+
+//    SeasideSyncModel      *seasideModel();
+//    SeasideProxyModel     *seasideProxy();
+ //   HistoryTableModel     *historyModel();
+ //   QSortFilterProxyModel *historyProxy();
+    
+Q_SIGNALS:
+    void showUi();
+    void hideUi();
+
+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;
+
+    //SeasideSyncModel      *m_seasideModel;
+    //SeasideProxyModel     *m_seasideProxy;
+
+    //HistoryTableModel     *m_historyModel;
+   // QSortFilterProxyModel *m_historyProxy;
+
+    Q_DISABLE_COPY(DialerApplication);
+};
+
+#endif // DIALERAPPLICATION_H
diff --git a/src/dialercontext.cpp b/src/dialercontext.cpp
new file mode 100644 (file)
index 0000000..897abaf
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * 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;
+//    ResourceProxy       *policyManager;
+    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()));
+
+    // ResourceProxy is a singleton, probably don't need to store this...
+    //d->policyManager = ResourceProxy::instance();
+
+    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;
+}
+
+/*
+ResourceProxy* DialerContext::policyManager() const
+{
+    return d->policyManager;
+}
+*/
+
+QStringList DialerContext::modes() const
+{
+    return d->modes;
+}
+
+void DialerContext::setModes(const QStringList &modelist)
+{
+    d->modes = modelist;
+    d->modes.removeDuplicates();
+    emit modesChanged();
+}
+
+/*
+OfonoModem* DialerContext::modem() const
+{
+    if (d->callManager)
+        return d->callManager->modem();
+    return NULL;
+}
+*/
+
+/*
+ * 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(", ");
+}
diff --git a/src/dialercontext.h b/src/dialercontext.h
new file mode 100644 (file)
index 0000000..28aece1
--- /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 DIALERCONTEXT_H
+#define DIALERCONTEXT_H
+
+// libofono-qt headers
+#include <ofonomodemmanager.h>
+#include <ofonocallvolume.h>
+#include <ofonomessagewaiting.h>
+
+// local headers
+#include "callmanager.h"
+//#include "resourceproxy.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(ResourceProxy* policyManager READ policyManager)
+    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;
+    //ResourceProxy*       policyManager() 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
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644 (file)
index 0000000..1bae7da
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * 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>
+
+#define CONFIG_KEY_TARGET_UX "/apps/dialer/ux"
+
+#if !defined(CONFIG_DEFAULT_TARGET_UX)
+#  define CONFIG_DEFAULT_TARGET_UX "tizen-ux-components"
+#endif
+
+ void myMessageOutput(QtMsgType type, const char *msg)
+ {
+     QFile debugFile("/home/tizen/dialerout.txt");
+       debugFile.open(QIODevice::WriteOnly | QIODevice::Append);
+     QTextStream out(&debugFile);
+
+       out << msg << "\n";
+       debugFile.close();
+ }
+
+int main(int argc, char *argv[])
+{
+  TRACE
+   qInstallMsgHandler(myMessageOutput);
+   DialerApplication app(argc, argv);  
+
+    QMLMainWindow *qmw = QMLMainWindow::instance();
+    //setResizeMode(QDeclarativeView::SizeRootObjectToView);
+    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, "");
+}
+
+bool currentPageIs(int pagenum)
+{
+    DialerApplication *app = DialerApplication::instance();
+     return true;
+}
+
+// Returns a valid QDateTime if parsable as such, otherwise the result
+// will be !isValid()
+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 WANT_DEBUG
+    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 WANT_DEBUG
+                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;
+}
diff --git a/src/managerproxy.cpp b/src/managerproxy.cpp
new file mode 100644 (file)
index 0000000..521b84e
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+ * 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;
+}
+
+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();
+}
+
+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)
+        return;
+
+    if (m_modem)
+    {
+        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)
+{
+    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 || !m_callManager->isValid()) {
+            delete m_callManager;
+            m_callManager = new CallManager(modempath);
+            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();
+        }
+    }
+}
diff --git a/src/managerproxy.h b/src/managerproxy.h
new file mode 100644 (file)
index 0000000..597ad6e
--- /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 MANAGERPROXY_H
+#define MANAGERPROXY_H
+
+#include "manager_interface.h"
+#include "modemproxy.h"
+#include "networkproxy.h"
+#include "callmanager.h"
+//#include "resourceproxy.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
diff --git a/src/modemproxy.cpp b/src/modemproxy.cpp
new file mode 100644 (file)
index 0000000..3199018
--- /dev/null
@@ -0,0 +1,365 @@
+/*
+ * 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;
+
+    QDBusPendingReply<QVariantMap> reply;
+    reply = SetProperty("Powered", QDBusVariant(is_powered?true:false));
+    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();
+      }
+    }
+}
diff --git a/src/modemproxy.h b/src/modemproxy.h
new file mode 100644 (file)
index 0000000..92e9999
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * 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
diff --git a/src/networkproxy.cpp b/src/networkproxy.cpp
new file mode 100644 (file)
index 0000000..57dea9b
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * 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
+ * **************************************************************/
+/* TODO: make property reference/storage more generic
+
+typedef struct {
+    unsigned int  id;
+    const char   *name;
+} OperatorProperty;
+
+enum OperatorPropertyID {
+        CountryCode = 0,
+        NetworkCode,
+        Name,
+        Status,
+        Technologies,
+};
+
+static OperatorProperty operatorProperty[] = {
+        { CountryCode,  "MobileCountryCode", },
+        { NetworkCode,  "MobileNetworkCode", },
+        { Name,         "Name",              },
+        { Status,       "Status",            },
+        { Technologies, "Technologies",      },
+};
+*/
+
+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);
+
+            // GetProperties() has probably not completed yet, so this
+            // test will be unlikely to work.
+            // TODO: connect to the propertyChanged() signal and do this there
+/*
+            if (op->status() == "current") {
+                m_currentOperator = op;
+                qDebug() << "Current network operator is " <<
+                            m_currentOperator->name() << " (" <<
+                            m_currentOperator->path() << ")";
+            }
+*/
+        }
+        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();
+        }
+    }
+}
+
diff --git a/src/networkproxy.h b/src/networkproxy.h
new file mode 100644 (file)
index 0000000..f4c21bb
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * 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
diff --git a/src/pacontrol.cpp b/src/pacontrol.cpp
new file mode 100644 (file)
index 0000000..e9edf61
--- /dev/null
@@ -0,0 +1,703 @@
+/*
+ * 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;
+    }
+
+    //qDebug() << "pa_sinklist_cb() Sink added: " << l->name;
+    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;
+    }
+
+    //qDebug() << "pa_modulelist_cb() Module added: " << i->name;
+    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()
+{
+    CallManager *cm = ManagerProxy::instance()->callManager();
+    if (!cm || !cm->isValid())
+    {
+           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();
+        }
+    }
+}
+
diff --git a/src/pacontrol.h b/src/pacontrol.h
new file mode 100644 (file)
index 0000000..19e0526
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * 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
diff --git a/src/policy/audio-resource.h b/src/policy/audio-resource.h
new file mode 100644 (file)
index 0000000..2dddff7
--- /dev/null
@@ -0,0 +1,131 @@
+/*************************************************************************
+This file is part of libresourceqt
+
+Copyright (C) 2010 Nokia Corporation.
+
+This library is free software; you can redistribute
+it and/or modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation
+version 2.1 of the License.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+USA.
+*************************************************************************/
+/**
+ * @file audio-resource.h
+ * @brief Declaration of ResourcePolicy::AudioResource resource class.
+ *
+ * @copyright Copyright (C) 2010 Nokia Corporation.
+ * @author Wolf Bergenheim
+ * \par License
+ * @license LGPL
+ * This file is part of libresourceqt
+ * \par
+ * Copyright (C) 2010 Nokia Corporation.
+ * \par
+ * This library is free software; you can redistribute
+ * it and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation
+ * version 2.1 of the License.
+ * \par
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * \par
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA.
+ */
+
+#ifndef AUDIO_RESOURCE_H
+#define AUDIO_RESOURCE_H
+
+#include <QObject>
+#include <QString>
+#include <policy/resource.h>
+
+namespace ResourcePolicy
+{
+
+/**
+ * The AudioResource class represents the audio device. It is a bit 
+ * different from other resource types in that in takes more parameters to
+ * allow the programmer to classify the audio stream used by the application.
+ */
+class AudioResource: public QObject, public Resource
+{
+    Q_OBJECT
+public:
+       /**
+     * The constructor.
+     * \param audioGroup The audio group which this application belongs to.
+     * This is an optional parameter.
+     */
+    AudioResource(const QString &audioGroup = QString());
+    AudioResource(const AudioResource &other);
+    virtual ~AudioResource();
+
+    //! Accessor for the  audioGroup.
+    QString audioGroup() const;
+    //! A test to check whether the audio group is set or not.
+    bool audioGroupIsSet() const;
+    /**
+     * Set the audio group (classification)
+     * \param newGroup The new audio group to set.
+     */
+    void setAudioGroup(const QString & newGroup);
+
+    //! \return The PID of the process which is responsible for rendering the audio stream.
+    quint32 processID() const;
+    /**
+     * Use this to indicate to the Resource Manager the PID of the audio
+     * stream renderer.
+     * \param newPID Set this to the PID of the process which will render the audio.
+     */
+    void setProcessID(quint32 newPID);
+
+    //! \return the name of the stream tag.
+    QString streamTagName() const;
+    //! \return the value of the stream tag.
+    QString streamTagValue() const;
+    //! A test to check whether the stream tag has been set or not.
+    bool streamTagIsSet() const;
+    /**
+     * Set the tream tag to help policy to correctly identify the audio stream
+     * beloning to you.
+     * \param name The name of the tag. For example "media.name"
+     * \param value The value of the stream tag.
+     */
+    void setStreamTag(const QString &name, const QString &value);
+
+    virtual ResourceType type() const;
+private:
+    QString group;
+    quint32 pid;
+    QString streamName;
+    QString streamValue;
+signals:
+    /**
+     * This signal is emitted when any of the properties of the AudioResource
+     * are changed. This signal is connected to in the ResourceSet to
+     * track the changes to the AudioResource object.
+     * \param group The new audio group
+     * \param pid The new PID of the audio renderer
+     * \param name The new Stream tag name
+     * \param value the new stream tag value
+     */
+    void audioPropertiesChanged(const QString &group, quint32 pid,
+                                const QString &name, const QString &value);
+};
+}
+
+#endif
diff --git a/src/policy/resource-set.h b/src/policy/resource-set.h
new file mode 100644 (file)
index 0000000..a36254d
--- /dev/null
@@ -0,0 +1,352 @@
+/*************************************************************************
+This file is part of libresourceqt
+
+Copyright (C) 2010 Nokia Corporation.
+
+This library is free software; you can redistribute
+it and/or modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation
+version 2.1 of the License.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+USA.
+*************************************************************************/
+/**
+ * @file resource-set.h
+ * @brief Declaration of ResourcePolicy::ResourceSet
+ *
+ * @copyright Copyright (C) 2010 Nokia Corporation.
+ * @author Wolf Bergenheim
+ * \par License
+ * @license LGPL
+ * This file is part of libresourceqt
+ * \par
+ * Copyright (C) 2010 Nokia Corporation.
+ * \par
+ * This library is free software; you can redistribute
+ * it and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation
+ * version 2.1 of the License.
+ * \par
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * \par
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA.
+ */
+
+#ifndef RESOURCE_SET_H
+#define RESOURCE_SET_H
+
+#include <QString>
+#include <QObject>
+#include <QVector>
+#include <QList>
+#include <policy/resources.h>
+#include <policy/audio-resource.h>
+
+/**
+ * \mainpage Resource Policy Library
+ *
+ * \section intro_section Introduction
+ *
+ * This library is used to request resources from the Policy Resource Manager.
+ * To use this library two classes are provided: \ref ResourcePolicy::Resource and
+ * \ref ResourcePolicy::ResourceSet.
+ *
+ * \section library_use_section Library Usage
+ *
+ * To use the Resource Policy Library, you first need to create the
+ * \ref ResourcePolicy::ResourceSet like this:
+ * \code
+ * ResourcePolicy::ResourceSet *resources = new ResourcePolicy::ResourceSet("player");
+ * \endcode
+ * Then to add resources to the set use the ResourceSet::addResource() method to add
+ * resources to the ResourcePolicy::ResourceSet. Like this:
+ * \code
+ * resources->addResource(AudioPlaybackType);
+ * resources->addResource(VideoPlaybackType);
+ * \endcode
+ * If you want to pre-populate the AudioResource with the audio group (it is a good idea)
+ * and other audio parameters you can create an audio object yourself and then
+ * give that to the ResourcePolicy::ResourceSet. Note that you should NOT free this object.
+ * The ResourcePolicy::ResourceSet takes ownership of this pointer.
+ * \code
+ * ResourcePolicy::AudioResource *audioResource = new ResourcePolicy::AudioResource("player");
+ * resources->addResourceObject(audioResource);
+ * \endcode
+ * Calling the ResourcePolicy::ResourceSet::deleteResource() method will remove
+ * and delete the object. Then when you want to acquire the ResourcePolicy::ResourceSet
+ * you simply use the ResourcePolicy::ResourceSet::acquire() method, like this:
+ * \code
+ * QObject::connect(resources, SIGNAL(resourcesAcquired()),
+ *                  this, SLOT(acquireOkHandler(QList<ResourcePolicy::Resource>)));
+ * QObject::connect(resources, SIGNAL(resourcesDenied()), this, SLOT(acquireDeniedHandler()));
+ * resources->acquire();
+ * \endcode
+ * You should also connect to the ResourcePolicy::ResourceSet::lostResources() signal like this:
+ * \code
+ * QObject::connect(resources, SIGNAL(lostResources()),
+ *                  this, SLOT(lostResources()));
+ * \endcode
+ * This signal tells you when you should stop using the resources you have asked for.
+ * So it is important that you connect to it.
+ *
+ * To modify the properties of the resources you can use the ResourcePolicy::ResourceSet::resource() method.
+ *
+ * \section see_devel_doc See Also
+ * For a more detailed guide see the
+ * <a href="https://projects.maemo.org/mediawiki/index.php/Maemo_Developer_Guide/Developing_Harmattan_applications/Application_policy_guidelines">Application policy guidelines</a>.
+ */
+
+/**
+ * \brief The Namespace for Resource Policy.
+ * All Resource Policy Qt APIs reside under the ResourcePolicy namespace.
+ */
+namespace ResourcePolicy
+{
+class ResourceEngine;
+/**
+ * The resourceSet repesents a set of attributes. Each set can only contain
+ * a single Resource of a given type. That is one AudioPlaybackResource, etc.
+ *
+ * Internally the set is stored as a QVector of \ref Resource objects.
+ */
+class ResourceSet: public QObject
+{
+    Q_OBJECT
+    Q_DISABLE_COPY(ResourceSet)
+public:
+    /**
+     * Alternative constructor with additional parameters for setting
+     * alwaysReply and autoRelease.
+     * \param applicationClass This parameter defines the application class.
+     * The application class is used to determine the priority order of the
+     * application.
+     * \param parent The parent of this class.
+     * \param alwaysReply see setAlwaysReply()
+     * \param autoRelease see setAutoRelease()
+     */
+    ResourceSet(const QString &applicationClass, QObject *parent,
+                bool alwaysReply, bool autoRelease);
+    /**
+     * Alternative backwards-compatible constructor.
+     * \param applicationClass This parameter defines the application class.
+     * The application class is used to determine the priority order of the
+     * application.
+     * \param parent The optional parent of of this class.
+     */
+    ResourceSet(const QString &applicationClass, QObject *parent = NULL);
+    /**
+     * The destructor
+     */
+    ~ResourceSet();
+
+    /**
+     * This method adds a resource to the set. A set contains only a single
+     * instance of a given resource. If the ResourceSet already contains a
+     * resource of the given type it will be overridden.
+     * \param resourceType The resource to add to the set. A copy of this object
+     * is stored in the Set.
+     */
+    bool addResource(ResourceType resourceType);
+
+    /**
+    * This method adds a resource to the set. A set contains only a single
+    * instance of a given resource. If the ResourceSet already contains a
+    * resource of the given type it will be overridden.
+    * \param resource The resource to add to the set.
+    * The ResourcePolicy::ResourseSet takes ownership of the pointer. Do NOT free!
+    */
+    void addResourceObject(Resource *resource);
+
+    /**
+     * This method removes the resource of the given type
+     * \param type The type of the resource to remove from the set.
+     */
+    void deleteResource(ResourceType type);
+
+    /**
+     * This method returns a list of all resource in the set.
+     * \return a QList of all resources in the set.
+     */    QList<Resource *> resources() const;
+    /**
+     * This method returns a const pointer to a resource of a specific type.
+     * \param type The type of resource we are interested in.
+     * \return a pointer to the Resource if it is defined NULL otherwise.
+     */
+    Resource * resource(ResourceType type) const;
+    /**
+     * Checks if the \ref ResourceSet contains the given \ref Resource
+     * \param type The Resource to look for
+     * \return true if the \ref Resource is defined in this \ref ResourceSet
+     */
+    bool contains(ResourceType type) const;
+
+    /**
+     * Checks if the \ref ResourceSet contains all given resources.
+     * \param types A list of resources to check for
+     * \return true if \b all given resources are defined in the ResourceSet.
+     */
+    bool contains(const QList<ResourceType> &types) const;
+
+    /**
+     * Returns the unique identifier for this ResourceSet.
+     * @return the unique identifier for this ResourceSet.
+     */
+    quint32 id() const;
+
+    /**
+     * Returns the registered application class (given in the constructor).
+     */
+    QString applicationClass();
+
+    /**
+      * Initialize and connect the ResourceEngine of this ResourceSet.
+      * Use this method after adding resources to the ResourceSet initially.
+      *  \return true if the method succeeds without encountering errors.
+      */
+    bool initAndConnect();
+
+    /**
+     * Try to acquire the \ref ResourceSet. The resourcesGranted() or
+     * resourcesDenied() signal will be emited depending on whether the
+     * requested resources could be acquired or not.
+     */
+    bool acquire();
+    /**
+     * Release the acquired resources.
+     */
+    bool release();
+    /**
+     * Commit changes to the \ref ResourcePolicy::ResourceSet. Remember to call update()
+     * after adding and/or removing resources.
+     */
+    bool update();
+
+    /**
+     * Sets the auto-release. When loosing the resources due to another
+     * application with a higher priority the default is that we automatically
+     * re-gain our resources without having to re-request them. However if
+     * the AutoRelease is set we release the resources and need to re-acquire
+     * them, when the pre-emting application releases its resources.
+     *
+     * This feature is by default disabled.
+     *
+     * This flag should be set once only before calling anything else
+     * (excluding setAlwaysReply()), and cannot be unset.
+     */
+    bool setAutoRelease();
+    /**
+     * Check whether we have setAutoRelease().
+     * \return true if auto-release is ennabled.
+     */
+    bool willAutoRelease();
+    /**
+     * Sets that the resourcesGranted() signal is emited even if we already
+     * have the requested resources granted. By default this feature is off.
+     *
+     * This flag should be set once only before calling anything else
+     * (excluding setAutoRelease()), and cannot be unset.
+     */
+    bool setAlwaysReply();
+    /**
+     * Check whether the always-get-reply flag has been set.
+     * \return true if we will always get a reply (even if there is no change).
+     */
+    bool alwaysGetReply();
+
+signals:
+    /**
+     * This signal is emited when the Resource Policy Manager notifies that
+     * the given resources have become available.
+     * \param availableResources A list of available resources. The list of
+     * available resources contains only available resource which we have in the set.
+     */
+    void resourcesBecameAvailable(const QList<ResourcePolicy::ResourceType> &availableResources);
+    /**
+     * This signal is emitted as a response to the acquire() request.
+     * \param grantedOptionalResources The list of granted optional resources.
+     * All the mandatory resources have also been acquired.
+     */
+    void resourcesGranted(const QList<ResourcePolicy::ResourceType> &grantedOptionalResources);
+    /**
+     * This signal is emitted as a response to the acquire() request, in the
+     * case where one or more of the mandatory resources were not available.
+     */
+    void resourcesDenied();
+    /**
+     * This signal is emitted as a response to the release() request.
+     */
+    void resourcesReleased();
+    /**
+      * This signal is emited when the manager releases our acquired resources,
+      * so that we have to acquire them again when the user wishes to interact
+      * with us.
+      */
+    void resourcesReleasedByManager();
+    /**
+     * This signal is emitted when some other program with a higher priority
+     * supersedes us, and as a result we loose (some of) our resources.
+     * It is very important to connect to this signal as it is signaling when
+     * the acquired resources shouldn't be used anymore.
+     */
+    void lostResources();
+
+    /**
+     * Subscribe to this signal to receive error notifications,
+     * particularly security errors.
+     */
+    void errorCallback(quint32, const char*);
+
+    /**
+      * This signals that we have connected to the Resource Manager.
+      */
+    void connectedToManager();
+
+private:
+
+    bool initialize();
+
+    quint32 identifier;
+    const QString resourceClass;
+    Resource* resourceSet[NumberOfTypes];
+    ResourceEngine *resourceEngine;
+    AudioResource *audioResource;
+    bool autoRelease;
+    bool alwaysReply;
+    bool initialized;
+    bool pendingAcquire;
+    bool pendingUpdate;
+    bool pendingAudioProperties;
+    bool haveAudioProperties;
+
+    void registerAudioProperties();
+
+private slots:
+    void connectedHandler();
+    void handleGranted(quint32);
+    void handleDeny();
+    void handleReleased();
+    void handleResourcesLost(quint32);
+    void handleResourcesBecameAvailable(quint32);
+
+    void handleAudioPropertiesChanged(const QString &group, quint32 pid,
+                                      const QString &name, const QString &value);
+
+};
+}
+
+#endif
+
diff --git a/src/policy/resource.h b/src/policy/resource.h
new file mode 100644 (file)
index 0000000..a4d3c0a
--- /dev/null
@@ -0,0 +1,144 @@
+/*************************************************************************
+This file is part of libresourceqt
+
+Copyright (C) 2010 Nokia Corporation.
+
+This library is free software; you can redistribute
+it and/or modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation
+version 2.1 of the License.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+USA.
+*************************************************************************/
+/**
+ * @file resource.h
+ * @brief Declaration of ResourcePolicy::Resource and
+ * ResourcePolicy::ResourceType
+ *
+ * @copyright Copyright (C) 2010 Nokia Corporation.
+ * @author Wolf Bergenheim
+ * \par License
+ * @license LGPL
+ * This file is part of libresourceqt
+ * \par
+ * Copyright (C) 2010 Nokia Corporation.
+ * \par
+ * This library is free software; you can redistribute
+ * it and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation
+ * version 2.1 of the License.
+ * \par
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * \par
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA.
+ */
+
+#ifndef RESOURCE_H
+#define RESOURCE_H
+
+#include <QtCore>
+
+namespace ResourcePolicy
+{
+/**
+  * This enumeration represents the resources which can be reserved.
+  * \see ResourcePolicy::ResourceSet for info on how to reserve resources.
+  */
+enum ResourceType {
+    AudioPlaybackType = 0, ///< For audio playback
+    VideoPlaybackType,     ///< For video playback
+    AudioRecorderType,     ///< For audio recording (using of the microphone)
+    VideoRecorderType,     ///< For video recording (using the camera)
+    VibraType,             ///< For Vibra
+    LedsType,              ///< For LEDs
+    BacklightType,         ///< For the backlight (of the display)
+    SystemButtonType,      ///< For the system (power) button
+    LockButtonType,        ///< For the lock button
+    ScaleButtonType,       ///< The scale (zoom) button
+    SnapButtonType,        ///< Use this if you are a camera application
+    LensCoverType,
+    HeadsetButtonsType,    ///< Use this to reserve the headset buttons
+    NumberOfTypes
+};
+
+class ResourceSet;
+
+/**
+ * This class is the super class for all resources. It represents a generic
+ * \ref Resource. The type specific resource classes should be used.
+ */
+class Resource
+{
+    friend class ResourceSet;
+public:
+    /**
+     * Whether or not this resource is optional, in that it doesn't need to
+     * be available for the set to be acquired.
+     * \return true when this resource is optional.
+     */
+    bool isOptional() const;
+    /**
+     * Set the resource to be optional or mandatory.
+     * \param resourceIsOptional This optional parameter defaults to true.
+     * The default, true, results in the resource becoming optional. When it
+     * is set to false the resource becomes mandatory.
+     */
+    void setOptional(bool resourceIsOptional = true);
+    /**
+     * Whether or not the resource to be shared. If it is shared then other
+     * programs are allowed to share this resource.
+     * \return true when this resource is shared.
+     */
+    bool isGranted() const;
+
+    /**
+     * Use this method to check for the type of Resource
+     * \return The ResourceType associated to this resource
+     */
+    virtual ResourceType type() const = 0;
+    virtual ~Resource();
+protected:
+    Resource();
+    Resource(const Resource &other);
+
+    /**
+     * \internal
+     * This holds the type of the resource.
+     */
+    ResourceType resourceType;
+    /**
+     * \internal
+     * This is true when this resource is optional.
+     * \sa isOptional
+     * \sa setOptional
+     */
+    bool optional;
+    /**
+     * \internal
+     * This is just a unique identifier for the resource.
+     */
+    quint32 identifier;
+private:
+    void setGranted();
+    void unsetGranted();
+    bool granted;
+
+};
+}
+
+#endif
+
diff --git a/src/policy/resources.h b/src/policy/resources.h
new file mode 100644 (file)
index 0000000..f8f6c0b
--- /dev/null
@@ -0,0 +1,384 @@
+/*************************************************************************
+This file is part of libresourceqt
+
+Copyright (C) 2010 Nokia Corporation.
+
+This library is free software; you can redistribute
+it and/or modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation
+version 2.1 of the License.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+USA.
+*************************************************************************/
+/**
+ * @file resources.h
+ * @brief Declaration of The different resource classes: 
+ * ResourcePolicy::AudioRecorderResource
+ * ResourcePolicy::BacklightResource
+ * ResourcePolicy::LedsResource
+ * ResourcePolicy::VibraResource
+ * ResourcePolicy::VideoRecorderResource
+ * ResourcePolicy::VideoResource
+ * ResourcePolicy::LockButtonResource
+ * ResourcePolicy::ScaleButtonResource
+ * ResourcePolicy::SystemButtonResource
+ * ResourcePolicy::LensCoverResource
+ * ResourcePolicy::HeadsetButtonsResource
+ *
+ * @copyright Copyright (C) 2010 Nokia Corporation.
+ * @author Wolf Bergenheim
+ * \par License
+ * @license LGPL
+ * This file is part of libresourceqt
+ * \par
+ * Copyright (C) 2010 Nokia Corporation.
+ * \par
+ * This library is free software; you can redistribute
+ * it and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation
+ * version 2.1 of the License.
+ * \par
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * \par
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA.
+ */
+
+#ifndef RESOURCES_H
+#define RESOURCES_H
+
+#include <policy/resource.h>
+#include <QString>
+
+namespace ResourcePolicy
+{
+
+/**
+ * The AudioRecorderResource class represents the audio recorder device.
+ */
+class AudioRecorderResource: public Resource
+{
+public:
+       /**
+     * The constructor.
+     */
+    AudioRecorderResource();
+       /**
+     * The copy constructor.
+     * \param other The resource to copy from
+     */
+    AudioRecorderResource(const AudioRecorderResource &other);
+       /**
+     * The destructor.
+     */
+    virtual ~AudioRecorderResource();
+
+       /**
+     * \return the resource type
+     */
+    virtual ResourceType type() const;
+};
+
+/**
+ * The BacklightResource is used by applications wanting to control the
+ * backlight
+ */
+class BacklightResource: public Resource
+{
+public:
+       /**
+     * The constructor.
+     */
+    BacklightResource();
+       /**
+     * The copy constructor.
+     * \param other The resource to copy from
+     */
+    BacklightResource(const BacklightResource &other);
+       /**
+     * The destructor.
+     */
+    virtual ~BacklightResource();
+
+       /**
+     * \return the resource type
+     */
+    virtual ResourceType type() const;
+};
+
+/**
+ * Resource to be used when the application wants to fiddle with the leds.
+ */
+class LedsResource: public Resource
+{
+public:
+       /**
+     * The constructor.
+     */
+    LedsResource();
+       /**
+     * The copy constructor.
+     * \param other The resource to copy from
+     */
+    LedsResource(const LedsResource &other);
+       /**
+     * The destructor.
+     */
+    virtual ~LedsResource();
+
+       /**
+     * \return the resource type
+     */
+    virtual ResourceType type() const;
+};
+
+/**
+ * Resource to be used when the application wants to use the vibra.
+ */
+class VibraResource: public Resource
+{
+public:
+       /**
+     * The constructor.
+     */
+    VibraResource();
+       /**
+     * The copy constructor.
+     * \param other The resource to copy from
+     */
+    VibraResource(const VibraResource &other);
+       /**
+     * The destructor.
+     */
+    virtual ~VibraResource();
+
+       /**
+     * \return the resource type
+     */
+    virtual ResourceType type() const;
+};
+
+/**
+ * Resource to be used when the application wants to record video.
+ */
+class VideoRecorderResource: public Resource
+{
+public:
+       /**
+     * The constructor.
+     */
+    VideoRecorderResource();
+       /**
+     * The copy constructor.
+     * \param other The resource to copy from
+     */
+    VideoRecorderResource(const VideoRecorderResource &other);
+       /**
+     * The destructor.
+     */
+    virtual ~VideoRecorderResource();
+
+       /**
+     * \return the resource type
+     */
+    virtual ResourceType type() const;
+};
+
+/**
+ * Resource to be used when the application wants to render video with the
+ * DSP decoder to render the viewfinder.
+ */
+class VideoResource: public Resource
+{
+public:
+       /**
+     * The constructor.
+     */
+    VideoResource();
+       /**
+     * The copy constructor.
+     * \param other The resource to copy from
+     */
+    VideoResource(const VideoResource &other);
+       /**
+     * The destructor.
+     */
+    virtual ~VideoResource();
+
+       /**
+     * \return the resource type
+     */
+    virtual ResourceType type() const;
+};
+
+/**
+ * Resource to be used when the application wants to control the system button.
+ */
+class SystemButtonResource: public Resource
+{
+public:
+       /**
+     * The constructor.
+     */
+    SystemButtonResource();
+       /**
+     * The copy constructor.
+     * \param other The resource to copy from
+     */
+    SystemButtonResource(const SystemButtonResource &other);
+       /**
+     * The destructor.
+     */
+    virtual ~SystemButtonResource();
+
+       /**
+     * \return the resource type
+     */
+    virtual ResourceType type() const;
+};
+
+/**
+ * Resource to be used when the application wants to control the lock button.
+ */
+class LockButtonResource: public Resource
+{
+public:
+       /**
+     * The constructor.
+     */
+    LockButtonResource();
+       /**
+     * The copy constructor.
+     * \param other The resource to copy from
+     */
+    LockButtonResource(const LockButtonResource &other);
+       /**
+     * The destructor.
+     */
+    virtual ~LockButtonResource();
+
+       /**
+     * \return the resource type
+     */
+    virtual ResourceType type() const;
+};
+
+/**
+ * Resource to be used when the application wants to control
+ * the volume/scale button.
+ */
+class ScaleButtonResource: public Resource
+{
+public:
+       /**
+     * The constructor.
+     */
+    ScaleButtonResource();
+       /**
+     * The copy constructor.
+     * \param other The resource to copy from
+     */
+    ScaleButtonResource(const ScaleButtonResource &other);
+       /**
+     * The destructor.
+     */
+    virtual ~ScaleButtonResource();
+
+       /**
+     * \return the resource type
+     */
+    virtual ResourceType type() const;
+};
+
+/**
+ * Resource to be used when the application wants to take still pictures.
+ */
+class SnapButtonResource: public Resource
+{
+public:
+       /**
+     * The constructor.
+     */
+    SnapButtonResource();
+       /**
+     * The copy constructor.
+     * \param other The resource to copy from
+     */
+    SnapButtonResource(const SnapButtonResource &other);
+       /**
+     * The destructor.
+     */
+    virtual ~SnapButtonResource();
+
+       /**
+     * \return the resource type
+     */
+    virtual ResourceType type() const;
+};
+
+class LensCoverResource: public Resource
+{
+public:
+       /**
+     * The constructor.
+     */
+    LensCoverResource();
+       /**
+     * The copy constructor.
+     * \param other The resource to copy from
+     */
+    LensCoverResource(const LensCoverResource &other);
+       /**
+     * The destructor.
+     */
+    virtual ~LensCoverResource();
+
+       /**
+     * \return the resource type
+     */
+    virtual ResourceType type() const;
+};
+
+/**
+ * Resource to be used when the application wants to control the
+ * headset buttons.
+ */
+class HeadsetButtonsResource: public Resource
+{
+public:
+       /**
+     * The constructor.
+     */
+    HeadsetButtonsResource();
+       /**
+     * The copy constructor.
+     * \param other The resource to copy from
+     */
+    HeadsetButtonsResource(const HeadsetButtonsResource &other);
+       /**
+     * The destructor.
+     */
+    virtual ~HeadsetButtonsResource();
+
+       /**
+     * \return the resource type
+     */
+    virtual ResourceType type() const;
+};
+
+}
+#endif
+
diff --git a/src/qmlcallitem.cpp b/src/qmlcallitem.cpp
new file mode 100644 (file)
index 0000000..4cfe59c
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * 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
+   return 32;    
+
+    if (d->proxy->callProxy())
+        return d->proxy->callProxy()->duration();
+    return 66;
+}
+
+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());
+}
diff --git a/src/qmlcallitem.h b/src/qmlcallitem.h
new file mode 100644 (file)
index 0000000..4ea34ec
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * 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
diff --git a/src/qmldialer.cpp b/src/qmldialer.cpp
new file mode 100644 (file)
index 0000000..4b97ec9
--- /dev/null
@@ -0,0 +1,271 @@
+/*
+ * 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()));
+
+    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()->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;
+}
+
+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()
+{
+  /*  TRACE
+    CallManager *cm = ManagerProxy::instance()->callManager();
+    if (cm && cm->isValid())
+        cm->createMultiparty();
+*/
+}
+
+void QMLDialer::hangupMultiparty()
+{
+/*
+    TRACE
+    CallManager *cm = ManagerProxy::instance()->callManager();
+    if (cm && cm->isValid())
+        cm->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;
+    }
+}
+
+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 (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);
+}
diff --git a/src/qmldialer.h b/src/qmldialer.h
new file mode 100644 (file)
index 0000000..66475bc
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * 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)
+
+public:
+    explicit QMLDialer(QObject *parent = 0);
+            ~QMLDialer();
+
+    QString      mailbox        () const;
+    QMLCallItem* currentCall    () const;
+    bool         modemOnline    ();
+
+Q_SIGNALS:
+    void incomingCall();
+    void outgoingCall();
+
+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
diff --git a/src/qmlmainwindow.cpp b/src/qmlmainwindow.cpp
new file mode 100644 (file)
index 0000000..cf008a7
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * 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.tizen.hfdialer", 1, 0, "Dialer");
+
+    qmlRegisterUncreatableType<QMLCallItem>("com.tizen.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();
+
+    da->setActiveWindow(this);
+
+    connect(this->engine(), SIGNAL(quit()), this, SLOT(close()));
+}
+
+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->addImportPath("/usr/share/hfdialer/qml/base");
+
+    d->engine->rootContext()->setContextProperty("controller", this); //TODO: Remove
+   // d->engine->rootContext()->setContextProperty("History", DialerApplication::instance()->historyProxy());
+    this->setSource(QUrl::fromLocalFile("/usr/share/hfdialer/qml/main.qml"));
+    //this->setResizeMode(QDeclarativeView::SizeRootObjectToView);
+    //this->setSize(this->geometry);
+    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();
+       da->activeWindow()->raise();
+       this->show();
+    }
+}
+void QMLMainWindow::hide()
+{
+    TRACE
+    QGraphicsView::hide();
+}
+
+void QMLMainWindow::closeEvent(QCloseEvent *event)
+{
+    TRACE
+/*    if(this->closeOnLazyShutdown())
+    {
+        this->setCloseOnLazyShutdown(false);
+    }
+*/
+    event->accept();
+
+}
+
+void QMLMainWindow::onGeometryChanged()
+{
+    TRACE
+   // d->item->setSize(d->widget->size());
+}
+
+void QMLMainWindow::setAdapter(QMLDialer *adapter)
+{
+    TRACE
+    d->adapter = adapter;
+}
diff --git a/src/qmlmainwindow.h b/src/qmlmainwindow.h
new file mode 100644 (file)
index 0000000..d6a0099
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * 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();
+
+public Q_SLOTS:
+    void hide();
+    void tryToShow();
+    
+    void setAdapter(QMLDialer *adapter); //TODO: Refactor out
+
+protected Q_SLOTS:
+    void setupUi();
+
+    void onGeometryChanged();
+
+protected:
+    virtual void closeEvent(QCloseEvent *event);
+
+private:
+    explicit QMLMainWindow(QWidget *parent = 0);
+    QMLMainWindowPrivate *d;
+    QDeclarativeView qv;
+    Q_DISABLE_COPY(QMLMainWindow)
+};
+
+#endif // QMLMAINWINDOW_H
diff --git a/src/src.pro b/src/src.pro
new file mode 100644 (file)
index 0000000..9000eee
--- /dev/null
@@ -0,0 +1,77 @@
+include (../common.pri)
+TEMPLATE = app
+QT += dbus declarative
+CONFIG += qdbus mobility qt-mobility link_pkgconfig network debug
+PKGCONFIG += libpulse-mainloop-glib
+MOBILITY += contacts multimedia
+MOC_DIR = .moc
+OBJECTS_DIR = .obj
+MGEN_OUTDIR = .gen
+
+if (wayland) {
+    PKGCONFIG += mlite-wayland ofono-qt-wayland
+} else {
+    PKGCONFIG += mlite-xlib ofono-qt-xlib
+}
+
+DEFINES += CONFIG_DEFAULT_TARGET_UX=\\\"tizen-ux-components\\\"
+
+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
+
+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 \
+    $$DBUS_INTERFACE_HEADERS \
+    $$DBUS_ADAPTOR_HEADERS \
+    qmlmainwindow.h \
+    qmldialer.h \
+    qmlcallitem.h \
+    dbusdialeradapter.h
+
+DBUS_ADAPTORS += dbus/com.tizen.hfdialer.xml
+
+DBUS_INTERFACES += \
+    dbus/org.ofono.voicecall.xml \
+    dbus/org.ofono.manager.xml \
+    dbus/org.ofono.modem.xml \
+    dbus/org.ofono.operator.xml \
+
+    system(qdbusxml2cpp -a dialer_adaptor.h: dbus/com.tizen.hfdialer.xml)
+    system(qdbusxml2cpp -i dbustypes.h -p manager_interface.h: dbus/org.ofono.manager.xml)
+    system(qdbusxml2cpp -i dbustypes.h -p modem_interface.h: 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