diff --git a/assets/android/AndroidManifest.xml b/assets/android/AndroidManifest.xml
index de2f2ba8..a37da990 100644
--- a/assets/android/AndroidManifest.xml
+++ b/assets/android/AndroidManifest.xml
@@ -7,17 +7,20 @@
+
+
-
-
+
+
-
+
+
@@ -30,9 +33,10 @@
android:theme="@style/AppTheme" android:icon="@mipmap/ic_launcher"
android:label="WatchFlower">
+
diff --git a/qml/DeviceList.qml b/qml/DeviceList.qml
index 6ff76f7f..e3e51ee3 100644
--- a/qml/DeviceList.qml
+++ b/qml/DeviceList.qml
@@ -48,16 +48,29 @@ Item {
function checkBluetoothStatus() {
if (deviceManager.hasDevices) {
- if (!deviceManager.bluetoothAdapter || !deviceManager.bluetoothEnabled) {
- rectangleBluetoothStatus.setBluetoothWarning()
- } else if (!deviceManager.bluetoothPermissions) {
- rectangleBluetoothStatus.setPermissionWarning()
+ // The device list is shown
+ loaderItemStatus.source = ""
+
+ if (!deviceManager.bluetoothPermissions) {
+ actionbarBluetoothStatus.setPermissionWarning()
+ } else if (!deviceManager.bluetoothAdapter) {
+ actionbarBluetoothStatus.setAdapterWarning()
+ } else if (!deviceManager.bluetoothEnabled) {
+ actionbarBluetoothStatus.setBluetoothWarning()
} else {
- rectangleBluetoothStatus.hide()
+ actionbarBluetoothStatus.hide()
}
} else {
// The sensor list is not populated
- rectangleBluetoothStatus.hide()
+ actionbarBluetoothStatus.hide()
+
+ if (!deviceManager.bluetoothPermissions) {
+ loaderItemStatus.source = "ItemNoPermissions.qml"
+ } else if (!deviceManager.bluetoothAdapter || !deviceManager.bluetoothEnabled) {
+ loaderItemStatus.source = "ItemNoBluetooth.qml"
+ } else {
+ loaderItemStatus.source = "ItemNoDevice.qml"
+ }
}
}
@@ -120,7 +133,7 @@ Item {
////////////////
ActionbarBluetooth {
- id: rectangleBluetoothStatus
+ id: actionbarBluetoothStatus
anchors.left: parent.left
anchors.right: parent.right
}
@@ -128,7 +141,7 @@ Item {
////////////////
ActionbarSelection {
- id: rectangleSelections
+ id: actionbarSelection
anchors.left: parent.left
anchors.right: parent.right
}
@@ -136,19 +149,23 @@ Item {
////////////////////////////////////////////////////////////////////////////
- ItemNoDevice {
+ Loader {
+ id: loaderDeviceList
anchors.fill: parent
- visible: !deviceManager.hasDevices
+ anchors.topMargin: rowbar.height
+
+ visible: deviceManager.hasDevices
+ asynchronous: false
}
- ////////////////////////////////////////////////////////////////////////////
+ ////////
Loader {
- id: loaderDeviceList
+ id: loaderItemStatus
anchors.fill: parent
- anchors.topMargin: rowbar.height
- asynchronous: false
+ visible: !deviceManager.hasDevices
+ asynchronous: true
}
////////////////////////////////////////////////////////////////////////////
diff --git a/qml/MobilePermissions.qml b/qml/MobilePermissions.qml
index 1f7c0c51..e7504f2c 100644
--- a/qml/MobilePermissions.qml
+++ b/qml/MobilePermissions.qml
@@ -56,18 +56,78 @@ Item {
////////
- Item {
- id: element_bluetooth
- height: 24
+ Item { // Bluetooth
anchors.left: parent.left
anchors.right: parent.right
+ height: 24
RoundButtonIcon {
+ anchors.left: parent.left
+ anchors.leftMargin: Theme.componentMargin
+ anchors.verticalCenter: parent.verticalCenter
width: 32
height: 32
+
+ property bool validperm: deviceManager.permissionOS
+
+ source: (validperm) ? "qrc:/assets/icons_material/baseline-check-24px.svg" : "qrc:/assets/icons_material/baseline-close-24px.svg"
+ iconColor: (validperm) ? "white" : "white"
+ backgroundColor: (validperm) ? Theme.colorSuccess : Theme.colorSubText
+ backgroundVisible: true
+
+ onClicked: {
+ utilsApp.vibrate(25)
+ utilsApp.getMobileBluetoothPermission()
+ refreshPermissions.start()
+ }
+ }
+
+ Text {
+ anchors.left: parent.left
+ anchors.leftMargin: appHeader.headerPosition
+ anchors.right: parent.right
+ anchors.rightMargin: Theme.componentMargin
+ anchors.verticalCenter: parent.verticalCenter
+ height: 16
+
+ text: qsTr("Bluetooth")
+ textFormat: Text.PlainText
+ wrapMode: Text.WordWrap
+ font.pixelSize: 17
+ color: Theme.colorText
+ verticalAlignment: Text.AlignVCenter
+ }
+ }
+ Text { // Bluetooth legend
+ anchors.left: parent.left
+ anchors.leftMargin: appHeader.headerPosition
+ anchors.right: parent.right
+ anchors.rightMargin: Theme.componentMargin
+
+ text: qsTr("The Android operating system requires permission to scan for nearby Bluetooth Low Energy sensors.")
+ textFormat: Text.StyledText
+ wrapMode: Text.WordWrap
+ color: Theme.colorSubText
+ font.pixelSize: Theme.fontSizeContentSmall
+ }
+
+ ////////
+
+ ListSeparatorPadded { height: 16+1 }
+
+ ////////
+
+ Item { // Bluetooth control
+ anchors.left: parent.left
+ anchors.right: parent.right
+ height: 24
+
+ RoundButtonIcon {
anchors.left: parent.left
anchors.leftMargin: Theme.componentMargin
anchors.verticalCenter: parent.verticalCenter
+ width: 32
+ height: 32
property bool validperm: true
@@ -78,12 +138,12 @@ Item {
}
Text {
- height: 16
anchors.left: parent.left
anchors.leftMargin: appHeader.headerPosition
anchors.right: parent.right
anchors.rightMargin: Theme.componentMargin
anchors.verticalCenter: parent.verticalCenter
+ height: 16
text: qsTr("Bluetooth control")
textFormat: Text.PlainText
@@ -113,16 +173,16 @@ Item {
////////
Item { // Location
- height: 24
anchors.left: parent.left
anchors.right: parent.right
+ height: 24
RoundButtonIcon {
- width: 32
- height: 32
anchors.left: parent.left
anchors.leftMargin: Theme.componentMargin
anchors.verticalCenter: parent.verticalCenter
+ width: 32
+ height: 32
property bool validperm: deviceManager.permissionLocationBLE
@@ -139,12 +199,12 @@ Item {
}
Text {
- height: 16
anchors.left: parent.left
anchors.leftMargin: appHeader.headerPosition
anchors.right: parent.right
anchors.rightMargin: Theme.componentMargin
anchors.verticalCenter: parent.verticalCenter
+ height: 16
text: qsTr("Location")
textFormat: Text.PlainText
@@ -168,9 +228,9 @@ Item {
font.pixelSize: Theme.fontSizeContentSmall
}
ButtonWireframeIcon {
- height: 36
anchors.left: parent.left
anchors.leftMargin: appHeader.headerPosition
+ height: 36
primaryColor: Theme.colorPrimary
secondaryColor: Theme.colorBackground
@@ -199,11 +259,11 @@ Item {
anchors.right: parent.right
RoundButtonIcon {
- width: 32
- height: 32
anchors.left: parent.left
anchors.leftMargin: Theme.componentMargin
anchors.verticalCenter: parent.verticalCenter
+ width: 32
+ height: 32
property bool validperm: deviceManager.permissionLocationBackground
@@ -220,12 +280,12 @@ Item {
}
Text {
- height: 16
anchors.left: parent.left
anchors.leftMargin: appHeader.headerPosition
anchors.right: parent.right
anchors.rightMargin: Theme.componentMargin
anchors.verticalCenter: parent.verticalCenter
+ height: 16
text: qsTr("Background location")
textFormat: Text.PlainText
@@ -254,17 +314,17 @@ Item {
////////
- Item { // GPS
- height: 24
+ Item { // GPS
anchors.left: parent.left
anchors.right: parent.right
+ height: 24
RoundButtonIcon {
- width: 32
- height: 32
anchors.left: parent.left
anchors.leftMargin: Theme.componentMargin
anchors.verticalCenter: parent.verticalCenter
+ width: 32
+ height: 32
property bool validperm: deviceManager.permissionLocationGPS
@@ -280,12 +340,12 @@ Item {
}
Text {
- height: 16
anchors.left: parent.left
anchors.leftMargin: appHeader.headerPosition
anchors.right: parent.right
anchors.rightMargin: Theme.componentMargin
anchors.verticalCenter: parent.verticalCenter
+ height: 16
text: qsTr("GPS")
textFormat: Text.PlainText
@@ -309,9 +369,9 @@ Item {
}
ButtonWireframeIcon {
- height: 36
anchors.left: parent.left
anchors.leftMargin: appHeader.headerPosition
+ height: 36
primaryColor: Theme.colorPrimary
secondaryColor: Theme.colorBackground
@@ -331,16 +391,16 @@ Item {
Item {
id: element_infos
- height: 24
anchors.left: parent.left
anchors.right: parent.right
+ height: 32
IconSvg {
- width: 32
- height: 32
anchors.left: parent.left
anchors.leftMargin: Theme.componentMargin
anchors.verticalCenter: parent.verticalCenter
+ width: 32
+ height: 32
opacity: 0.66
color: Theme.colorSubText
@@ -352,9 +412,11 @@ Item {
anchors.leftMargin: appHeader.headerPosition
anchors.right: parent.right
anchors.rightMargin: Theme.componentMargin
+ anchors.verticalCenter: parent.verticalCenter
text: qsTr("Click on the checkmarks to request missing permissions.")
textFormat: Text.StyledText
+ lineHeight : 0.8
wrapMode: Text.WordWrap
color: Theme.colorText
font.pixelSize: Theme.fontSizeContent
@@ -376,9 +438,9 @@ Item {
}
ButtonWireframeIcon {
- height: 36
anchors.left: parent.left
anchors.leftMargin: appHeader.headerPosition
+ height: 36
primaryColor: Theme.colorPrimary
secondaryColor: Theme.colorBackground
diff --git a/qml/components/ActionbarBluetooth.qml b/qml/components/ActionbarBluetooth.qml
index d426fc31..6b894422 100644
--- a/qml/components/ActionbarBluetooth.qml
+++ b/qml/components/ActionbarBluetooth.qml
@@ -18,14 +18,19 @@ Rectangle {
function hide() {
actionbarBluetoothStatus.height = 0
}
- function setBluetoothWarning() {
- textBluetoothStatus.text = qsTr("Bluetooth is disabled...")
- actionbarBluetoothStatus.height = 52
- }
+
function setPermissionWarning() {
textBluetoothStatus.text = qsTr("Bluetooth permission is missing...")
actionbarBluetoothStatus.height = 52
}
+ function setAdapterWarning() {
+ textBluetoothStatus.text = qsTr("Bluetooth adapter not found...")
+ actionbarBluetoothStatus.height = 52
+ }
+ function setBluetoothWarning() {
+ textBluetoothStatus.text = qsTr("Bluetooth is disabled...")
+ actionbarBluetoothStatus.height = 52
+ }
////////////////
@@ -58,19 +63,20 @@ Rectangle {
primaryColor: Theme.colorActionbarHighlight
text: {
+ if (!deviceManager.bluetoothPermissions) return qsTr("Request")
if (Qt.platform.os === "android") {
if (!deviceManager.bluetoothEnabled) return qsTr("Enable")
- else if (!deviceManager.bluetoothPermissions) return qsTr("About")
}
return qsTr("Retry")
}
onClicked: {
- if (Qt.platform.os === "android" && !deviceManager.bluetoothPermissions) {
- // someone clicked 'never ask again' on the Bluetooth permission?
- screenAboutPermissions.loadScreenFrom("DeviceList")
- } else {
+ if (!deviceManager.bluetoothPermissions) {
+ deviceManager.requestBluetoothPermissions()
+ }
+ if (!deviceManager.bluetoothEnabled) {
deviceManager.enableBluetooth(settingsManager.bluetoothControl)
}
+ deviceManager.checkBluetooth()
}
}
diff --git a/qml/components/ItemNoBluetooth.qml b/qml/components/ItemNoBluetooth.qml
new file mode 100644
index 00000000..ad9192ce
--- /dev/null
+++ b/qml/components/ItemNoBluetooth.qml
@@ -0,0 +1,119 @@
+import QtQuick
+import QtQuick.Layouts
+
+import ThemeEngine
+
+Item {
+ id: itemNoBluetooth
+ anchors.fill: parent
+
+ Column {
+ anchors.left: parent.left
+ anchors.leftMargin: Theme.componentMarginXL
+ anchors.right: parent.right
+ anchors.rightMargin: Theme.componentMarginXL
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.verticalCenterOffset: -Theme.componentMarginXL
+ spacing: Theme.componentMargin
+
+ ////
+
+ Column {
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ Rectangle {
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ width: singleColumn ? (itemNoBluetooth.width*0.5) : (itemNoBluetooth.height*0.4)
+ height: width
+ radius: width
+ color: Theme.colorForeground
+
+ IconSvg { // bluetooth disabled icon
+ anchors.centerIn: parent
+ width: parent.width*0.8
+ height: width
+
+ source: "qrc:/assets/icons_material/baseline-bluetooth_disabled-24px.svg"
+ fillMode: Image.PreserveAspectFit
+ color: Theme.colorSubText
+ opacity: 0.9
+ smooth: true
+ }
+ }
+
+ Item { width: Theme.componentMarginXL; height: Theme.componentMarginXL; }
+
+ Text {
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ text: {
+ if (deviceManager.bluetoothAdapter && !deviceManager.bluetoothEnabled) {
+ return qsTr("Bluetooth is disabled...")
+ }
+ return qsTr("Bluetooth adapter not found...")
+ }
+ textFormat: Text.PlainText
+ font.pixelSize: Theme.fontSizeContentBig
+ color: Theme.colorText
+ }
+
+ Item { width: 8; height: 8; }
+
+ ButtonWireframe {
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ fullColor: true
+ text: {
+ if (deviceManager.bluetoothAdapter &&!deviceManager.bluetoothEnabled) {
+ if (Qt.platform.os === "android") return qsTr("Enable")
+ }
+ return qsTr("Retry")
+ }
+ onClicked: {
+ if (deviceManager.bluetoothAdapter &&!deviceManager.bluetoothEnabled) {
+ if (Qt.platform.os === "android") {
+ deviceManager.enableBluetooth()
+ return
+ }
+ }
+ deviceManager.checkBluetooth()
+ }
+ }
+
+ Item { width: 8; height: 8; }
+ }
+
+ ////
+
+ RowLayout {
+ anchors.horizontalCenter: parent.horizontalCenter
+ width: singleColumn ? (itemNoBluetooth.width*0.85) : undefined
+ spacing: Theme.componentMargin
+
+ visible: !deviceManager.bluetoothEnabled
+
+ IconSvg {
+ Layout.preferredWidth: 20
+ Layout.preferredHeight: 20
+ Layout.alignment: Qt.AlignVCenter
+
+ source: "qrc:/assets/icons_material/baseline-warning-24px.svg"
+ color: Theme.colorWarning
+ }
+ Text {
+ Layout.fillWidth: singleColumn
+ Layout.alignment: Qt.AlignVCenter
+
+ text: qsTr("Please enable Bluetooth on your device in order to use the application.")
+ textFormat: Text.StyledText
+ font.pixelSize: Theme.fontSizeContentSmall
+ color: Theme.colorSubText
+ wrapMode: Text.WordWrap
+ horizontalAlignment: singleColumn ? Text.AlignJustify : Text.AlignHCenter
+ }
+ }
+
+ ////
+ }
+}
diff --git a/qml/components/ItemNoDevice.qml b/qml/components/ItemNoDevice.qml
index 7eca0a9e..e9c66a4b 100644
--- a/qml/components/ItemNoDevice.qml
+++ b/qml/components/ItemNoDevice.qml
@@ -7,28 +7,6 @@ Item {
id: itemNoDevice
anchors.fill: parent
- ////////////////////////////////////////////////////////////////////////////
-
- Timer {
- id: retryScan
- interval: 333
- running: false
- repeat: false
- onTriggered: scan()
- }
-
- function scan() {
- if (!deviceManager.updating) {
- if (deviceManager.scanning) {
- deviceManager.scanDevices_stop()
- } else {
- deviceManager.scanDevices_start()
- }
- }
- }
-
- ////////////////////////////////////////////////////////////////////////////
-
Column {
anchors.left: parent.left
anchors.right: parent.right
@@ -58,146 +36,71 @@ Item {
Column {
anchors.left: parent.left
anchors.right: parent.right
- spacing: Theme.componentMarginXL
-
- ////////
+ spacing: Theme.componentMarginXL + 8
- ColumnLayout {
- anchors.left: parent.left
- anchors.leftMargin: Theme.componentMargin*2.5 + 20
- anchors.right: parent.right
- anchors.rightMargin: Theme.componentMargin*2.5
- spacing: Theme.componentMargin/2
+ ////
- ////
+ ButtonWireframe {
+ anchors.horizontalCenter: parent.horizontalCenter
- Text {
- Layout.maximumWidth: parent.width
- Layout.alignment: Qt.AlignHCenter
+ width: (isDesktop || isTablet || (isPhone && screenOrientation === Qt.LandscapeOrientation)) ? 320 : (parent.width*0.5)
- visible: !deviceManager.bluetoothEnabled
+ text: deviceManager.scanning ? qsTr("Scanning...") : qsTr("Launch detection")
+ fullColor: true
+ primaryColor: Theme.colorPrimary
- IconSvg {
- anchors.right: parent.left
- anchors.rightMargin: Theme.componentMargin
- anchors.verticalCenter: parent.verticalCenter
- width: 20; height: 20;
- source: "qrc:/assets/icons_material/baseline-warning-24px.svg"
- color: Theme.colorWarning
+ onClicked: {
+ // Just to be sure...
+ if (!deviceManager.bluetoothPermissions) {
+ // Ask permission
+ utilsApp.getMobileBleLocationPermission()
}
-
- text: qsTr("Please enable Bluetooth on your device in order to use the application.")
- textFormat: Text.StyledText
- font.pixelSize: Theme.fontSizeContentSmall
- color: Theme.colorSubText
- wrapMode: Text.WordWrap
- horizontalAlignment: singleColumn ? Text.AlignJustify : Text.AlignHCenter
- }
-
- ////
-
- Text {
- Layout.maximumWidth: parent.width
- Layout.alignment: Qt.AlignHCenter
-
- visible: (Qt.platform.os === "osx" || Qt.platform.os === "ios")
-
- IconSvg {
- anchors.right: parent.left
- anchors.rightMargin: Theme.componentMargin
- anchors.verticalCenter: parent.verticalCenter
- width: 20; height: 20;
- source: "qrc:/assets/icons_material/baseline-warning-24px.svg"
- color: Theme.colorWarning
+ if (!deviceManager.bluetoothAdapter || !deviceManager.bluetoothEnabled) {
+ // Enable
+ deviceManager.enableBluetooth(true)
}
- text: qsTr("Authorization to use Bluetooth is required to connect to the sensors.")
- textFormat: Text.StyledText
- font.pixelSize: Theme.fontSizeContentSmall
- color: Theme.colorSubText
- wrapMode: Text.WordWrap
- horizontalAlignment: singleColumn ? Text.AlignJustify : Text.AlignHCenter
+ // Now we scan...
+ tryScan.start()
}
- ////
-
- Text {
- Layout.maximumWidth: parent.width
- Layout.alignment: Qt.AlignHCenter
-
- visible: (Qt.platform.os === "android")
-
- IconSvg {
- anchors.right: parent.left
- anchors.rightMargin: Theme.componentMargin
- anchors.verticalCenter: parent.verticalCenter
- width: 20; height: 20;
- source: "qrc:/assets/icons_material/baseline-warning-24px.svg"
- color: Theme.colorWarning
+ Timer {
+ id: tryScan
+ interval: 333
+ running: false
+ repeat: false
+ onTriggered: {
+ if (!deviceManager.updating) {
+ if (deviceManager.scanning) {
+ deviceManager.scanDevices_stop()
+ } else {
+ deviceManager.scanDevices_start()
+ }
+ }
}
-
- text: qsTr("On Android 6+, scanning for Bluetooth Low Energy devices requires location permission.")
- textFormat: Text.StyledText
- font.pixelSize: Theme.fontSizeContentSmall
- color: Theme.colorSubText
- wrapMode: Text.WordWrap
- horizontalAlignment: singleColumn ? Text.AlignJustify : Text.AlignHCenter
- }
- Text {
- Layout.maximumWidth: parent.width
- Layout.alignment: Qt.AlignHCenter
-
- visible: (Qt.platform.os === "android")
-
- text: qsTr("The application is neither using nor storing your location. Sorry for the inconvenience.")
- textFormat: Text.PlainText
- font.pixelSize: Theme.fontSizeContentSmall
- color: Theme.colorSubText
- wrapMode: Text.WordWrap
- horizontalAlignment: singleColumn ? Text.AlignJustify : Text.AlignHCenter
}
+ }
- ////
+ ////
- Text {
- Layout.maximumWidth: parent.width
- Layout.alignment: Qt.AlignHCenter
+ RowLayout {
+ anchors.horizontalCenter: parent.horizontalCenter
+ width: singleColumn ? (itemNoDevice.width*0.85) : undefined
+ spacing: Theme.componentMargin
- visible: (Qt.platform.os === "android" && !deviceManager.permissionLocationGPS)
+ //visible: !deviceManager.bluetoothEnabled
- IconSvg {
- anchors.right: parent.left
- anchors.rightMargin: Theme.componentMargin
- anchors.verticalCenter: parent.verticalCenter
- width: 20; height: 20;
- source: "qrc:/assets/icons_material/baseline-warning-24px.svg"
- color: Theme.colorSubText
- }
+ IconSvg {
+ Layout.preferredWidth: 20
+ Layout.preferredHeight: 20
+ Layout.alignment: Qt.AlignVCenter
- text: qsTr("Some Android devices also require the actual GPS to be turned on.")
- textFormat: Text.StyledText
- font.pixelSize: Theme.fontSizeContentSmall
+ source: "qrc:/assets/icons_material/baseline-info-24px.svg"
color: Theme.colorSubText
- wrapMode: Text.WordWrap
- horizontalAlignment: singleColumn ? Text.AlignJustify : Text.AlignHCenter
}
-
- ////
-
Text {
- Layout.maximumWidth: parent.width
- Layout.alignment: Qt.AlignHCenter
-
- visible: settingsManager.bluetoothLimitScanningRange
-
- IconSvg {
- anchors.right: parent.left
- anchors.rightMargin: Theme.componentMargin
- anchors.verticalCenter: parent.verticalCenter
- width: 20; height: 20;
- source: "qrc:/assets/icons_material/baseline-info-24px.svg"
- color: Theme.colorSubText
- }
+ Layout.fillWidth: singleColumn
+ Layout.alignment: Qt.AlignVCenter
text: qsTr("Please keep your device close to the sensors you want to scan.")
textFormat: Text.StyledText
@@ -206,103 +109,9 @@ Item {
wrapMode: Text.WordWrap
horizontalAlignment: singleColumn ? Text.AlignJustify : Text.AlignHCenter
}
-
- ////
- }
-
- ////////
-
- Grid {
- anchors.horizontalCenter: parent.horizontalCenter
-
- visible: isMobile
- spacing: Theme.componentMarginXL
-
- rows: 2
- columns: singleColumn ? 1 : 2
-
- Item {
- width: singleColumn ? contentColumn.width : btn1.width
- height: Theme.componentHeight
-
- ButtonWireframeIcon {
- id: btn1
- anchors.horizontalCenter: parent.horizontalCenter
-
- //width: (isDesktop || isTablet || (isPhone && appWindow.screenOrientation === Qt.LandscapeOrientation)) ? undefined : (parent.width*0.75)
-
- text: qsTr("Official information")
- primaryColor: Theme.colorSubText
- sourceSize: 20
- source: "qrc:/assets/icons_material/duotone-launch-24px.svg"
-
- onClicked: {
- if (Qt.platform.os === "android") {
- if (utilsApp.getAndroidSdkVersion() >= 12)
- Qt.openUrlExternally("https://developer.android.com/guide/topics/connectivity/bluetooth/permissions#declare-android12-or-higher")
- else
- Qt.openUrlExternally("https://developer.android.com/guide/topics/connectivity/bluetooth/permissions#declare-android11-or-lower")
- } else if (Qt.platform.os === "ios") {
- Qt.openUrlExternally("https://support.apple.com/HT210578")
- }
- }
- }
- }
-
- Item {
- width: singleColumn ? contentColumn.width : btn2.width
- height: Theme.componentHeight
-
- ButtonWireframe {
- id: btn2
- anchors.horizontalCenter: parent.horizontalCenter
-
- //width: (isDesktop || isTablet || (isPhone && appWindow.screenOrientation === Qt.LandscapeOrientation)) ? undefined : (parent.width*0.75)
-
- text: deviceManager.scanning ? qsTr("Scanning...") : qsTr("Launch detection")
- fullColor: true
- primaryColor: Theme.colorPrimary
-
- onClicked: {
- if (!deviceManager.bluetoothAdapter || !deviceManager.bluetoothEnabled) {
- // Just to be sure...
- deviceManager.enableBluetooth(true)
- }
-
- if (!deviceManager.bluetoothPermissions) {
- // Ask permission
- utilsApp.getMobileBleLocationPermission()
- }
-
- // Now we scan...
- retryScan.start()
- }
- }
- }
- }
-
- ////////
-
- ButtonWireframe { // desktop only launch button
- anchors.horizontalCenter: parent.horizontalCenter
- width: 320
-
- visible: isDesktop
- fullColor: true
- primaryColor: Theme.colorPrimary
-
- text: deviceManager.scanning ? qsTr("Scanning...") : qsTr("Launch detection")
-
- onClicked: {
- // Just to be sure...
- deviceManager.enableBluetooth()
-
- // Now we scan...
- retryScan.start()
- }
}
- ////////
+ ////
}
}
diff --git a/qml/components/ItemNoPermissions.qml b/qml/components/ItemNoPermissions.qml
new file mode 100644
index 00000000..1bf2f950
--- /dev/null
+++ b/qml/components/ItemNoPermissions.qml
@@ -0,0 +1,230 @@
+import QtQuick
+import QtQuick.Layouts
+
+import ThemeEngine
+
+Item {
+ id: itemNoPermissions
+ anchors.fill: parent
+
+ Column {
+ anchors.left: parent.left
+ anchors.leftMargin: Theme.componentMarginXL
+ anchors.right: parent.right
+ anchors.rightMargin: Theme.componentMarginXL
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.verticalCenterOffset: -Theme.componentMarginXL
+ spacing: Theme.componentMargin
+
+ ////
+
+ Column {
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ Rectangle {
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ width: singleColumn ? (itemNoPermissions.width*0.5) : (itemNoPermissions.height*0.4)
+ height: width
+ radius: width
+ color: Theme.colorForeground
+
+ IconSvg { // lock icon
+ anchors.centerIn: parent
+ width: parent.width*0.8
+ height: width
+
+ source: "qrc:/assets/icons_material/outline-lock-24px.svg"
+ fillMode: Image.PreserveAspectFit
+ color: Theme.colorSubText
+ opacity: 0.9
+ smooth: true
+ }
+ }
+
+ Item { width: Theme.componentMarginXL; height: Theme.componentMarginXL; }
+
+ Text {
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ text: qsTr("Bluetooth permission(s) missing…")
+ textFormat: Text.PlainText
+ font.pixelSize: Theme.fontSizeContentBig
+ color: Theme.colorText
+ }
+
+ Item { width: 8; height: 8; }
+
+ Row {
+ anchors.horizontalCenter: parent.horizontalCenter
+ spacing: Theme.componentMargin
+
+ ButtonWireframeIcon {
+ //width: ((isDesktop || isTablet) && !singleColumn) ? 256 : undefined
+
+ text: qsTr("Request permission(s)")
+ primaryColor: Theme.colorPrimary
+ fullColor: true
+ sourceSize: 24
+ source: "qrc:/assets/icons_material/duotone-touch_app-24px.svg"
+
+ onClicked: {
+ deviceManager.requestBluetoothPermissions()
+ }
+ }
+ }
+
+ Item { width: 8; height: 8; }
+ }
+
+ ////
+
+ RowLayout {
+ anchors.horizontalCenter: parent.horizontalCenter
+ width: singleColumn ? (itemNoPermissions.width*0.85) : undefined
+ spacing: Theme.componentMargin
+
+ visible: (Qt.platform.os === "android" || Qt.platform.os === "ios" || Qt.platform.os === "osx")
+
+ IconSvg {
+ Layout.preferredWidth: 20
+ Layout.preferredHeight: 20
+ Layout.alignment: Qt.AlignVCenter
+
+ source: "qrc:/assets/icons_material/baseline-warning-24px.svg"
+ color: Theme.colorWarning
+ }
+ Text {
+ Layout.fillWidth: singleColumn
+ Layout.alignment: Qt.AlignVCenter
+
+ text: qsTr("Authorization to use Bluetooth is required to connect to the sensors.")
+ textFormat: Text.StyledText
+ font.pixelSize: Theme.fontSizeContentSmall
+ color: Theme.colorSubText
+ wrapMode: Text.WordWrap
+ horizontalAlignment: singleColumn ? Text.AlignJustify : Text.AlignHCenter
+ }
+ }
+
+ ////
+
+ RowLayout {
+ anchors.horizontalCenter: parent.horizontalCenter
+ width: singleColumn ? (itemNoPermissions.width*0.85) : undefined
+ spacing: Theme.componentMargin
+
+ visible: (Qt.platform.os === "android")
+
+ IconSvg {
+ Layout.preferredWidth: 20
+ Layout.preferredHeight: 20
+ Layout.alignment: Qt.AlignVCenter
+
+ source: "qrc:/assets/icons_material/baseline-warning-24px.svg"
+ color: Theme.colorWarning
+ }
+ Text {
+ Layout.fillWidth: true
+ Layout.alignment: Qt.AlignVCenter
+
+ text: qsTr("On Android 6+, scanning for Bluetooth Low Energy devices requires location permission.")
+ textFormat: Text.StyledText
+ font.pixelSize: Theme.fontSizeContentSmall
+ color: Theme.colorSubText
+ wrapMode: Text.WordWrap
+ horizontalAlignment: singleColumn ? Text.AlignJustify : Text.AlignHCenter
+ }
+ }
+
+ ////
+
+ RowLayout {
+ anchors.horizontalCenter: parent.horizontalCenter
+ width: singleColumn ? (itemNoPermissions.width*0.85) : undefined
+ spacing: Theme.componentMargin
+
+ visible: (Qt.platform.os === "android" && !deviceManager.permissionLocationGPS)
+
+ IconSvg {
+ Layout.preferredWidth: 20
+ Layout.preferredHeight: 20
+ Layout.alignment: Qt.AlignVCenter
+
+ source: "qrc:/assets/icons_material/baseline-warning-24px.svg"
+ color: Theme.colorSubText
+ }
+
+ Text {
+ Layout.fillWidth: singleColumn
+ Layout.alignment: Qt.AlignVCenter
+
+ text: qsTr("Some Android devices also require the actual GPS to be turned on.")
+ textFormat: Text.StyledText
+ font.pixelSize: Theme.fontSizeContentSmall
+ color: Theme.colorSubText
+ wrapMode: Text.WordWrap
+ horizontalAlignment: singleColumn ? Text.AlignJustify : Text.AlignHCenter
+ }
+ }
+
+ ////
+
+ RowLayout {
+ anchors.horizontalCenter: parent.horizontalCenter
+ width: singleColumn ? (itemNoPermissions.width*0.85) : undefined
+ spacing: Theme.componentMargin
+
+ visible: (Qt.platform.os === "android")
+
+ IconSvg {
+ Layout.preferredWidth: 20
+ Layout.preferredHeight: 20
+ Layout.alignment: Qt.AlignVCenter
+
+ source: "qrc:/assets/icons_material/baseline-info-24px.svg"
+ color: Theme.colorSubText
+ }
+ Text {
+ Layout.fillWidth: singleColumn
+ Layout.alignment: Qt.AlignVCenter
+
+ text: qsTr("The application is neither using nor storing your location. Sorry for the inconvenience.")
+ textFormat: Text.PlainText
+ font.pixelSize: Theme.fontSizeContentSmall
+ color: Theme.colorSubText
+ wrapMode: Text.WordWrap
+ horizontalAlignment: singleColumn ? Text.AlignJustify : Text.AlignHCenter
+ }
+ }
+
+ ////
+
+ Row {
+ anchors.horizontalCenter: parent.horizontalCenter
+ spacing: Theme.componentMargin
+
+ ButtonWireframeIcon {
+ //width: ((isDesktop || isTablet) && !singleColumn) ? 256 : undefined
+
+ text: qsTr("Official information")
+ primaryColor: Theme.colorSubText
+ sourceSize: 20
+ source: "qrc:/assets/icons_material/duotone-launch-24px.svg"
+
+ onClicked: {
+ if (Qt.platform.os === "android") {
+ if (utilsApp.getAndroidSdkVersion() >= 12)
+ Qt.openUrlExternally("https://developer.android.com/guide/topics/connectivity/bluetooth/permissions#declare-android12-or-higher")
+ else
+ Qt.openUrlExternally("https://developer.android.com/guide/topics/connectivity/bluetooth/permissions#declare-android11-or-lower")
+ } else if (Qt.platform.os === "ios") {
+ Qt.openUrlExternally("https://support.apple.com/HT210578")
+ }
+ }
+ }
+ }
+
+ ////
+ }
+}
diff --git a/qml/qml.qrc b/qml/qml.qrc
index d64ffeab..b04880aa 100644
--- a/qml/qml.qrc
+++ b/qml/qml.qrc
@@ -61,9 +61,11 @@
components/ItemEnvBox.qml
components/ItemWeatherBox.qml
components/ItemLoadData.qml
- components/ItemNoData.qml
+ components/ItemNoBluetooth.qml
+ components/ItemNoPermissions.qml
components/ItemNoDevice.qml
components/ItemNoDeviceNearby.qml
+ components/ItemNoData.qml
components/ItemNoPlant.qml
components/ItemNoPlants.qml
components/ItemNoJournal.qml
diff --git a/src/DeviceManager.cpp b/src/DeviceManager.cpp
index 09fcf4ab..a72a10d5 100644
--- a/src/DeviceManager.cpp
+++ b/src/DeviceManager.cpp
@@ -62,7 +62,7 @@
#include
#include
-#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
+#if defined(Q_OS_MACOS) || defined(Q_OS_IOS) || defined(Q_OS_ANDROID)
#if QT_CONFIG(permissions)
#include
#include
@@ -313,6 +313,10 @@ bool DeviceManager::enableBluetooth(bool enforceUserPermissionCheck)
if (m_bluetoothAdapter && !m_bluetoothAdapter->isValid())
{
qDebug() << "DeviceManager::enableBluetooth() deleting current adapter";
+
+ disconnect(m_bluetoothAdapter, &QBluetoothLocalDevice::hostModeStateChanged,
+ this, &DeviceManager::bluetoothHostModeStateChanged);
+
delete m_bluetoothAdapter;
m_bluetoothAdapter = nullptr;
}
@@ -366,6 +370,7 @@ bool DeviceManager::enableBluetooth(bool enforceUserPermissionCheck)
}
else
{
+ qWarning() << "DeviceManager::enableBluetooth() we have an invalid adapter";
m_bleAdapter = false;
m_bleEnabled = false;
}
@@ -386,11 +391,16 @@ bool DeviceManager::checkBluetoothPermissions()
{
//qDebug() << "DeviceManager::checkBluetoothPermissions()";
-#if !defined(Q_OS_MACOS) && !defined(Q_OS_IOS)
+#if defined(Q_OS_ANDROID)
+ //
+#elif defined(Q_OS_LINUX) || defined(Q_OS_WINDOWS)
+ // These OS don't ask for any particular permissions
m_permOS = true;
+ m_blePermissions = true;
#endif
#if !defined(Q_OS_ANDROID)
+ // The location permission(s) debacle is Android only
m_permLocationBLE = true;
m_permLocationBKG = true;
m_permGPS = true;
@@ -403,44 +413,33 @@ bool DeviceManager::checkBluetoothPermissions()
bool btP_was = m_blePermissions;
#if defined(Q_OS_ANDROID)
-
+ m_permOS = UtilsApp::checkMobileBluetoothPermission();
m_permLocationBLE = UtilsApp::checkMobileBleLocationPermission();
m_permLocationBKG = UtilsApp::checkMobileBackgroundLocationPermission();
m_permGPS = UtilsApp::isMobileGpsEnabled();
- // set m_permLocationBLE as primary
- // we will check for GPS or background location permissions explicitely if we need them
- m_blePermissions = m_permLocationBLE;
+ m_blePermissions = m_permOS && m_permLocationBLE;
+#endif
-#elif defined(Q_OS_MACOS) || defined(Q_OS_IOS)
+#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
#if QT_CONFIG(permissions)
-
if (qApp)
{
- QBluetoothPermission blePermission;
- switch (qApp->checkPermission(blePermission))
+ switch (qApp->checkPermission(QBluetoothPermission{}))
{
case Qt::PermissionStatus::Undetermined:
- qApp->requestPermission(blePermission, this, &DeviceManager::checkBluetoothPermissions);
- return false;
case Qt::PermissionStatus::Denied:
m_permOS = false;
- m_blePermissions = m_permOS;
+ m_blePermissions = false;
break;
case Qt::PermissionStatus::Granted:
m_permOS = true;
- m_blePermissions = m_permOS;
+ m_blePermissions = true;
break;
}
}
-
#endif // QT_CONFIG(permissions)
-#else
-
- // Linux and Windows don't have required BLE permissions
- m_blePermissions = true;
-
-#endif
+#endif // defined(Q_OS_MACOS) || defined(Q_OS_IOS)
if (os_was != m_permOS || gps_was != m_permGPS ||
loc_was != m_permLocationBLE || loc_bg_was != m_permLocationBKG)
@@ -457,11 +456,91 @@ bool DeviceManager::checkBluetoothPermissions()
return m_blePermissions;
}
+bool DeviceManager::requestBluetoothPermissions()
+{
+ //qDebug() << "DeviceManager::requestBluetoothPermissions()";
+
+#if defined(Q_OS_ANDROID)
+#if QT_CONFIG(permissions)
+
+ // qApp->checkPermission(QBluetoothPermission{}) doesn't work on Android
+ // so we do it ourselves, the old fashioned way...
+
+ bool permLocationBLE = UtilsApp::checkMobileBleLocationPermission();
+ bool permOS = UtilsApp::checkMobileBluetoothPermission();
+
+ if (!permLocationBLE || !permOS)
+ {
+ if (qApp)
+ {
+ qApp->requestPermission(QBluetoothPermission{}, this, &DeviceManager::requestBluetoothPermissions_results);
+ }
+ }
+
+#else // QT_CONFIG(permissions)
+
+ m_permOS = UtilsApp::getMobileBluetoothPermission();
+ m_permLocationBLE = UtilsApp::getMobileBleLocationPermission();
+ m_blePermissions = m_permOS && m_permLocationBLE;
+
+#endif // QT_CONFIG(permissions)
+#endif // defined(Q_OS_ANDROID)
+
+#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
+#if QT_CONFIG(permissions)
+
+ if (qApp)
+ {
+ switch (qApp->checkPermission(QBluetoothPermission{}))
+ {
+ case Qt::PermissionStatus::Undetermined:
+ qDebug() << "Qt::PermissionStatus::Undetermined";
+ qApp->requestPermission(QBluetoothPermission{}, this, &DeviceManager::requestBluetoothPermissions_results);
+ break;
+ case Qt::PermissionStatus::Granted:
+ qDebug() << "Qt::PermissionStatus::Granted";
+ m_permOS = true;
+ m_blePermissions = true;
+ break;
+ case Qt::PermissionStatus::Denied:
+ qDebug() << "Qt::PermissionStatus::Denied";
+ m_permOS = false;
+ m_blePermissions = false;
+ break;
+ }
+ }
+
+#endif // QT_CONFIG(permissions)
+#endif // defined(Q_OS_MACOS) || defined(Q_OS_IOS)
+
+ return m_blePermissions;
+}
+
+void DeviceManager::requestBluetoothPermissions_results()
+{
+ // evaluate the results
+ checkBluetooth();
+
+ if (m_blePermissions)
+ {
+ // try enabling the adapter
+ if (!m_bleAdapter || !m_bleEnabled)
+ {
+ enableBluetooth();
+ }
+ }
+ else
+ {
+ // try again?
+ //requestBluetoothPermissions();
+ }
+}
+
/* ************************************************************************** */
void DeviceManager::bluetoothHostModeStateChanged(QBluetoothLocalDevice::HostMode state)
{
- qDebug() << "DeviceManager::bluetoothHostModeStateChanged() host mode now:" << state;
+ //qDebug() << "DeviceManager::bluetoothHostModeStateChanged() host mode now:" << state;
if (state != m_ble_hostmode)
{
@@ -505,6 +584,20 @@ void DeviceManager::bluetoothStatusChanged()
}
}
+void DeviceManager::bluetoothPermissionsChanged()
+{
+ //qDebug() << "DeviceManager::bluetoothPermissionsChanged()";
+
+ if (m_bleAdapter && m_bleEnabled)
+ {
+ checkBluetooth();
+ }
+ else
+ {
+ enableBluetooth();
+ }
+}
+
/* ************************************************************************** */
/* ************************************************************************** */
@@ -1486,8 +1579,9 @@ void DeviceManager::addBleDevice(const QBluetoothDeviceInfo &info)
// Various sanity checks
{
if (info.rssi() >= 0) return; // we probably just hit the device cache
-
+ //if ((info.coreConfigurations() & QBluetoothDeviceInfo::LowEnergyCoreConfiguration) == false) return; // not a BLE device
if (m_devices_blacklist.contains(info.address().toString())) return; // device is blacklisted
+ if (m_devices_blacklist.contains(info.deviceUuid().toString())) return; // device is blacklisted
SettingsManager *sm = SettingsManager::getInstance();
if (sm && sm->getBluetoothLimitScanningRange() && info.rssi() < -70) return; // device is too far away
@@ -1610,7 +1704,7 @@ void DeviceManager::addBleDevice(const QBluetoothDeviceInfo &info)
}
}
- //
+ // Connect and handle update
connect(d, &Device::deviceUpdated, this, &DeviceManager::refreshDevices_finished);
connect(d, &Device::deviceSynced, this, &DeviceManager::syncDevices_finished);
diff --git a/src/DeviceManager.h b/src/DeviceManager.h
index 68f122d2..bbb15f5a 100644
--- a/src/DeviceManager.h
+++ b/src/DeviceManager.h
@@ -90,9 +90,9 @@ class DeviceManager: public QObject
bool m_bleAdapter = false; //!< do we have a BLE adapter?
bool m_bleEnabled = false; //!< is the BLE adapter enabled?
- bool m_blePermissions = false; //!< do we have necessary BLE permissions? (OS independent)
+ bool m_blePermissions = false; //!< do we have necessary BLE permissions? (brings together all other permsissions)
- bool m_permOS = false; //!< do we have OS permissions for BLE? (macOS, iOS)
+ bool m_permOS = false; //!< do we have OS permissions for BLE? (macOS, iOS, Android)
bool m_permLocationBLE = false; //!< do we location permission? (Android)
bool m_permLocationBKG = false; //!< do we background location permission? (Android)
bool m_permGPS = false; //!< is the GPS enabled? (Android)
@@ -164,6 +164,7 @@ class DeviceManager: public QObject
Q_SIGNALS:
void bluetoothChanged();
+ void hostModeChanged();
void permissionsChanged();
void adaptersListUpdated();
@@ -177,12 +178,12 @@ class DeviceManager: public QObject
void scanningChanged();
void updatingChanged();
void syncingChanged();
- void hostModeChanged();
private slots:
// QBluetoothLocalDevice related
void bluetoothHostModeStateChanged(QBluetoothLocalDevice::HostMode);
void bluetoothStatusChanged();
+ void bluetoothPermissionsChanged();
// QBluetoothDeviceDiscoveryAgent related
void addNearbyBleDevice(const QBluetoothDeviceInfo &info);
@@ -210,6 +211,8 @@ private slots:
Q_INVOKABLE bool checkBluetooth();
Q_INVOKABLE bool checkBluetoothPermissions();
Q_INVOKABLE bool enableBluetooth(bool enforceUserPermissionCheck = false);
+ Q_INVOKABLE bool requestBluetoothPermissions();
+ void requestBluetoothPermissions_results();
// Scanning management
static int getLastRun();
diff --git a/src/thirdparty/AppUtils/utils_app.cpp b/src/thirdparty/AppUtils/utils_app.cpp
index b12bed40..35ead48e 100644
--- a/src/thirdparty/AppUtils/utils_app.cpp
+++ b/src/thirdparty/AppUtils/utils_app.cpp
@@ -253,9 +253,9 @@ int UtilsApp::getAndroidSdkVersion()
{
#if defined(Q_OS_ANDROID)
return UtilsAndroid::getSdkVersion();
-#else
- return 0;
#endif
+
+ return 0;
}
void UtilsApp::openAndroidAppInfo(const QString &packageName)
@@ -283,60 +283,84 @@ void UtilsApp::openAndroidLocationSettings()
#endif
}
+/* ************************************************************************** */
+
+bool UtilsApp::checkMobileBluetoothPermission()
+{
+#if defined(Q_OS_ANDROID)
+ return UtilsAndroid::checkPermission_bluetooth();
+#elif defined(Q_OS_IOS)
+ #warning("Please use Qt permission system directly on iOS")
+ return false;
+#endif
+
+ return true;
+}
+
+bool UtilsApp::getMobileBluetoothPermission()
+{
+#if defined(Q_OS_ANDROID)
+ return UtilsAndroid::getPermission_bluetooth();
+#elif defined(Q_OS_IOS)
+ #warning("Please use Qt permission system directly on iOS")
+ return false;
+#endif
+
+ return true;
+}
+
bool UtilsApp::checkMobileLocationPermission()
{
#if defined(Q_OS_ANDROID)
return UtilsAndroid::checkPermission_location();
-#else
- return true;
#endif
+
+ return true;
}
bool UtilsApp::getMobileLocationPermission()
{
#if defined(Q_OS_ANDROID)
return UtilsAndroid::getPermission_location();
-#else
- return true;
#endif
+
+ return true;
}
bool UtilsApp::checkMobileBleLocationPermission()
{
#if defined(Q_OS_ANDROID)
return UtilsAndroid::checkPermission_location_ble();
-#elif defined(Q_OS_IOS)
- return true; // TODO // we know have Bluetooth permission on iOS too
-#else
- return true;
#endif
+
+ return true;
}
bool UtilsApp::getMobileBleLocationPermission()
{
#if defined(Q_OS_ANDROID)
return UtilsAndroid::getPermission_location_ble();
-#else
- return true;
#endif
+
+ return true;
}
bool UtilsApp::checkMobileBackgroundLocationPermission()
{
#if defined(Q_OS_ANDROID)
return UtilsAndroid::checkPermission_location_background();
-#else
- return true;
#endif
+
+ return true;
}
bool UtilsApp::getMobileBackgroundLocationPermission()
{
#if defined(Q_OS_ANDROID)
return UtilsAndroid::getPermission_location_background();
-#else
- return true;
#endif
+
+ return true;
}
bool UtilsApp::checkMobileStoragePermissions()
@@ -345,9 +369,9 @@ bool UtilsApp::checkMobileStoragePermissions()
return UtilsAndroid::checkPermissions_storage();
#elif defined(Q_OS_IOS)
return false;
-#else
- return true;
#endif
+
+ return true;
}
bool UtilsApp::getMobileStoragePermissions()
@@ -356,9 +380,9 @@ bool UtilsApp::getMobileStoragePermissions()
return UtilsAndroid::getPermissions_storage();
#elif defined(Q_OS_IOS)
return false;
-#else
- return true;
#endif
+
+ return true;
}
bool UtilsApp::checkMobileStorageReadPermission()
@@ -367,9 +391,9 @@ bool UtilsApp::checkMobileStorageReadPermission()
return UtilsAndroid::checkPermission_storage_read();
#elif defined(Q_OS_IOS)
return false;
-#else
- return true;
#endif
+
+ return true;
}
bool UtilsApp::getMobileStorageReadPermission()
@@ -378,9 +402,9 @@ bool UtilsApp::getMobileStorageReadPermission()
return UtilsAndroid::getPermission_storage_read();
#elif defined(Q_OS_IOS)
return false;
-#else
- return true;
#endif
+
+ return true;
}
bool UtilsApp::checkMobileStorageWritePermission()
@@ -389,9 +413,9 @@ bool UtilsApp::checkMobileStorageWritePermission()
return UtilsAndroid::checkPermission_storage_write();
#elif defined(Q_OS_IOS)
return false;
-#else
- return true;
#endif
+
+ return true;
}
bool UtilsApp::getMobileStorageWritePermission()
@@ -400,9 +424,9 @@ bool UtilsApp::getMobileStorageWritePermission()
return UtilsAndroid::getPermission_storage_write();
#elif defined(Q_OS_IOS)
return false;
-#else
- return true;
#endif
+
+ return true;
}
bool UtilsApp::checkMobileStorageFileSystemPermission()
@@ -411,9 +435,9 @@ bool UtilsApp::checkMobileStorageFileSystemPermission()
return UtilsAndroid::checkPermission_storage_filesystem();
#elif defined(Q_OS_IOS)
return false;
-#else
- return true;
#endif
+
+ return true;
}
bool UtilsApp::getMobileStorageFileSystemPermission(const QString &packageName)
@@ -424,9 +448,9 @@ bool UtilsApp::getMobileStorageFileSystemPermission(const QString &packageName)
return UtilsAndroid::getPermission_storage_filesystem(packageName);
#elif defined(Q_OS_IOS)
return false;
-#else
- return true;
#endif
+
+ return true;
}
bool UtilsApp::checkMobilePhoneStatePermission()
@@ -435,9 +459,9 @@ bool UtilsApp::checkMobilePhoneStatePermission()
return UtilsAndroid::checkPermission_phonestate();
#elif defined(Q_OS_IOS)
return false;
-#else
- return true;
#endif
+
+ return true;
}
bool UtilsApp::getMobilePhoneStatePermission()
@@ -446,9 +470,9 @@ bool UtilsApp::getMobilePhoneStatePermission()
return UtilsAndroid::getPermission_phonestate();
#elif defined(Q_OS_IOS)
return false;
-#else
- return true;
#endif
+
+ return true;
}
/* ************************************************************************** */
@@ -459,9 +483,9 @@ bool UtilsApp::checkMobileCameraPermission()
return UtilsAndroid::checkPermission_camera();
#elif defined(Q_OS_IOS)
return false;
-#else
- return true;
#endif
+
+ return true;
}
bool UtilsApp::getMobileCameraPermission()
@@ -470,9 +494,33 @@ bool UtilsApp::getMobileCameraPermission()
return UtilsAndroid::getPermission_camera();
#elif defined(Q_OS_IOS)
return false;
-#else
+#endif
+
return true;
+}
+
+/* ************************************************************************** */
+
+bool UtilsApp::checkMobileNotificationPermission()
+{
+#if defined(Q_OS_ANDROID)
+ return UtilsAndroid::getPermission_notification();
+#elif defined(Q_OS_IOS)
+ return false;
#endif
+
+ return true;
+}
+
+bool UtilsApp::getMobileNotificationPermission()
+{
+#if defined(Q_OS_ANDROID)
+ return UtilsAndroid::getPermission_notification();
+#elif defined(Q_OS_IOS)
+ return false;
+#endif
+
+ return true;
}
/* ************************************************************************** */
@@ -482,10 +530,10 @@ bool UtilsApp::isMobileGpsEnabled()
#if defined(Q_OS_ANDROID)
return UtilsAndroid::gpsutils_isGpsEnabled();
#elif defined(Q_OS_IOS)
- return false; // TODO
-#else
- return false;
+ return false; // TODO?
#endif
+
+ return false;
}
void UtilsApp::forceMobileGpsEnabled()
@@ -501,18 +549,18 @@ QString UtilsApp::getMobileDeviceModel()
{
#if defined(Q_OS_ANDROID)
return UtilsAndroid::getDeviceModel();
-#else
- return QString();
#endif
+
+ return QString();
}
QString UtilsApp::getMobileDeviceSerial()
{
#if defined(Q_OS_ANDROID)
return UtilsAndroid::getDeviceSerial();
-#else
- return QString();
#endif
+
+ return QString();
}
/* ************************************************************************** */
diff --git a/src/thirdparty/AppUtils/utils_app.h b/src/thirdparty/AppUtils/utils_app.h
index 6514b0cf..397eb145 100644
--- a/src/thirdparty/AppUtils/utils_app.h
+++ b/src/thirdparty/AppUtils/utils_app.h
@@ -92,6 +92,9 @@ class UtilsApp : public QObject
static Q_INVOKABLE bool checkMobileStorageFileSystemPermission();
static Q_INVOKABLE bool getMobileStorageFileSystemPermission(const QString &packageName);
+ static Q_INVOKABLE bool checkMobileBluetoothPermission();
+ static Q_INVOKABLE bool getMobileBluetoothPermission();
+
static Q_INVOKABLE bool checkMobileLocationPermission();
static Q_INVOKABLE bool getMobileLocationPermission();
@@ -107,6 +110,9 @@ class UtilsApp : public QObject
static Q_INVOKABLE bool checkMobileCameraPermission();
static Q_INVOKABLE bool getMobileCameraPermission();
+ static Q_INVOKABLE bool checkMobileNotificationPermission();
+ static Q_INVOKABLE bool getMobileNotificationPermission();
+
static Q_INVOKABLE bool isMobileGpsEnabled();
static Q_INVOKABLE void forceMobileGpsEnabled();
diff --git a/src/thirdparty/AppUtils/utils_os_android.h b/src/thirdparty/AppUtils/utils_os_android.h
index 579e9de8..6d52d6d6 100644
--- a/src/thirdparty/AppUtils/utils_os_android.h
+++ b/src/thirdparty/AppUtils/utils_os_android.h
@@ -78,6 +78,26 @@ class UtilsAndroid
*/
static bool getPermission_camera();
+ /*!
+ * \return True if POST_NOTIFICATIONS permission has been previously obtained.
+ */
+ static bool checkPermission_notification();
+
+ /*!
+ * \return True if POST_NOTIFICATIONS permission has been explicitly obtained.
+ */
+ static bool getPermission_notification();
+
+ /*!
+ * \return True if Bluetooth permission has been previously obtained.
+ */
+ static bool checkPermission_bluetooth();
+
+ /*!
+ * \return True if Bluetooth permission has been explicitly obtained.
+ */
+ static bool getPermission_bluetooth();
+
/*!
* \return True if ACCESS_FINE_LOCATION permission has been previously obtained.
*/
diff --git a/src/thirdparty/AppUtils/utils_os_android_qt5.cpp b/src/thirdparty/AppUtils/utils_os_android_qt5.cpp
index ee6316b6..e37c91fb 100644
--- a/src/thirdparty/AppUtils/utils_os_android_qt5.cpp
+++ b/src/thirdparty/AppUtils/utils_os_android_qt5.cpp
@@ -164,6 +164,30 @@ bool UtilsAndroid::getPermission_camera()
/* ************************************************************************** */
+bool UtilsAndroid::checkPermission_notification()
+{
+ return false; // TODO
+}
+
+bool UtilsAndroid::getPermission_notification()
+{
+ return false; // TODO
+}
+
+/* ************************************************************************** */
+
+bool UtilsAndroid::checkPermission_bluetooth()
+{
+ return false; // TODO
+}
+
+bool UtilsAndroid::getPermission_bluetooth()
+{
+ return false; // TODO
+}
+
+/* ************************************************************************** */
+
bool UtilsAndroid::checkPermission_location()
{
QtAndroid::PermissionResult loc = QtAndroid::checkPermission("android.permission.ACCESS_FINE_LOCATION");
diff --git a/src/thirdparty/AppUtils/utils_os_android_qt6.cpp b/src/thirdparty/AppUtils/utils_os_android_qt6.cpp
index b486553a..661e228d 100644
--- a/src/thirdparty/AppUtils/utils_os_android_qt6.cpp
+++ b/src/thirdparty/AppUtils/utils_os_android_qt6.cpp
@@ -189,6 +189,113 @@ bool UtilsAndroid::getPermission_camera()
/* ************************************************************************** */
+bool UtilsAndroid::checkPermission_notification()
+{
+ QFuture notif = QtAndroidPrivate::checkPermission("android.permission.POST_NOTIFICATIONS");
+ //cam.waitForFinished();
+
+ return (notif.result() == QtAndroidPrivate::PermissionResult::Authorized);
+}
+
+bool UtilsAndroid::getPermission_notification()
+{
+ bool status = true;
+
+ QFuture notif = QtAndroidPrivate::checkPermission("android.permission.POST_NOTIFICATIONS");
+ //notif.waitForFinished();
+
+ if (notif.result() == QtAndroidPrivate::PermissionResult::Denied)
+ {
+ QtAndroidPrivate::requestPermission("android.permission.POST_NOTIFICATIONS");
+ notif = QtAndroidPrivate::checkPermission("android.permission.POST_NOTIFICATIONS");
+ //notif.waitForFinished();
+
+ if (notif.result() == QtAndroidPrivate::PermissionResult::Denied)
+ {
+ qWarning() << "POST_NOTIFICATIONS PERMISSION DENIED";
+ status = false;
+ }
+ }
+
+ return status;
+}
+
+/* ************************************************************************** */
+
+bool UtilsAndroid::checkPermission_bluetooth()
+{
+ bool status = false;
+
+ // (up to) Android 11 / SDK 30
+ // BLUETOOTH
+ // BLUETOOTH_ADMIN
+
+ if (getSdkVersion() <= 30)
+ {
+ QFuture ble = QtAndroidPrivate::checkPermission("android.permission.BLUETOOTH");
+ //ble.waitForFinished();
+
+ QFuture ble_admin = QtAndroidPrivate::checkPermission("android.permission.BLUETOOTH_ADMIN");
+ //ble_admin.waitForFinished();
+
+ status = (ble.result() == QtAndroidPrivate::PermissionResult::Authorized) &&
+ (ble_admin.result() == QtAndroidPrivate::PermissionResult::Authorized);
+ }
+
+ // (from) Android 12+ / SDK 31
+ // BLUETOOTH_SCAN
+ // BLUETOOTH_CONNECT
+
+ if (getSdkVersion() >= 31)
+ {
+ QFuture ble_scan = QtAndroidPrivate::checkPermission("android.permission.BLUETOOTH_SCAN");
+ //ble_scan.waitForFinished();
+
+ QFuture ble_connect = QtAndroidPrivate::checkPermission("android.permission.BLUETOOTH_CONNECT");
+ //ble_connect.waitForFinished();
+
+ status = (ble_scan.result() == QtAndroidPrivate::PermissionResult::Authorized) &&
+ (ble_connect.result() == QtAndroidPrivate::PermissionResult::Authorized);
+ }
+
+ return status;
+}
+
+bool UtilsAndroid::getPermission_bluetooth()
+{
+ if (getSdkVersion() <= 30)
+ {
+ QFuture ble = QtAndroidPrivate::checkPermission("android.permission.BLUETOOTH");
+ if (ble.result() == QtAndroidPrivate::PermissionResult::Denied)
+ {
+ QtAndroidPrivate::requestPermission("android.permission.BLUETOOTH");
+ }
+ QFuture ble_admin = QtAndroidPrivate::checkPermission("android.permission.BLUETOOTH_ADMIN");
+ if (ble_admin.result() == QtAndroidPrivate::PermissionResult::Denied)
+ {
+ QtAndroidPrivate::requestPermission("android.permission.BLUETOOTH_ADMIN");
+ }
+ }
+
+ if (getSdkVersion() >= 31)
+ {
+ QFuture ble_scan = QtAndroidPrivate::checkPermission("android.permission.BLUETOOTH_SCAN");
+ if (ble_scan.result() == QtAndroidPrivate::PermissionResult::Denied)
+ {
+ QtAndroidPrivate::requestPermission("android.permission.BLUETOOTH_SCAN");
+ }
+ QFuture ble_connect = QtAndroidPrivate::checkPermission("android.permission.BLUETOOTH_CONNECT");
+ if (ble_connect.result() == QtAndroidPrivate::PermissionResult::Denied)
+ {
+ QtAndroidPrivate::requestPermission("android.permission.BLUETOOTH_CONNECT");
+ }
+ }
+
+ return checkPermission_bluetooth();
+}
+
+/* ************************************************************************** */
+
bool UtilsAndroid::checkPermission_location()
{
QFuture loc = QtAndroidPrivate::checkPermission("android.permission.ACCESS_FINE_LOCATION");