android - How to make a call with Qt directly from the application? -


i want implement dialer-feature in app. actually, it's done, works way don't want to. when button pressed, native dialer opens , waiting pressing button. possible call directly without double pressing? here's code:

button {         id: callbutton         anchors.centerin: parent         text: 'make call'         onclicked: qt.openurlexternally('tel:+77051085322')     } 

whereas in ios call can issued directly, same not apply android. overcome problem can define c++ class wrapper handles call, depending on current os. instance of class registered context property , directly used in qml.

inside class can exploit android native apis provide automatic dialing feature via intent action action_call (but remember there restrictions in using it). typically in android write:

intent callintent = new callintent(intent.action_call); callintent.setpackage("com.android.phone");          // force native dialer  (android < 5) callintent.setpackage("com.android.server.telecom"); // force native dialer  (android >= 5) callintent.setdata(uri.parse("tel:" + number)); callintent.setflags(intent.flag_activity_new_task); startactivity(callintent); 

by setting package can force usage of native dialer. without user prompt choose among available dialers (i.e. skype, viber, etc...) clearly if other installed on device. system dialer package changed between lollipop , previous releases necessary check sdk @ runtime set correct one.


to call these apis in c++ need qt android extras , in particular qandroidjniobject related permissions in custom android manifest. add .pro file:

android: qt += androidextras  #included in android builds 

and following row manifest:

<uses-permission android:name="android.permission.call_phone"/> 

if did not define custom manifest add one. of qt creator 3.3 go projects > build > build android apk > create templates generate custom manifest.


the header of our class looks following - constructor/deconstructor missing:

#ifndef wrapper_h #define wrapper_h #include <qobject> #include <qstring> #include <qdebug> #if defined(q_os_ios) #include <qurl> #include <qdesktopservices> #elif defined(q_os_android) #include <qtandroid> #include <qandroidjniobject> #endif  #include <qdesktopservices> #include <qurl>  class wrapper: public qobject {     q_object public:     q_invokable void directcall(qstring number); };  #endif // wrapper_h 

the corresponding source file looks following - again constructor/deconstructor missing:

#include "wrapper.h"  void wrapper::directcall(qstring number) { #if defined(q_os_ios)     qdesktopservices::openurl(qurl(qstring("tel://%1").arg(number))); #elif defined(q_os_android)     // qt android activity     qandroidjniobject activity =  qandroidjniobject::callstaticobjectmethod("org/qtproject/qt5/android/qtnative", "activity", "()landroid/app/activity;");     //     if (activity.isvalid()){     // real java code c++ code     // intent callintent = new callintent(intent.action_call);     qandroidjniobject callconstant = qandroidjniobject::getstaticobjectfield<jstring>("android/content/intent", "action_call");     qandroidjniobject callintent("android/content/intent",  "(ljava/lang/string;)v", callconstant.object());     // callintent.setpackage("com.android.phone"); (<= 4.4w)  intent.setpackage("com.android.server.telecom");  (>= 5)     qandroidjniobject package;     if(qtandroid::androidsdkversion() >= 21)         package = qandroidjniobject::fromstring("com.android.server.telecom");     else         package = qandroidjniobject::fromstring("com.android.phone");     callintent.callobjectmethod("setpackage", "(ljava/lang/string;)landroid/content/intent;", package.object<jstring>());     // callintent.setdata(uri.parse("tel:" + number));     qandroidjniobject jnumber = qandroidjniobject::fromstring(qstring("tel:%1").arg(number));     qandroidjniobject uri = qandroidjniobject::callstaticobjectmethod("android/net/uri","parse","(ljava/lang/string;)landroid/net/uri;", jnumber.object());     callintent.callobjectmethod("setdata", "(landroid/net/uri;)landroid/content/intent;", uri.object<jobject>());     // callintent.setflags(intent.flag_activity_new_task);     jint flag = qandroidjniobject::getstaticfield<jint>("android/content/intent", "flag_activity_new_task");     callintent.callobjectmethod("setflags", "(i)landroid/content/intent;", flag);     //startactivity(callintent);     activity.callmethod<void>("startactivity","(landroid/content/intent;)v", callintent.object<jobject>()); }     else         qdebug() << "something wrong qt activity..."; #else     qdebug() << "does nothing here..."; #endif } 

as discussed @ beginning, can include instance of class context property. main purpose looks following:

#include <qapplication> #include <qqmlcontext> #include <qqmlapplicationengine> #include "wrapper.h"  int main(int argc, char *argv[]) {     qapplication app(argc, argv);      qqmlapplicationengine engine;     wrapper jw;     engine.rootcontext()->setcontextproperty("caller", &jw);     engine.load(qurl(qstringliteral("qrc:/main.qml")));            return app.exec(); } 

finally in qml can write:

button {     id: callbutton     anchors.centerin: parent     text: 'make call'     onclicked: caller.directcall("+0123456789") } 

the code can extended support winphone while maintaining same qml interface (probably via inclusion of dedicated header/source pair). finally, usage of conditional inclusions guarantees code correctly compiles if used kit changed on fly.

as final note, add google play policies not strict apple app store policies. hence, app rejection due usage of action_call not happen.


Comments

Popular posts from this blog

google chrome - Developer tools - How to inspect the elements which are added momentarily (by JQuery)? -

angularjs - Showing an empty as first option in select tag -

php - Cloud9 cloud IDE and CakePHP -