Update permission handling
This commit is contained in:
parent
a5bea39212
commit
b847d5ba59
@ -227,7 +227,7 @@ public class NymeaAppControlService extends ControlsProviderService {
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
|
||||
intent.putExtra("nymeaId", nymeaId.toString());
|
||||
intent.putExtra("thingId", thing.id.toString());
|
||||
pi = PendingIntent.getActivity(context, intentId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
pi = PendingIntent.getActivity(context, intentId, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
|
||||
Log.d(TAG, "Created pendingintent for " + thing.name + " with id " + intentId + " and extra " + thing.id);
|
||||
|
||||
Control.StatefulBuilder builder = new Control.StatefulBuilder(thing.id.toString(), pi)
|
||||
|
||||
@ -36,7 +36,6 @@
|
||||
#include "thingmanager.h"
|
||||
#include "connection/nymeatransportinterface.h"
|
||||
#include "jsonrpc/jsonrpcclient.h"
|
||||
#include "wifisetup/bluetoothdiscovery.h"
|
||||
|
||||
class RuleManager;
|
||||
class ScriptManager;
|
||||
|
||||
@ -73,6 +73,8 @@
|
||||
#include "configuration/serverconfigurations.h"
|
||||
#include "configuration/mqttpolicy.h"
|
||||
#include "configuration/mqttpolicies.h"
|
||||
#include "wifisetup/bluetoothdeviceinfos.h"
|
||||
#include "wifisetup/bluetoothdiscovery.h"
|
||||
#include "wifisetup/btwifisetup.h"
|
||||
#include "types/wirelessaccesspoint.h"
|
||||
#include "types/wirelessaccesspoints.h"
|
||||
|
||||
@ -45,6 +45,7 @@
|
||||
#include "nfchelper.h"
|
||||
#include "nfcthingactionwriter.h"
|
||||
#include "platformhelper.h"
|
||||
#include "platformintegration/platformpermissions.h"
|
||||
#include "dashboard/dashboardmodel.h"
|
||||
#include "dashboard/dashboarditem.h"
|
||||
#include "mouseobserver.h"
|
||||
@ -169,6 +170,7 @@ int main(int argc, char *argv[])
|
||||
engine->rootContext()->setContextProperty("styleController", &styleController);
|
||||
|
||||
qmlRegisterSingletonType<PlatformHelper>("Nymea", 1, 0, "PlatformHelper", PlatformHelper::platformHelperProvider);
|
||||
qmlRegisterSingletonType<PlatformPermissions>("Nymea", 1, 0, "PlatformPermissions", PlatformPermissions::qmlProvider);
|
||||
qmlRegisterSingletonType<NfcHelper>("Nymea", 1, 0, "NfcHelper", NfcHelper::nfcHelperProvider);
|
||||
qmlRegisterType<NfcThingActionWriter>("Nymea", 1, 0, "NfcThingActionWriter");
|
||||
|
||||
|
||||
@ -27,6 +27,7 @@ HEADERS += \
|
||||
nfchelper.h \
|
||||
nfcthingactionwriter.h \
|
||||
platformintegration/generic/screenhelper.h \
|
||||
platformintegration/platformpermissions.h \
|
||||
stylecontroller.h \
|
||||
pushnotifications.h \
|
||||
platformhelper.h \
|
||||
@ -39,6 +40,7 @@ SOURCES += main.cpp \
|
||||
mouseobserver.cpp \
|
||||
nfchelper.cpp \
|
||||
nfcthingactionwriter.cpp \
|
||||
platformintegration/platformpermissions.cpp \
|
||||
stylecontroller.cpp \
|
||||
pushnotifications.cpp \
|
||||
platformhelper.cpp \
|
||||
@ -73,11 +75,14 @@ android {
|
||||
include(../3rdParty/android/android_openssl/openssl.pri)
|
||||
|
||||
ANDROID_MIN_SDK_VERSION = 21
|
||||
ANDROID_TARGET_SDK_VERSION = 31
|
||||
ANDROID_TARGET_SDK_VERSION = 33
|
||||
|
||||
QT += androidextras
|
||||
HEADERS += platformintegration/android/platformhelperandroid.h
|
||||
SOURCES += platformintegration/android/platformhelperandroid.cpp
|
||||
HEADERS += platformintegration/android/platformhelperandroid.h \
|
||||
platformintegration/android/platformpermissionsandroid.h \
|
||||
|
||||
SOURCES += platformintegration/android/platformhelperandroid.cpp \
|
||||
platformintegration/android/platformpermissionsandroid.cpp \
|
||||
|
||||
# https://bugreports.qt.io/browse/QTBUG-83165
|
||||
LIBS += -L$${top_builddir}/libnymea-app/$${ANDROID_TARGET_ARCH}
|
||||
@ -131,13 +136,20 @@ macx: {
|
||||
|
||||
ios: {
|
||||
message("iOS build")
|
||||
HEADERS += platformintegration/ios/platformhelperios.h
|
||||
SOURCES += platformintegration/ios/platformhelperios.cpp
|
||||
HEADERS += platformintegration/ios/platformhelperios.h \
|
||||
platformintegration/ios/platformpermissionsios.h \
|
||||
|
||||
SOURCES += platformintegration/ios/platformhelperios.cpp \
|
||||
platformintegration/ios/platformpermissionsios.cpp \
|
||||
|
||||
OBJECTIVE_SOURCES += platformintegration/ios/platformhelperios.mm \
|
||||
platformintegration/ios/pushnotifications.mm \
|
||||
platformintegration/ios/platformpermissionsios.mm \
|
||||
|
||||
OTHER_FILES += $${OBJECTIVE_SOURCES}
|
||||
|
||||
LIBS += -framework CoreLocation \
|
||||
|
||||
# Add Firebase SDK
|
||||
QMAKE_LFLAGS += -ObjC $(inherited)
|
||||
firebase_files.files += $$files($${IOS_PACKAGE_DIR}/GoogleService-Info.plist)
|
||||
|
||||
@ -99,16 +99,6 @@ PlatformHelper *PlatformHelper::instance(bool create)
|
||||
return s_instance;
|
||||
}
|
||||
|
||||
bool PlatformHelper::hasPermissions() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void PlatformHelper::requestPermissions()
|
||||
{
|
||||
emit permissionsRequestFinished();
|
||||
}
|
||||
|
||||
void PlatformHelper::hideSplashScreen()
|
||||
{
|
||||
setSplashVisible(false);
|
||||
|
||||
@ -43,7 +43,6 @@ class QJSEngine;
|
||||
class PlatformHelper : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool hasPermissions READ hasPermissions NOTIFY permissionsRequestFinished)
|
||||
Q_PROPERTY(QString platform READ platform CONSTANT)
|
||||
Q_PROPERTY(QString deviceSerial READ deviceSerial CONSTANT)
|
||||
Q_PROPERTY(QString device READ device CONSTANT)
|
||||
@ -70,9 +69,6 @@ public:
|
||||
static PlatformHelper* instance(bool create = true);
|
||||
virtual ~PlatformHelper() = default;
|
||||
|
||||
virtual bool hasPermissions() const;
|
||||
Q_INVOKABLE virtual void requestPermissions();
|
||||
|
||||
virtual QString platform() const;
|
||||
virtual QString machineHostname() const;
|
||||
virtual QString device() const;
|
||||
@ -113,7 +109,6 @@ public:
|
||||
void notificationActionReceived(const QString &nymeaData);
|
||||
|
||||
signals:
|
||||
void permissionsRequestFinished();
|
||||
void screenTimeoutChanged();
|
||||
void screenBrightnessChanged();
|
||||
void topPanelColorChanged();
|
||||
|
||||
@ -50,7 +50,7 @@ public class NymeaAppNotificationService extends FirebaseMessagingService {
|
||||
intent.setAction(Intent.ACTION_SEND);
|
||||
intent.putExtra("notificationData", remoteMessage.getData().get("nymeaData"));
|
||||
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent, PendingIntent.FLAG_CANCEL_CURRENT);
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_MUTABLE);
|
||||
|
||||
// We can't directly access R.drawable.notificationicon from here:
|
||||
// When the package is branded, the package name is not "io.guh.nymeaapp" and resources in
|
||||
@ -83,7 +83,7 @@ public class NymeaAppNotificationService extends FirebaseMessagingService {
|
||||
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
NotificationChannel channel = new NotificationChannel("notify_001", "Channel human readable title", NotificationManager.IMPORTANCE_HIGH);
|
||||
NotificationChannel channel = new NotificationChannel("notify_001", "Notifications from your nymea system", NotificationManager.IMPORTANCE_HIGH);
|
||||
notificationManager.createNotificationChannel(channel);
|
||||
}
|
||||
|
||||
|
||||
@ -84,11 +84,6 @@ PlatformHelperAndroid::PlatformHelperAndroid(QObject *parent) : PlatformHelper(p
|
||||
}
|
||||
}
|
||||
|
||||
void PlatformHelperAndroid::requestPermissions()
|
||||
{
|
||||
// Not using any fancy permissions in android yet...
|
||||
}
|
||||
|
||||
void PlatformHelperAndroid::hideSplashScreen()
|
||||
{
|
||||
// Android's splash will flicker when fading out twice
|
||||
@ -99,12 +94,6 @@ void PlatformHelperAndroid::hideSplashScreen()
|
||||
}
|
||||
}
|
||||
|
||||
bool PlatformHelperAndroid::hasPermissions() const
|
||||
{
|
||||
// Not using any fancy permissions in android yet...
|
||||
return true;
|
||||
}
|
||||
|
||||
QString PlatformHelperAndroid::machineHostname() const
|
||||
{
|
||||
// QSysInfo::machineHostname always gives "localhost" on android... best we can do here is:
|
||||
@ -265,14 +254,6 @@ void PlatformHelperAndroid::shareFile(const QString &fileName)
|
||||
);
|
||||
}
|
||||
|
||||
void PlatformHelperAndroid::permissionRequestFinished(const QtAndroid::PermissionResultMap &result)
|
||||
{
|
||||
foreach (const QString &key, result.keys()) {
|
||||
qDebug() << "Permission result:" << key << static_cast<int>(result.value(key));
|
||||
}
|
||||
emit m_instance->permissionsRequestFinished();
|
||||
}
|
||||
|
||||
void PlatformHelperAndroid::darkModeEnabledChangedJNI()
|
||||
{
|
||||
if (m_instance) {
|
||||
|
||||
@ -45,11 +45,8 @@ public:
|
||||
|
||||
explicit PlatformHelperAndroid(QObject *parent = nullptr);
|
||||
|
||||
Q_INVOKABLE void requestPermissions() override;
|
||||
|
||||
Q_INVOKABLE void hideSplashScreen() override;
|
||||
|
||||
bool hasPermissions() const override;
|
||||
QString machineHostname() const override;
|
||||
QString deviceSerial() const override;
|
||||
QString device() const override;
|
||||
|
||||
@ -0,0 +1,64 @@
|
||||
#include "platformpermissionsandroid.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDebug>
|
||||
|
||||
PlatformPermissionsAndroid * PlatformPermissionsAndroid::s_instance = nullptr;
|
||||
|
||||
QHash<PlatformPermissions::Permission, QStringList> permissionMap = {
|
||||
// TODO: Once QtBluetooth does not request the COARSE_LOCATION for Bluetooth any more, remove it from here. The new Bluetooth permissions would be enough.
|
||||
{PlatformPermissions::PermissionBluetooth, {"android.permission.BLUETOOTH_SCAN", "android.permission.BLUETOOTH_CONNECT", "android.permission.ACCESS_COARSE_LOCATION"}},
|
||||
{PlatformPermissions::PermissionLocation, {"android.permission.ACCESS_FINE_LOCATION"}},
|
||||
{PlatformPermissions::PermissionBackgroundLocation, {"android.permission.ACCESS_FINE_LOCATION", "android.permission.ACCESS_BACKGROUND_LOCATION"}},
|
||||
{PlatformPermissions::PermissionNotifications, {"android.permission.POST_NOTIFICATIONS"}},
|
||||
};
|
||||
|
||||
PlatformPermissionsAndroid::PlatformPermissionsAndroid(QObject *parent)
|
||||
: PlatformPermissions{parent}
|
||||
{
|
||||
s_instance = this;
|
||||
// If the user switches to the settings app and changes permission settings there, we won't get notified
|
||||
// in any way, so let's just refresh when we become active
|
||||
connect(qApp, &QApplication::applicationStateChanged, this, [this](Qt::ApplicationState state){
|
||||
if (state == Qt::ApplicationActive) {
|
||||
emit bluetoothPermissionChanged();
|
||||
emit locationPermissionChanged();
|
||||
emit backgroundLocationPermissionChanged();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
void PlatformPermissionsAndroid::requestPermission(PlatformPermissions::Permission permission)
|
||||
{
|
||||
qWarning() << "****** android permission request" << permission;
|
||||
QtAndroid::requestPermissions({permissionMap.value(permission)}, &permissionResultCallback);
|
||||
}
|
||||
|
||||
void PlatformPermissionsAndroid::openPermissionSettings()
|
||||
{
|
||||
QtAndroid::androidActivity().callMethod<void>("openPermissionSettings", "()V");
|
||||
}
|
||||
|
||||
PlatformPermissions::PermissionStatus PlatformPermissionsAndroid::checkPermission(Permission permission) const
|
||||
{
|
||||
PermissionStatus status = PermissionStatusGranted;
|
||||
QStringList androidPermissions = permissionMap.value(permission);
|
||||
foreach (const QString androidPermission, androidPermissions) {
|
||||
if (QtAndroid::shouldShowRequestPermissionRationale(androidPermission)) {
|
||||
return PermissionStatusDenied;
|
||||
}
|
||||
if (QtAndroid::checkPermission(androidPermission) == QtAndroid::PermissionResult::Denied) {
|
||||
status = PermissionStatusNotDetermined;
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
void PlatformPermissionsAndroid::permissionResultCallback(const QtAndroid::PermissionResultMap &/*results*/)
|
||||
{
|
||||
emit s_instance->bluetoothPermissionChanged();
|
||||
emit s_instance->locationPermissionChanged();
|
||||
emit s_instance->backgroundLocationPermissionChanged();
|
||||
}
|
||||
|
||||
@ -0,0 +1,28 @@
|
||||
#ifndef PLATFORMPERMISSIONSANDROID_H
|
||||
#define PLATFORMPERMISSIONSANDROID_H
|
||||
|
||||
#include "../platformpermissions.h"
|
||||
|
||||
#include <QtAndroidExtras/QtAndroid>
|
||||
|
||||
class PlatformPermissionsAndroid : public PlatformPermissions
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit PlatformPermissionsAndroid(QObject *parent = nullptr);
|
||||
|
||||
PermissionStatus checkPermission(Permission permission) const override;
|
||||
|
||||
void requestPermission(Permission permission) override;
|
||||
void openPermissionSettings() override;
|
||||
|
||||
signals:
|
||||
|
||||
private:
|
||||
|
||||
static PlatformPermissionsAndroid *s_instance;
|
||||
static void permissionResultCallback(const QtAndroid::PermissionResultMap &results);
|
||||
|
||||
};
|
||||
|
||||
#endif // PLATFORMPERMISSIONSANDROID_H
|
||||
@ -44,13 +44,6 @@ PlatformHelperIOS::PlatformHelperIOS(QObject *parent) : PlatformHelper(parent)
|
||||
QObject::connect(screen, &QScreen::orientationChanged, qApp, [this](Qt::ScreenOrientation) {
|
||||
setBottomPanelColor(bottomPanelColor());
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
void PlatformHelperIOS::requestPermissions()
|
||||
{
|
||||
emit permissionsRequestFinished();
|
||||
}
|
||||
|
||||
void PlatformHelperIOS::hideSplashScreen()
|
||||
@ -58,11 +51,6 @@ void PlatformHelperIOS::hideSplashScreen()
|
||||
// Nothing to be done
|
||||
}
|
||||
|
||||
bool PlatformHelperIOS::hasPermissions() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
QString PlatformHelperIOS::machineHostname() const
|
||||
{
|
||||
return QSysInfo::machineHostName();
|
||||
|
||||
@ -41,11 +41,8 @@ class PlatformHelperIOS : public PlatformHelper
|
||||
public:
|
||||
explicit PlatformHelperIOS(QObject *parent = nullptr);
|
||||
|
||||
Q_INVOKABLE virtual void requestPermissions() override;
|
||||
|
||||
Q_INVOKABLE void hideSplashScreen() override;
|
||||
|
||||
virtual bool hasPermissions() const override;
|
||||
virtual QString machineHostname() const override;
|
||||
virtual QString device() const override;
|
||||
virtual QString deviceSerial() const override;
|
||||
|
||||
69
nymea-app/platformintegration/ios/platformpermissionsios.cpp
Normal file
69
nymea-app/platformintegration/ios/platformpermissionsios.cpp
Normal file
@ -0,0 +1,69 @@
|
||||
#include "platformpermissionsios.h"
|
||||
|
||||
#include <QSettings>
|
||||
|
||||
PlatformPermissionsIOS *PlatformPermissionsIOS::s_instance = nullptr;
|
||||
|
||||
PlatformPermissionsIOS::PlatformPermissionsIOS(QObject *parent)
|
||||
: PlatformPermissions{parent}
|
||||
{
|
||||
s_instance = this;
|
||||
initObjC();
|
||||
}
|
||||
|
||||
PlatformPermissionsIOS *PlatformPermissionsIOS::instance()
|
||||
{
|
||||
return s_instance;
|
||||
}
|
||||
|
||||
PlatformPermissions::PermissionStatus PlatformPermissionsIOS::checkPermission(Permission permission) const
|
||||
{
|
||||
switch (permission) {
|
||||
case PermissionLocalNetwork:
|
||||
return checkLocalNetworkPermission();
|
||||
case PermissionNotifications:
|
||||
return m_notificationPermissions;
|
||||
case PermissionBackgroundLocation:
|
||||
return checkBackgroundLocationPermission();
|
||||
case PermissionLocation:
|
||||
return checkLocationPermission();
|
||||
case PermissionBluetooth:
|
||||
return checkBluetoothPermission();
|
||||
default:
|
||||
return PermissionStatusGranted;
|
||||
}
|
||||
}
|
||||
|
||||
void PlatformPermissionsIOS::requestPermission(Permission permission)
|
||||
{
|
||||
switch (permission) {
|
||||
case PermissionLocalNetwork:
|
||||
requestLocalNetworkPermission();
|
||||
break;
|
||||
case PermissionNotifications:
|
||||
requestNotificationPermission();
|
||||
break;
|
||||
case PermissionBackgroundLocation:
|
||||
requestBackgroundLocationPermission();
|
||||
break;
|
||||
case PermissionLocation:
|
||||
requestLocationPermission();
|
||||
break;
|
||||
case PermissionBluetooth:
|
||||
requestBluetoothPermission();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
PlatformPermissions::PermissionStatus PlatformPermissionsIOS::checkLocalNetworkPermission() const
|
||||
{
|
||||
QSettings settings;
|
||||
return settings.value("askedForLocalNetworkPermission", false).toBool() ? PermissionStatusGranted : PermissionStatusNotDetermined;
|
||||
}
|
||||
|
||||
void PlatformPermissionsIOS::requestLocalNetworkPermission()
|
||||
{
|
||||
QSettings settings;
|
||||
settings.setValue("askedForLocalNetworkPermission", true);
|
||||
emit localNetworkPermissionChanged();
|
||||
}
|
||||
51
nymea-app/platformintegration/ios/platformpermissionsios.h
Normal file
51
nymea-app/platformintegration/ios/platformpermissionsios.h
Normal file
@ -0,0 +1,51 @@
|
||||
#ifndef PLATFORMPERMISSIONSIOS_H
|
||||
#define PLATFORMPERMISSIONSIOS_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "../platformpermissions.h"
|
||||
|
||||
#if __OBJC__
|
||||
@class CLLocationManager;
|
||||
@class CBCentralManager;
|
||||
#else
|
||||
typedef void CLLocationManager;
|
||||
typedef void CBCentralManager;
|
||||
#endif
|
||||
|
||||
class PlatformPermissionsIOS : public PlatformPermissions
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit PlatformPermissionsIOS(QObject *parent = nullptr);
|
||||
static PlatformPermissionsIOS *instance();
|
||||
|
||||
PermissionStatus checkPermission(Permission permission) const override;
|
||||
void requestPermission(Permission permission) override;
|
||||
void openPermissionSettings() override;
|
||||
|
||||
private:
|
||||
void initObjC();
|
||||
void refreshNotificationsPermission();
|
||||
|
||||
static PlatformPermissionsIOS *s_instance;
|
||||
|
||||
PermissionStatus checkLocalNetworkPermission() const;
|
||||
PermissionStatus checkBluetoothPermission() const;
|
||||
PermissionStatus checkLocationPermission() const;
|
||||
PermissionStatus checkBackgroundLocationPermission() const;
|
||||
|
||||
void requestLocalNetworkPermission();
|
||||
void requestNotificationPermission();
|
||||
void requestBluetoothPermission();
|
||||
void requestLocationPermission();
|
||||
void requestBackgroundLocationPermission();
|
||||
|
||||
PermissionStatus m_notificationPermissions = PermissionStatusNotDetermined;
|
||||
|
||||
|
||||
CLLocationManager *m_locationManager = nullptr;
|
||||
CBCentralManager *m_bluetoothManager = nullptr;
|
||||
};
|
||||
|
||||
#endif // PLATFORMPERMISSIONSIOS_H
|
||||
144
nymea-app/platformintegration/ios/platformpermissionsios.mm
Normal file
144
nymea-app/platformintegration/ios/platformpermissionsios.mm
Normal file
@ -0,0 +1,144 @@
|
||||
#include "platformpermissionsios.h"
|
||||
|
||||
#import <UserNotifications/UNUserNotificationCenter.h>
|
||||
#import <UserNotifications/UNNotificationSettings.h>
|
||||
#import <CoreLocation/CoreLocation.h>
|
||||
#import <CoreBluetooth/CoreBluetooth.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface LocationManagerPermissionDelegate : NSObject <CLLocationManagerDelegate>
|
||||
@end
|
||||
@implementation LocationManagerPermissionDelegate
|
||||
- (void)locationManagerDidChangeAuthorization:(CLLocationManager *)manager {
|
||||
emit PlatformPermissionsIOS::instance()->locationPermissionChanged();
|
||||
}
|
||||
@end
|
||||
|
||||
@interface BluetoothManagerDelegate: NSObject<CBCentralManagerDelegate>
|
||||
@end
|
||||
@implementation BluetoothManagerDelegate
|
||||
- (void)centralManagerDidUpdateState:(CBCentralManager *)manager {
|
||||
emit PlatformPermissionsIOS::instance()->bluetoothPermissionChanged();
|
||||
}
|
||||
@end
|
||||
|
||||
void PlatformPermissionsIOS::initObjC()
|
||||
{
|
||||
m_locationManager = [[CLLocationManager alloc] init];
|
||||
m_locationManager.delegate = [[LocationManagerPermissionDelegate alloc] init];
|
||||
|
||||
// Refresh notification permissions right away as that can be retrieved async only. We wanna be ready when the app requests it.
|
||||
refreshNotificationsPermission();
|
||||
}
|
||||
|
||||
void PlatformPermissionsIOS::refreshNotificationsPermission()
|
||||
{
|
||||
// Notification permissions can be retrieved async only.
|
||||
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
|
||||
[center getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings *settings) {
|
||||
PermissionStatus newPermission;
|
||||
switch (settings.authorizationStatus) {
|
||||
case UNAuthorizationStatusNotDetermined:
|
||||
newPermission = PermissionStatusNotDetermined;
|
||||
break;
|
||||
case UNAuthorizationStatusDenied:
|
||||
newPermission = PermissionStatusDenied;
|
||||
break;
|
||||
case UNAuthorizationStatusAuthorized:
|
||||
case UNAuthorizationStatusProvisional:
|
||||
case UNAuthorizationStatusEphemeral:
|
||||
newPermission = PermissionStatusGranted;
|
||||
break;
|
||||
}
|
||||
if (newPermission != m_notificationPermissions) {
|
||||
m_notificationPermissions = newPermission;
|
||||
emit notificationsPermissionChanged();
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
void PlatformPermissionsIOS::requestNotificationPermission()
|
||||
{
|
||||
UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter];
|
||||
[center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert + UNAuthorizationOptionBadge + UNAuthorizationOptionSound)
|
||||
completionHandler:^(BOOL granted, NSError * _Nullable error) {
|
||||
m_notificationPermissions = granted ? PermissionStatusGranted : PermissionStatusDenied;
|
||||
emit notificationsPermissionChanged();
|
||||
}];
|
||||
}
|
||||
|
||||
PlatformPermissions::PermissionStatus PlatformPermissionsIOS::checkBluetoothPermission() const
|
||||
{
|
||||
// iOS 13.0 would have an api but it's more complicated and also deprecated... Ignoring...
|
||||
if (@available(iOS 13.1, *)) {
|
||||
switch (CBCentralManager.authorization) {
|
||||
case CBManagerAuthorizationAllowedAlways:
|
||||
case CBManagerAuthorizationRestricted:
|
||||
return PermissionStatusGranted;
|
||||
case CBManagerAuthorizationDenied:
|
||||
return PermissionStatusDenied;
|
||||
case CBManagerAuthorizationNotDetermined:
|
||||
return PermissionStatusNotDetermined;
|
||||
}
|
||||
}
|
||||
// Before iOS 13, Bluetooth permissions are not required
|
||||
return PermissionStatusGranted;
|
||||
}
|
||||
|
||||
void PlatformPermissionsIOS::requestBluetoothPermission()
|
||||
{
|
||||
// Instantiating a Bluetooth manager just trigger the popup...
|
||||
if (!m_bluetoothManager) {
|
||||
BluetoothManagerDelegate *delegate = [[BluetoothManagerDelegate alloc] init];
|
||||
m_bluetoothManager = [[CBCentralManager alloc] initWithDelegate:delegate queue:nil];
|
||||
}
|
||||
}
|
||||
|
||||
PlatformPermissions::PermissionStatus PlatformPermissionsIOS::checkLocationPermission() const
|
||||
{
|
||||
switch ([CLLocationManager authorizationStatus]) {
|
||||
case kCLAuthorizationStatusNotDetermined:
|
||||
return PermissionStatusNotDetermined;
|
||||
case kCLAuthorizationStatusAuthorizedAlways:
|
||||
case kCLAuthorizationStatusAuthorizedWhenInUse:
|
||||
return PermissionStatusGranted;
|
||||
case kCLAuthorizationStatusDenied:
|
||||
case kCLAuthorizationStatusRestricted:
|
||||
return PermissionStatusDenied;
|
||||
}
|
||||
return PermissionStatusGranted;
|
||||
}
|
||||
|
||||
void PlatformPermissionsIOS::requestLocationPermission()
|
||||
{
|
||||
if ([m_locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
|
||||
[m_locationManager requestWhenInUseAuthorization];
|
||||
}
|
||||
}
|
||||
|
||||
PlatformPermissions::PermissionStatus PlatformPermissionsIOS::checkBackgroundLocationPermission() const
|
||||
{
|
||||
switch ([CLLocationManager authorizationStatus]) {
|
||||
case kCLAuthorizationStatusNotDetermined:
|
||||
return PermissionStatusNotDetermined;
|
||||
case kCLAuthorizationStatusAuthorizedAlways:
|
||||
return PermissionStatusGranted;
|
||||
case kCLAuthorizationStatusAuthorizedWhenInUse:
|
||||
case kCLAuthorizationStatusDenied:
|
||||
case kCLAuthorizationStatusRestricted:
|
||||
return PermissionStatusDenied;
|
||||
}
|
||||
return PermissionStatusGranted;
|
||||
}
|
||||
|
||||
void PlatformPermissionsIOS::requestBackgroundLocationPermission()
|
||||
{
|
||||
if ([m_locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
|
||||
[m_locationManager requestAlwaysAuthorization];
|
||||
}
|
||||
}
|
||||
|
||||
void PlatformPermissionsIOS::openPermissionSettings()
|
||||
{
|
||||
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
|
||||
}
|
||||
@ -8,9 +8,18 @@
|
||||
|
||||
#import "Firebase/Firebase.h"
|
||||
|
||||
@interface FirebaseDelegate: NSObject<FIRMessagingDelegate>
|
||||
@end
|
||||
|
||||
@implementation FirebaseDelegate
|
||||
- (void)messaging:(FIRMessaging *)messaging didReceiveRegistrationToken:(NSString *)fcmToken {
|
||||
qDebug() << "Firebase token received:" << QString::fromNSString(fcmToken);
|
||||
dynamic_cast<PushNotifications*>(PushNotifications::instance())->setFirebaseRegistrationToken(QString::fromNSString(fcmToken));
|
||||
}
|
||||
@end
|
||||
|
||||
// This is hidden, so we declare it here to hook into it
|
||||
@interface QIOSApplicationDelegate: UIResponder <UIApplicationDelegate,UNUserNotificationCenterDelegate,FIRMessagingDelegate>
|
||||
@interface QIOSApplicationDelegate: UIResponder <UIApplicationDelegate,UNUserNotificationCenterDelegate>
|
||||
@end
|
||||
|
||||
//add a category to QIOSApplicationDelegate
|
||||
@ -23,50 +32,12 @@
|
||||
|
||||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
|
||||
|
||||
// Use Firebase library to configure APIs
|
||||
[FIRApp configure];
|
||||
[FIRMessaging messaging].delegate = self;
|
||||
|
||||
|
||||
// Register to receive notifications from the system
|
||||
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
|
||||
center.delegate = self;
|
||||
[center requestAuthorizationWithOptions:(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge) completionHandler:^(BOOL granted, NSError * _Nullable error){
|
||||
if(!error){
|
||||
[[UIApplication sharedApplication] registerForRemoteNotifications];
|
||||
}
|
||||
}];
|
||||
|
||||
NSLog(@"registering for remote notifications");
|
||||
qDebug() << "Registering for remote notifications";
|
||||
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
|
||||
NSLog(@"Did Register for Remote Notifications with Device Token (%@)", deviceToken);
|
||||
|
||||
const unsigned *tokenBytes = (const unsigned*)[deviceToken bytes];
|
||||
NSString *tokenStr = [NSString stringWithFormat:@"%08x%08x%08x%08x%08x%08x%08x%08x",
|
||||
ntohl(tokenBytes[0]), ntohl(tokenBytes[1]), ntohl(tokenBytes[2]),
|
||||
ntohl(tokenBytes[3]), ntohl(tokenBytes[4]), ntohl(tokenBytes[5]),
|
||||
ntohl(tokenBytes[6]), ntohl(tokenBytes[7])];
|
||||
|
||||
// We've switched to firebase... Not emitting the native APNS token
|
||||
|
||||
// qDebug() << "Registering for remote notifications";
|
||||
// qDebug() << "Token description:" << QString::fromNSString(deviceToken.description);
|
||||
// qDebug() << "Parsed token:" << QString::fromNSString(tokenStr);
|
||||
PushNotifications::instance()->setAPNSRegistrationToken(QString::fromNSString(tokenStr));
|
||||
}
|
||||
|
||||
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
|
||||
NSLog(@"Did Fail to Register for Remote Notifications");
|
||||
NSLog(@"%@, %@", error, error.localizedDescription);
|
||||
qWarning() << "Failed to register for notifications:" << QString::fromNSString(error.localizedDescription);
|
||||
}
|
||||
|
||||
-(void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler{
|
||||
NSLog(@"User Info : %@",notification.request.content.userInfo);
|
||||
qDebug() << "willPresentNotification called!";
|
||||
@ -91,20 +62,15 @@
|
||||
|
||||
}
|
||||
|
||||
- (void)messaging:(FIRMessaging *)messaging didReceiveRegistrationToken:(NSString *)fcmToken {
|
||||
NSLog(@"FCM registration token: %@", fcmToken);
|
||||
// Notify about received token.
|
||||
NSDictionary *dataDict = [NSDictionary dictionaryWithObject:fcmToken forKey:@"token"];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:
|
||||
@"FCMToken" object:nil userInfo:dataDict];
|
||||
// Note: This callback is fired at each app startup and whenever a new token is generated.
|
||||
//qDebug() << "Firebase token received:" << QString::fromNSString(fcmToken);
|
||||
PushNotifications::instance()->setFirebaseRegistrationToken(QString::fromNSString(fcmToken));
|
||||
|
||||
}
|
||||
|
||||
- (void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo {
|
||||
qDebug() << "didReceiveRemoteNotification called";
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
void PushNotifications::registerObjC()
|
||||
{
|
||||
[FIRApp configure];
|
||||
[FIRMessaging messaging].delegate = [[FirebaseDelegate alloc] init];
|
||||
[[UIApplication sharedApplication] registerForRemoteNotifications];
|
||||
}
|
||||
|
||||
64
nymea-app/platformintegration/platformpermissions.cpp
Normal file
64
nymea-app/platformintegration/platformpermissions.cpp
Normal file
@ -0,0 +1,64 @@
|
||||
#include "platformpermissions.h"
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
#include "android/platformpermissionsandroid.h"
|
||||
#elif defined Q_OS_IOS
|
||||
#include "ios/platformpermissionsios.h"
|
||||
#endif
|
||||
|
||||
PlatformPermissions *PlatformPermissions::instance()
|
||||
{
|
||||
#ifdef Q_OS_ANDROID
|
||||
return new PlatformPermissionsAndroid();
|
||||
#elif defined Q_OS_IOS
|
||||
return new PlatformPermissionsIOS();
|
||||
#else
|
||||
return new PlatformPermissions();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
PlatformPermissions::PlatformPermissions(QObject *parent)
|
||||
: QObject{parent}
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QObject *PlatformPermissions::qmlProvider(QQmlEngine *engine, QJSEngine *scriptEngine)
|
||||
{
|
||||
Q_UNUSED(engine)
|
||||
Q_UNUSED(scriptEngine)
|
||||
return instance();
|
||||
}
|
||||
|
||||
PlatformPermissions::PermissionStatus PlatformPermissions::localNetworkPermission() const
|
||||
{
|
||||
return checkPermission(PermissionLocalNetwork);
|
||||
}
|
||||
|
||||
PlatformPermissions::PermissionStatus PlatformPermissions::bluetoothPermission() const
|
||||
{
|
||||
return checkPermission(PermissionBluetooth);
|
||||
}
|
||||
|
||||
PlatformPermissions::PermissionStatus PlatformPermissions::locationPermission() const
|
||||
{
|
||||
return checkPermission(PermissionLocation);
|
||||
}
|
||||
|
||||
PlatformPermissions::PermissionStatus PlatformPermissions::backgroundLocationPermission() const
|
||||
{
|
||||
return checkPermission(PermissionBackgroundLocation);
|
||||
}
|
||||
|
||||
PlatformPermissions::PermissionStatus PlatformPermissions::notificationsPermission() const
|
||||
{
|
||||
return checkPermission(PermissionNotifications);
|
||||
}
|
||||
|
||||
PlatformPermissions::PermissionStatus PlatformPermissions::checkPermission(Permission permission) const
|
||||
{
|
||||
Q_UNUSED(permission)
|
||||
return PermissionStatusGranted;
|
||||
}
|
||||
|
||||
65
nymea-app/platformintegration/platformpermissions.h
Normal file
65
nymea-app/platformintegration/platformpermissions.h
Normal file
@ -0,0 +1,65 @@
|
||||
#ifndef PLATFORMPERMISSIONS_H
|
||||
#define PLATFORMPERMISSIONS_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class QQmlEngine;
|
||||
class QJSEngine;
|
||||
|
||||
class PlatformPermissions : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(PermissionStatus localNetworkPermission READ localNetworkPermission NOTIFY localNetworkPermissionChanged)
|
||||
Q_PROPERTY(PermissionStatus bluetoothPermission READ bluetoothPermission NOTIFY bluetoothPermissionChanged)
|
||||
Q_PROPERTY(PermissionStatus locationPermission READ locationPermission NOTIFY locationPermissionChanged)
|
||||
Q_PROPERTY(PermissionStatus backgroundLocationPermission READ backgroundLocationPermission NOTIFY backgroundLocationPermissionChanged)
|
||||
Q_PROPERTY(PermissionStatus notificationsPermission READ notificationsPermission NOTIFY notificationsPermissionChanged)
|
||||
|
||||
public:
|
||||
enum Permission {
|
||||
PermissionNone = 0x00,
|
||||
PermissionLocalNetwork = 0x01,
|
||||
PermissionBluetooth = 0x02,
|
||||
PermissionLocation = 0x04,
|
||||
PermissionBackgroundLocation = 0x08,
|
||||
PermissionNotifications = 0x10
|
||||
};
|
||||
Q_ENUM(Permission)
|
||||
Q_DECLARE_FLAGS(Permissions, Permission)
|
||||
Q_FLAG(Permissions)
|
||||
|
||||
enum PermissionStatus {
|
||||
PermissionStatusNotDetermined,
|
||||
PermissionStatusGranted,
|
||||
PermissionStatusDenied,
|
||||
};
|
||||
Q_ENUM(PermissionStatus)
|
||||
|
||||
static PlatformPermissions* instance();
|
||||
static QObject *qmlProvider(QQmlEngine *engine, QJSEngine *scriptEngine);
|
||||
virtual ~PlatformPermissions() = default;
|
||||
|
||||
PermissionStatus localNetworkPermission() const;
|
||||
PermissionStatus bluetoothPermission() const;
|
||||
PermissionStatus locationPermission() const;
|
||||
PermissionStatus backgroundLocationPermission() const;
|
||||
PermissionStatus notificationsPermission() const;
|
||||
|
||||
Q_INVOKABLE virtual PermissionStatus checkPermission(Permission permission) const;
|
||||
Q_INVOKABLE virtual void requestPermission(Permission permission) { Q_UNUSED(permission) }
|
||||
Q_INVOKABLE virtual void openPermissionSettings() {}
|
||||
|
||||
signals:
|
||||
void localNetworkPermissionChanged();
|
||||
void bluetoothPermissionChanged();
|
||||
void locationPermissionChanged();
|
||||
void backgroundLocationPermissionChanged();
|
||||
void notificationsPermissionChanged();
|
||||
|
||||
protected:
|
||||
explicit PlatformPermissions(QObject *parent = nullptr);
|
||||
|
||||
};
|
||||
|
||||
#endif // PLATFORMPERMISSIONS_H
|
||||
@ -42,33 +42,7 @@ static PushNotifications *m_client_pointer;
|
||||
|
||||
PushNotifications::PushNotifications(QObject *parent) : QObject(parent)
|
||||
{
|
||||
#if defined Q_OS_ANDROID && defined WITH_FIREBASE
|
||||
qDebug() << "Checking for play services";
|
||||
jboolean playServicesAvailable = QAndroidJniObject::callStaticMethod<jboolean>("io.guh.nymeaapp.NymeaAppNotificationService", "checkPlayServices", "()Z");
|
||||
if (playServicesAvailable) {
|
||||
qDebug() << "Setting up firebase";
|
||||
m_client_pointer = this;
|
||||
m_firebaseApp = ::firebase::App::Create(::firebase::AppOptions(), QAndroidJniEnvironment(), QtAndroid::androidActivity().object());
|
||||
m_firebase_initializer.Initialize(m_firebaseApp, nullptr, [](::firebase::App * fapp, void *) {
|
||||
return ::firebase::messaging::Initialize( *fapp, (::firebase::messaging::Listener *)m_client_pointer);
|
||||
});
|
||||
} else {
|
||||
qDebug() << "Google Play Services not available. Cannot connect to push client.";
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef UBPORTS
|
||||
m_pushClient = new PushClient(this);
|
||||
m_pushClient->setAppId("io.guh.nymeaapp_nymea-app");
|
||||
connect(m_pushClient, &PushClient::tokenChanged, this, [this](const QString &token) {
|
||||
// On UBPorts, core and cloud use the same token
|
||||
m_coreToken = token;
|
||||
emit coreTokenChanged();
|
||||
m_cloudToken = m_coreToken;
|
||||
emit cloudTokenChanged();
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
PushNotifications::~PushNotifications()
|
||||
@ -91,6 +65,57 @@ PushNotifications *PushNotifications::instance()
|
||||
return pushNotifications;
|
||||
}
|
||||
|
||||
|
||||
bool PushNotifications::enabled() const
|
||||
{
|
||||
return m_enabled;
|
||||
}
|
||||
|
||||
void PushNotifications::setEnabled(bool enabled)
|
||||
{
|
||||
if (m_enabled == enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_enabled = enabled;
|
||||
|
||||
if (enabled) {
|
||||
registerForPush();
|
||||
}
|
||||
}
|
||||
|
||||
void PushNotifications::registerForPush()
|
||||
{
|
||||
#if defined Q_OS_ANDROID && defined WITH_FIREBASE
|
||||
qDebug() << "Checking for play services";
|
||||
jboolean playServicesAvailable = QAndroidJniObject::callStaticMethod<jboolean>("io.guh.nymeaapp.NymeaAppNotificationService", "checkPlayServices", "()Z");
|
||||
if (playServicesAvailable) {
|
||||
qDebug() << "Setting up firebase";
|
||||
m_client_pointer = this;
|
||||
m_firebaseApp = ::firebase::App::Create(::firebase::AppOptions(), QAndroidJniEnvironment(), QtAndroid::androidActivity().object());
|
||||
m_firebase_initializer.Initialize(m_firebaseApp, nullptr, [](::firebase::App * fapp, void *) {
|
||||
return ::firebase::messaging::Initialize( *fapp, (::firebase::messaging::Listener *)m_client_pointer);
|
||||
});
|
||||
} else {
|
||||
qDebug() << "Google Play Services not available. Cannot connect to push client.";
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef UBPORTS
|
||||
m_pushClient = new PushClient(this);
|
||||
m_pushClient->setAppId("io.guh.nymeaapp_nymea-app");
|
||||
connect(m_pushClient, &PushClient::tokenChanged, this, [this](const QString &token) {
|
||||
m_token = token;
|
||||
emit tokenChanged();
|
||||
});
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
registerObjC();
|
||||
#endif
|
||||
}
|
||||
|
||||
QString PushNotifications::service() const
|
||||
{
|
||||
#if defined Q_OS_ANDROID
|
||||
@ -108,28 +133,16 @@ QString PushNotifications::clientId() const
|
||||
return PlatformHelper::instance()->deviceSerial();
|
||||
}
|
||||
|
||||
QString PushNotifications::coreToken() const
|
||||
QString PushNotifications::token() const
|
||||
{
|
||||
return m_coreToken;
|
||||
}
|
||||
|
||||
QString PushNotifications::cloudToken() const
|
||||
{
|
||||
return m_cloudToken;
|
||||
}
|
||||
|
||||
void PushNotifications::setAPNSRegistrationToken(const QString &apnsRegistrationToken)
|
||||
{
|
||||
qDebug() << "Received APNS push notification token:" << apnsRegistrationToken;
|
||||
m_cloudToken = apnsRegistrationToken;
|
||||
emit cloudTokenChanged();
|
||||
return m_token;
|
||||
}
|
||||
|
||||
void PushNotifications::setFirebaseRegistrationToken(const QString &firebaseRegistrationToken)
|
||||
{
|
||||
qDebug() << "Received Firebase/APNS push notification token:" << firebaseRegistrationToken;
|
||||
m_coreToken = firebaseRegistrationToken;
|
||||
emit coreTokenChanged();
|
||||
m_token = firebaseRegistrationToken;
|
||||
emit tokenChanged();
|
||||
}
|
||||
|
||||
#if defined Q_OS_ANDROID && defined WITH_FIREBASE
|
||||
@ -140,11 +153,8 @@ void PushNotifications::OnMessage(const firebase::messaging::Message &message)
|
||||
|
||||
void PushNotifications::OnTokenReceived(const char *token)
|
||||
{
|
||||
qDebug() << "Firebase token received:" << token;
|
||||
// On Android, both, core and cloud use the same token
|
||||
m_coreToken = QString(token);
|
||||
emit coreTokenChanged();
|
||||
m_cloudToken = m_coreToken;
|
||||
emit cloudTokenChanged();
|
||||
m_token = QString(token);
|
||||
qDebug() << "Firebase token received:" << m_token;
|
||||
emit tokenChanged();
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -51,10 +51,10 @@ class PushNotifications : public QObject
|
||||
#endif
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged)
|
||||
Q_PROPERTY(QString service READ service CONSTANT)
|
||||
Q_PROPERTY(QString clientId READ clientId CONSTANT)
|
||||
Q_PROPERTY(QString cloudToken READ cloudToken NOTIFY cloudTokenChanged)
|
||||
Q_PROPERTY(QString coreToken READ coreToken NOTIFY coreTokenChanged)
|
||||
Q_PROPERTY(QString token READ token NOTIFY tokenChanged)
|
||||
|
||||
public:
|
||||
explicit PushNotifications(QObject *parent = nullptr);
|
||||
@ -63,18 +63,19 @@ public:
|
||||
static QObject* pushNotificationsProvider(QQmlEngine *engine, QJSEngine *scriptEngine);
|
||||
static PushNotifications* instance();
|
||||
|
||||
bool enabled() const;
|
||||
void setEnabled(bool enabled);
|
||||
|
||||
QString service() const;
|
||||
QString clientId() const;
|
||||
QString coreToken() const;
|
||||
QString cloudToken() const;
|
||||
QString token() const;
|
||||
|
||||
// Called by Objective-C++ on iOS
|
||||
void setAPNSRegistrationToken(const QString &apnsRegistrationToken);
|
||||
void setFirebaseRegistrationToken(const QString &firebaseRegistrationToken);
|
||||
|
||||
signals:
|
||||
void coreTokenChanged();
|
||||
void cloudTokenChanged();
|
||||
void enabledChanged();
|
||||
void tokenChanged();
|
||||
|
||||
protected:
|
||||
|
||||
@ -92,10 +93,16 @@ private:
|
||||
#endif
|
||||
|
||||
private:
|
||||
// For nymea:core plugin based push notifications
|
||||
QString m_coreToken;
|
||||
// for nymea:cloud based push notifications (deprecated)
|
||||
QString m_cloudToken;
|
||||
|
||||
void registerForPush();
|
||||
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
void registerObjC();
|
||||
#endif
|
||||
|
||||
bool m_enabled = false;
|
||||
QString m_token;
|
||||
};
|
||||
|
||||
#endif // PUSHNOTIFICATIONS_H
|
||||
|
||||
@ -106,6 +106,12 @@ ApplicationWindow {
|
||||
value: "cloudEnvironment" in app ? app.cloudEnvironment : settings.cloudEnvironment
|
||||
}
|
||||
|
||||
Binding {
|
||||
target: PushNotifications
|
||||
property: "enabled"
|
||||
value: PlatformPermissions.notificationsPermission === PlatformPermissions.PermissionStatusGranted
|
||||
}
|
||||
|
||||
ConfiguredHostsModel {
|
||||
id: configuredHostsModel
|
||||
}
|
||||
@ -136,7 +142,9 @@ ApplicationWindow {
|
||||
property NymeaDiscovery nymeaDiscovery: NymeaDiscovery {
|
||||
objectName: "discovery"
|
||||
awsClient: AWSClient
|
||||
bluetoothDiscoveryEnabled: PlatformPermissions.bluetoothPermission === PlatformPermissions.PermissionStatusGranted
|
||||
// discovering: pageStack.currentItem.objectName === "discoveryPage"
|
||||
Component.onCompleted: console.warn("****************** local net perm", PlatformPermissions.localNetworkPermission, discovering, PlatformPermissions.localNetworkPermission === PlatformPermissions.PermissionStatusGranted, PlatformPermissions.PermissionStatusGranted)
|
||||
}
|
||||
|
||||
property var supportedInterfaces: [
|
||||
|
||||
@ -126,6 +126,12 @@ Item {
|
||||
target: nymeaDiscovery
|
||||
property: "discovering"
|
||||
value: engine.jsonRpcClient.currentHost === null
|
||||
&& (PlatformPermissions.localNetworkPermission === PlatformPermissions.PermissionStatusGranted
|
||||
// This OR wouldn't be needed but we introduced the permission handling later and the localNetworkPerm can't be read on iOS.
|
||||
// If there are configured hosts, it means that we actally already have the permission even though PlatformPermissions thinks we wouldn't...
|
||||
// So skipping the check in that case for now (1.6)
|
||||
|| configuredHostsModel.count > 0)
|
||||
|
||||
}
|
||||
|
||||
readonly property alias pageStack: _pageStack
|
||||
@ -137,7 +143,6 @@ Item {
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
setupPushNotifications();
|
||||
if (configuredHost.uuid.toString() !== "{00000000-0000-0000-0000-000000000000}") {
|
||||
print("Configured host id is", configuredHost.uuid)
|
||||
var cachedHost = nymeaDiscovery.nymeaHosts.find(configuredHost.uuid);
|
||||
@ -149,6 +154,7 @@ Item {
|
||||
} else if (autoConnectHost.length > 0 && index === 0) {
|
||||
var host = nymeaDiscovery.nymeaHosts.createLanHost(Configuration.systemName, autoConnectHost);
|
||||
engine.jsonRpcClient.connectToHost(host)
|
||||
|
||||
return;
|
||||
} else {
|
||||
// Only hide the splash right away if we're not trying to connect to something
|
||||
@ -223,43 +229,13 @@ Item {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Old nymea:cloud based push notifications...
|
||||
function setupPushNotifications(askForPermissions) {
|
||||
if (askForPermissions === undefined) {
|
||||
askForPermissions = true;
|
||||
}
|
||||
|
||||
if (!AWSClient.isLoggedIn) {
|
||||
print("AWS not logged in. Cannot register for push");
|
||||
return;
|
||||
}
|
||||
|
||||
if (PushNotifications.cloudToken.length === 0) {
|
||||
print("Don't have a token yet. Cannot register for push");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!PlatformHelper.hasPermissions) {
|
||||
if (askForPermissions) {
|
||||
PlatformHelper.requestPermissions();
|
||||
}
|
||||
} else {
|
||||
AWSClient.registerPushNotificationEndpoint(
|
||||
PushNotifications.cloudToken,
|
||||
PlatformHelper.machineHostname,
|
||||
PushNotifications.clientId,
|
||||
PlatformHelper.deviceManufacturer,
|
||||
PlatformHelper.deviceModel);
|
||||
}
|
||||
}
|
||||
|
||||
// New, nymea thing based push notifactions
|
||||
function updatePushNotificationThings() {
|
||||
if (PushNotifications.service == "") {
|
||||
print("This platform does not support push notifications")
|
||||
return;
|
||||
}
|
||||
if (!PushNotifications.coreToken) {
|
||||
if (!PushNotifications.token) {
|
||||
print("No push notification token available at this time. Not updating...");
|
||||
return;
|
||||
}
|
||||
@ -268,7 +244,7 @@ Item {
|
||||
print("Updating push notifications")
|
||||
print("Own push service:", PushNotifications.service);
|
||||
print("Own client ID:", clientId);
|
||||
print("Current token:", PushNotifications.coreToken);
|
||||
print("Current token:", PushNotifications.token);
|
||||
|
||||
|
||||
for (var i = 0; i < engine.thingManager.things.count; i++) {
|
||||
@ -279,11 +255,15 @@ Item {
|
||||
var tokenParam = thing.paramByName("token")
|
||||
print("Found a push notification thing for client id:", clientIdParam.value)
|
||||
if (clientIdParam.value === clientId) {
|
||||
if (tokenParam.value !== PushNotifications.coreToken) {
|
||||
if (PlatformPermissions.notificationsPermission !== PlatformPermissions.PermissionStatusGranted) {
|
||||
PlatformPermissions.requestPermission(PlatformPermissions.PermissionNotifications)
|
||||
}
|
||||
|
||||
if (tokenParam.value !== PushNotifications.token) {
|
||||
var params = [
|
||||
{ "paramTypeId": serviceParam.paramTypeId, "value": PushNotifications.service },
|
||||
{ "paramTypeId": clientIdParam.paramTypeId, "value": clientId },
|
||||
{ "paramTypeId": tokenParam.paramTypeId, "value": PushNotifications.coreToken }
|
||||
{ "paramTypeId": tokenParam.paramTypeId, "value": PushNotifications.token }
|
||||
];
|
||||
print("Reconfiguring PushNotifications for", thing.name)
|
||||
engine.thingManager.reconfigureThing(thing.id, params);
|
||||
@ -401,27 +381,6 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: PlatformHelper
|
||||
onHasPermissionsChanged: {
|
||||
setupPushNotifications(false)
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: PushNotifications
|
||||
onCloudTokenChanged: {
|
||||
setupPushNotifications();
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: AWSClient
|
||||
onIsLoggedInChanged: {
|
||||
setupPushNotifications()
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: engine.thingManager
|
||||
onFetchingDataChanged: {
|
||||
|
||||
@ -12,7 +12,10 @@ WizardPageBase {
|
||||
showExtraButton: true
|
||||
extraButtonText: qsTr("Demo mode")
|
||||
|
||||
onNext: pageStack.push(connectionSelectionComponent)
|
||||
onNext: {
|
||||
PlatformPermissions.requestPermission(PlatformPermissions.PermissionLocalNetwork)
|
||||
pageStack.push(connectionSelectionComponent)
|
||||
}
|
||||
onExtraButtonPressed: {
|
||||
var host = nymeaDiscovery.nymeaHosts.createWanHost("Demo server", "nymea://nymea.nymea.io:2222")
|
||||
engine.jsonRpcClient.connectToHost(host)
|
||||
@ -120,7 +123,13 @@ WizardPageBase {
|
||||
BigTile {
|
||||
Layout.fillWidth: true
|
||||
|
||||
onClicked: pageStack.push(wirelessInstructionsComponent)
|
||||
onClicked: {
|
||||
if (PlatformPermissions.bluetoothPermission != PlatformPermissions.PermissionStatusGranted) {
|
||||
PlatformPermissions.requestPermission(PlatformPermissions.PermissionBluetooth)
|
||||
} else {
|
||||
}
|
||||
pageStack.push(wirelessInstructionsComponent)
|
||||
}
|
||||
|
||||
contentItem: RowLayout {
|
||||
spacing: Style.margins
|
||||
|
||||
@ -46,6 +46,18 @@ Page {
|
||||
}
|
||||
}
|
||||
|
||||
function startWizard(thingClass) {
|
||||
var page = pageStack.push(Qt.resolvedUrl("SetupWizard.qml"), {thingClass: thingClass});
|
||||
page.done.connect(function() {
|
||||
pageStack.pop(root, StackView.Immediate);
|
||||
pageStack.pop();
|
||||
})
|
||||
page.aborted.connect(function() {
|
||||
pageStack.pop();
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
Pane {
|
||||
id: filterPane
|
||||
anchors { left: parent.left; top: parent.top; right: parent.right }
|
||||
@ -167,14 +179,7 @@ Page {
|
||||
property ThingClass thingClass: thingClassesProxy.get(index)
|
||||
|
||||
onClicked: {
|
||||
var page = pageStack.push(Qt.resolvedUrl("SetupWizard.qml"), {thingClass: thingClassesProxy.get(index)});
|
||||
page.done.connect(function() {
|
||||
pageStack.pop(root, StackView.Immediate);
|
||||
pageStack.pop();
|
||||
})
|
||||
page.aborted.connect(function() {
|
||||
pageStack.pop();
|
||||
})
|
||||
root.startWizard(thingClass)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -375,6 +375,16 @@ Page {
|
||||
visible: paramRepeater.count > 0
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
if (root.thingClass.id.toString().match(/\{?f0dd4c03-0aca-42cc-8f34-9902457b05de\}?/)) {
|
||||
console.warn("checking Notification permission!")
|
||||
if (PlatformPermissions.notificationsPermission != PlatformPermissions.PermissionStatusGranted) {
|
||||
console.warn("Notification permission missing!")
|
||||
PlatformPermissions.requestPermission(PlatformPermissions.PermissionNotifications)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Repeater {
|
||||
id: paramRepeater
|
||||
model: engine.jsonRpcClient.ensureServerVersion("1.12") || d.thingDescriptor == null ? root.thingClass.paramTypes : null
|
||||
@ -396,7 +406,7 @@ Page {
|
||||
return PushNotifications.service;
|
||||
}
|
||||
if (paramType.id.toString().match(/\{?12ec06b2-44e7-486a-9169-31c684b91c8f\}?/)) {
|
||||
return PushNotifications.coreToken;
|
||||
return PushNotifications.token;
|
||||
}
|
||||
if (paramType.id.toString().match(/\{?d76da367-64e3-4b7d-aa84-c96b3acfb65e\}?/)) {
|
||||
return PushNotifications.clientId + "+" + Configuration.appId;
|
||||
|
||||
@ -1,8 +1,14 @@
|
||||
<?xml version="1.0"?>
|
||||
<manifest package="io.guh.nymeaapp" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="1.0" android:versionCode="1" android:installLocation="auto">
|
||||
|
||||
<uses-permission android:name="android.permission.VIBRATE"/>
|
||||
<uses-permission android:name="android.permission.NFC" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
|
||||
<application android:hardwareAccelerated="true" android:name="org.qtproject.qt5.android.bindings.QtApplication" android:label="nymea:app" android:icon="@mipmap/icon" android:roundIcon="@mipmap/round_icon" android:extractNativeLibs="true">
|
||||
<activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density" android:name="io.guh.nymeaapp.NymeaAppActivity" android:label="nymea:app" android:screenOrientation="unspecified" android:launchMode="singleTop" android:theme="@style/SplashScreenTheme">
|
||||
<activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density" android:name="io.guh.nymeaapp.NymeaAppActivity" android:label="nymea:app" android:screenOrientation="unspecified" android:launchMode="singleTop" android:theme="@style/SplashScreenTheme" android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
@ -63,7 +69,7 @@
|
||||
</activity>
|
||||
|
||||
|
||||
<activity android:process=":qt_controlsActivity" android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density" android:name="io.guh.nymeaapp.NymeaAppControlsActivity" android:label="nymea:app" android:screenOrientation="unspecified" android:launchMode="standard">
|
||||
<activity android:process=":qt_controlsActivity" android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density" android:name="io.guh.nymeaapp.NymeaAppControlsActivity" android:label="nymea:app" android:screenOrientation="unspecified" android:launchMode="standard" android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.nfc.action.NDEF_DISCOVERED"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
@ -99,7 +105,7 @@
|
||||
|
||||
<!-- For adding service(s) please check: https://wiki.qt.io/AndroidServices -->
|
||||
|
||||
<service android:process=":qt_service" android:name="io.guh.nymeaapp.NymeaAppService">
|
||||
<service android:process=":qt_service" android:name="io.guh.nymeaapp.NymeaAppService" android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.nfc.action.NDEF_DISCOVERED"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
@ -130,7 +136,7 @@
|
||||
<service android:name="com.google.firebase.messaging.MessageForwardingService" android:exported="false">
|
||||
</service>
|
||||
|
||||
<service android:name="io.guh.nymeaapp.NymeaAppNotificationService">
|
||||
<service android:name="io.guh.nymeaapp.NymeaAppNotificationService" android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="com.google.firebase.MESSAGING_EVENT"/>
|
||||
</intent-filter>
|
||||
@ -163,6 +169,4 @@
|
||||
<!-- The following comment will be replaced upon deployment with default features based on the dependencies of the application.
|
||||
Remove the comment if you do not require these default features. -->
|
||||
<!-- %%INSERT_FEATURES -->
|
||||
<uses-permission android:name="android.permission.VIBRATE"/>
|
||||
<uses-permission android:name="android.permission.NFC" />
|
||||
</manifest>
|
||||
|
||||
Reference in New Issue
Block a user