mirror of
https://github.com/status-im/qzxing.git
synced 2025-02-12 19:06:50 +00:00
Added example with proper handling of Android application permissions for QZXingLive triggered by #22
This commit is contained in:
parent
5ef72fa114
commit
29860c538c
3
.gitignore
vendored
3
.gitignore
vendored
@ -22,3 +22,6 @@ debug/
|
||||
*.sln
|
||||
*.suo
|
||||
*.vcxproj*
|
||||
.gradle
|
||||
.idea
|
||||
.build
|
||||
|
@ -4,7 +4,18 @@ QT += qml quick
|
||||
|
||||
CONFIG += c++11 qzxing_multimedia
|
||||
|
||||
SOURCES += main.cpp
|
||||
CONFIG(debug, debug|release) {
|
||||
CONFIG+=qml_debug
|
||||
} else {
|
||||
DEFINES += QT_NO_DEBUG
|
||||
DEFINES += QT_NO_DEBUG_OUTPUT
|
||||
}
|
||||
|
||||
HEADERS += \
|
||||
application.h
|
||||
|
||||
SOURCES += main.cpp \
|
||||
application.cpp
|
||||
|
||||
RESOURCES += qml.qrc
|
||||
|
||||
@ -16,20 +27,30 @@ include(../../src/QZXing.pri)
|
||||
# Default rules for deployment.
|
||||
include(deployment.pri)
|
||||
|
||||
DISTFILES += \
|
||||
android/AndroidManifest.xml \
|
||||
android/gradle/wrapper/gradle-wrapper.jar \
|
||||
android/gradlew \
|
||||
android/res/values/libs.xml \
|
||||
android/build.gradle \
|
||||
android/gradle/wrapper/gradle-wrapper.properties \
|
||||
android/gradlew.bat \
|
||||
android/AndroidManifest.xml \
|
||||
android/gradle/wrapper/gradle-wrapper.jar \
|
||||
android/gradlew \
|
||||
android/res/values/libs.xml \
|
||||
android/build.gradle \
|
||||
android/gradle/wrapper/gradle-wrapper.properties \
|
||||
android/gradlew.bat
|
||||
android {
|
||||
QT += androidextras
|
||||
|
||||
ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android
|
||||
HEADERS += \
|
||||
native.h
|
||||
|
||||
SOURCES += \
|
||||
native.cpp
|
||||
|
||||
DISTFILES += \
|
||||
android/AndroidManifest.xml \
|
||||
android/gradle/wrapper/gradle-wrapper.jar \
|
||||
android/gradlew \
|
||||
android/res/values/libs.xml \
|
||||
android/build.gradle \
|
||||
android/gradle/wrapper/gradle-wrapper.properties \
|
||||
android/gradlew.bat \
|
||||
android/AndroidManifest.xml \
|
||||
android/gradle/wrapper/gradle-wrapper.jar \
|
||||
android/gradlew \
|
||||
android/res/values/libs.xml \
|
||||
android/build.gradle \
|
||||
android/gradle/wrapper/gradle-wrapper.properties \
|
||||
android/gradlew.bat
|
||||
|
||||
ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0"?>
|
||||
<manifest package="org.qtproject.example" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="1.0" android:versionCode="1" android:installLocation="auto">
|
||||
<application android:hardwareAccelerated="true" android:name="org.qtproject.qt5.android.bindings.QtApplication" android:label="QZXingLive" android:icon="@drawable/icon">
|
||||
<activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation" android:name="org.qtproject.qt5.android.bindings.QtActivity" android:label="QZXingLive" android:screenOrientation="unspecified" android:launchMode="singleTop">
|
||||
<activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation" android:name="org.ftylitak.qzxing.QZXingLiveActivity" android:label="QZXingLive" android:screenOrientation="unspecified" android:launchMode="singleTop">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
|
@ -4,7 +4,7 @@ buildscript {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:1.1.0'
|
||||
classpath 'com.android.tools.build:gradle:2.2.2'
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,6 +18,8 @@ apply plugin: 'com.android.application'
|
||||
|
||||
dependencies {
|
||||
compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||
compile 'com.android.support:appcompat-v7:25.0.1'
|
||||
compile 'com.android.support:design:25.0.1'
|
||||
}
|
||||
|
||||
android {
|
||||
|
@ -1,6 +1,6 @@
|
||||
#Wed Apr 10 15:27:10 PDT 2013
|
||||
#Sun Jan 29 12:19:44 EET 2017
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
|
||||
|
@ -0,0 +1,6 @@
|
||||
package org.ftylitak.qzxing;
|
||||
|
||||
public class NativeFunctions {
|
||||
public static native void onPermissionsGranted();
|
||||
public static native void onPermissionsDenied();
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package org.ftylitak.qzxing;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.pm.PackageManager;
|
||||
import org.qtproject.qt5.android.bindings.QtActivity;
|
||||
import static org.ftylitak.qzxing.Utilities.REQUEST_CAMERA;
|
||||
|
||||
public class QZXingLiveActivity extends QtActivity {
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode,
|
||||
String permissions[], int[] grantResults) {
|
||||
switch (requestCode) {
|
||||
case REQUEST_CAMERA: {
|
||||
// If request is cancelled, the result arrays are empty.
|
||||
if (grantResults.length > 0
|
||||
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
NativeFunctions.onPermissionsGranted();
|
||||
} else {
|
||||
NativeFunctions.onPermissionsDenied();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package org.ftylitak.qzxing;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class Utilities {
|
||||
|
||||
public static final int REQUEST_CAMERA = 0;
|
||||
|
||||
public static final String[] requiredPermissionsModifyPhoneState = {
|
||||
Manifest.permission.CAMERA,
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE
|
||||
};
|
||||
|
||||
public static void checkAndRequestPermissionList(Activity activity, String[] permissions) {
|
||||
ArrayList<String> permissionsToRequest = new ArrayList<>();
|
||||
for (int i = 0; i < permissions.length; i++) {
|
||||
if (ContextCompat.checkSelfPermission(activity, permissions[i])
|
||||
!= PackageManager.PERMISSION_GRANTED)
|
||||
permissionsToRequest.add(permissions[i]);
|
||||
}
|
||||
|
||||
if (permissionsToRequest.size() != 0)
|
||||
ActivityCompat.requestPermissions(activity,
|
||||
permissionsToRequest.toArray(new String[0]),
|
||||
REQUEST_CAMERA);
|
||||
else
|
||||
NativeFunctions.onPermissionsGranted();
|
||||
}
|
||||
|
||||
public static void requestQZXingPermissions(Activity activity) {
|
||||
checkAndRequestPermissionList(activity, requiredPermissionsModifyPhoneState);
|
||||
}
|
||||
|
||||
|
||||
}
|
44
examples/QZXingLive/application.cpp
Normal file
44
examples/QZXingLive/application.cpp
Normal file
@ -0,0 +1,44 @@
|
||||
#include "application.h"
|
||||
#include <QDebug>
|
||||
#include "native.h"
|
||||
|
||||
#if defined(Q_OS_ANDROID)
|
||||
#include <QAndroidJniObject>
|
||||
#include <QtAndroid>
|
||||
|
||||
#endif // Q_OS_ANDROID
|
||||
|
||||
Application::Application()
|
||||
{
|
||||
//both signals will be connected to the same function for
|
||||
//simplicity
|
||||
|
||||
connect(this, &Application::onPermissionsGranted,
|
||||
this, &Application::initializeQML);
|
||||
|
||||
connect(this, &Application::onPermissionsDenied,
|
||||
this, &Application::initializeQML);
|
||||
|
||||
NativeHelpers::registerApplicationInstance(this);
|
||||
}
|
||||
|
||||
void Application::initializeQML()
|
||||
{
|
||||
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
|
||||
}
|
||||
|
||||
void Application::checkPermissions()
|
||||
{
|
||||
#if defined(Q_OS_ANDROID)
|
||||
//intentionally called in the C++ thread since it is blocking and will continue after the check
|
||||
qDebug() << "About to request permissions";
|
||||
|
||||
QAndroidJniObject::callStaticMethod<void>("org/ftylitak/qzxing/Utilities",
|
||||
"requestQZXingPermissions",
|
||||
"(Landroid/app/Activity;)V",
|
||||
QtAndroid::androidActivity().object());
|
||||
qDebug() << "Permissions granted";
|
||||
#else
|
||||
emit onPermissionsGranted();
|
||||
#endif //Q_OS_ANDROID
|
||||
}
|
27
examples/QZXingLive/application.h
Normal file
27
examples/QZXingLive/application.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef APPLICATION_H
|
||||
#define APPLICATION_H
|
||||
|
||||
#include <QQmlApplicationEngine>
|
||||
#include <QObject>
|
||||
|
||||
class Application : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Application();
|
||||
|
||||
void checkPermissions();
|
||||
|
||||
public slots:
|
||||
void initializeQML();
|
||||
|
||||
signals:
|
||||
void onPermissionsGranted();
|
||||
void onPermissionsDenied();
|
||||
|
||||
private:
|
||||
QQmlApplicationEngine engine;
|
||||
};
|
||||
|
||||
#endif // APPLICATION_H
|
@ -6,15 +6,17 @@
|
||||
|
||||
#include <Qt>
|
||||
#include <QZXing.h>
|
||||
#include "application.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
|
||||
QGuiApplication app(argc, argv);
|
||||
QQmlApplicationEngine engine;
|
||||
|
||||
QZXing::registerQMLTypes();
|
||||
|
||||
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
|
||||
Application customApp;
|
||||
customApp.checkPermissions();
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
|
47
examples/QZXingLive/native.cpp
Normal file
47
examples/QZXingLive/native.cpp
Normal file
@ -0,0 +1,47 @@
|
||||
#include <jni.h>
|
||||
#include "native.h"
|
||||
#include <QMetaObject>
|
||||
|
||||
QObject *NativeHelpers::application_p_ = 0;
|
||||
|
||||
// define our native static functions
|
||||
// these are the functions that Java part will call directly from Android UI thread
|
||||
static void onPermissionsGranted(JNIEnv * /*env*/, jobject /*obj*/)
|
||||
{
|
||||
QMetaObject::invokeMethod(NativeHelpers::getApplicationInstance(), "onPermissionsGranted"
|
||||
, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
static void onPermissionsDenied(JNIEnv * /*env*/, jobject /*obj*/)
|
||||
{
|
||||
QMetaObject::invokeMethod(NativeHelpers::getApplicationInstance(), "onPermissionsDenied"
|
||||
, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
//create a vector with all our JNINativeMethod(s)
|
||||
static JNINativeMethod methods[] = {
|
||||
{"onPermissionsGranted", "()V", (void *)onPermissionsGranted},
|
||||
{"onPermissionsDenied", "()V", (void *)onPermissionsDenied},
|
||||
};
|
||||
|
||||
// this method is called automatically by Java after the .so file is loaded
|
||||
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* /*reserved*/)
|
||||
{
|
||||
JNIEnv* env;
|
||||
// get the JNIEnv pointer.
|
||||
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK)
|
||||
return JNI_ERR;
|
||||
|
||||
// search for Java class which declares the native methods
|
||||
jclass javaClass = env->FindClass("org/ftylitak/qzxing/NativeFunctions");
|
||||
if (!javaClass)
|
||||
return JNI_ERR;
|
||||
|
||||
// register our native methods
|
||||
if (env->RegisterNatives(javaClass, methods,
|
||||
sizeof(methods) / sizeof(methods[0])) < 0) {
|
||||
return JNI_ERR;
|
||||
}
|
||||
|
||||
return JNI_VERSION_1_6;
|
||||
}
|
20
examples/QZXingLive/native.h
Normal file
20
examples/QZXingLive/native.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef NATIVE_H
|
||||
#define NATIVE_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class NativeHelpers {
|
||||
public:
|
||||
static void registerApplicationInstance(QObject *app_p) {
|
||||
application_p_ = app_p;
|
||||
}
|
||||
|
||||
static QObject* getApplicationInstance() {
|
||||
return application_p_;
|
||||
}
|
||||
|
||||
private:
|
||||
static QObject *application_p_;
|
||||
};
|
||||
|
||||
#endif // NATIVE_H
|
Loading…
x
Reference in New Issue
Block a user