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
Post a Comment