FalsinSoft / QtAndroidTools

A library to manage Android from QML
MIT License
261 stars 82 forks source link

Exception after lowering & raising window when using battery status #13

Closed Allstar12345 closed 4 years ago

Allstar12345 commented 4 years ago

Just caught this little bug when using the battery module Tested on Android 8.0 and 10 Minimise the App then bringing back into view causes a crash and the following from debugger:

F ample.wearmusi: java_vm_ext.cc:570] JNI DETECTED ERROR IN APPLICATION: JNI CallVoidMethodV called with pending exception java.lang.IllegalArgumentException: Receiver not registered: com.falsinsoft.qtandroidtools.AndroidBatteryState$BatteryStateChangeReceiver@fd7c128

F ample.wearmusi: java_vm_ext.cc:570]   at android.content.IIntentReceiver android.app.LoadedApk.forgetReceiverDispatcher(android.content.Context, android.content.BroadcastReceiver) (LoadedApk.java:1429)

F ample.wearmusi: java_vm_ext.cc:570]   at void android.app.ContextImpl.unregisterReceiver(android.content.BroadcastReceiver) (ContextImpl.java:1577)

F ample.wearmusi: java_vm_ext.cc:570]   at void android.content.ContextWrapper.unregisterReceiver(android.content.BroadcastReceiver) (ContextWrapper.java:664)

F ample.wearmusi: java_vm_ext.cc:570]   at void com.falsinsoft.qtandroidtools.AndroidBatteryState.appStateChanged(int) (AndroidBatteryState.java:70)
FalsinSoft commented 4 years ago

Hi Can you clarify what you mean with "minimise the App"?

Allstar12345 commented 4 years ago

Lowering the app, so it still shows in the task switcher, this occurs on the QtAndroidToolsExample too

FalsinSoft commented 4 years ago

Try the latest committed version, it should fix the problem.

Allstar12345 commented 4 years ago

That's fixed it, thanks.

zlutor commented 4 years ago

Hi,

I try to reproduce demo AdMob examples in my application but I get nothing but blank screen (on emulators). It seems if "import QtAndroidTools 1.0" is in my QML file, original page will not be displayed but black screen only...

.pro file and given .qml file attached, permissions are set in manifest:

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

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

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

Thanks for your help in advance.

Zoltan

import QtQuick 2.7 import QtMultimedia 5.8 import QtAndroidTools 1.0

import "levelcompletedresource.js" as Resources import "levelcompleted.js" as LevelCompleteLogic import "../gamelogic.js" as GameLogic import "../gameoptions.js" as GameOptions import "../storymodelogic.js" as StoryModeLogic import "../scaling.js" as Scaling import "../forfictionmobile" import ".."

Item { id: levelCompletedPage / private / property int counter : 0 property int actualStarIndex : 0

focus: true

width: 240
height: 400

// Implements back key navigation
// http://doc.qt.io/qt-5/qtquick-input-focus.html
Keys.onReleased:    { handleBackKey( event ) }

function handleBackKey( event )
{
    if (event.key === Qt.Key_Back)
    {
        event.accepted = true
        backToPage("selectLevelPage")
    }
}

//    QtAndroidAdMobRewardedVideo {
//        id: rewardedVideo
//        unitId: "ca-app-pub-3940256099942544/5224354917"
//        onRewarded: rewardedVideoResult.text = "Type: " + type + " - Amount: " + amount
//        onLoadError: rewardedVideoState.text = "Error " + errorId
//        onLoading: rewardedVideoState.text = "Loading"
//        onLoaded: rewardedVideoState.text = "Loaded"
//        onOpened: rewardedVideoState.text = "Opened"
//        onClosed: rewardedVideoState.text = "Closed"
//        onStarted: rewardedVideoState.text = "Started"
//        onCompleted: rewardedVideoState.text = "Completed"
//        onLeftApplication: rewardedVideoState.text = "LeftApplication"
//    }

QtAndroidAdMobInterstitial {
    id: adMobInterstitial
    unitId: "ca-app-pub-3940256099942544/1033173712"
    onLoading: { console.debug("Loading...") }
    onLoaded: { console.debug("Loaded" )
        adMobInterstitial.show()
    }
    onLoadError: { console.debug("Error: " + errorId) }
    onClicked: {
        GameLogic.addIncome(amount)
        moneyIndicator.bonusMoney = amount
    }
}

Audio {
    id: audioPlayer
    volume: 0.8

    onStatusChanged: {
        if( Audio.Loaded === status && levelCompletedPage.visible ) {
            play()
        }
    }

    Component.onCompleted: {
        if (GameOptions.isSoundOn()) {
            source = "qrc:/sound/complete.mp3"
        }
    }
}

onVisibleChanged: {
    if ( !visible ) {
        audioPlayer.stop()
    }
}

Rectangle {
    id: background
    anchors.fill: parent
    color: "black"
}

Image {
    id: levelCompletedImage
    anchors.centerIn: parent
    source: Resources.getLevelCompletedImageResource()
}

Image {
    id: levelCompletedButtons
    anchors.horizontalCenter: parent.horizontalCenter
    anchors.top : levelCompletedImage.bottom
    anchors.margins: height/5
    source: Resources.getLevelCompletedButtonsResource()

    ClickOnceArea {
        id : skipMenuItemArea
        width: parent.width/4
        height: parent.height
        anchors.left: parent.left

        onClicked: { backToPage("selectLevelPage") }
    }

    ClickOnceArea {
        id : retryMenuItemArea
        width: parent.width/4
        height: parent.height
        anchors.left: skipMenuItemArea.right

        onClicked: {
            stackView.push( {item: Qt.resolvedUrl("../StoryGamePage.qml")
                               , immediate: true
                               , replace: true})
        }
    }

    ClickOnceArea {
        id : shopMenuItemArea
        width: parent.width/4
        height: parent.height
        anchors.left: retryMenuItemArea.right

        onClicked: { stackView.push(Qt.resolvedUrl("../shopping/ShoppingPage.qml")) }
    }

    ClickOnceArea {
        id : nextLevelMenuItemArea
        width: parent.width/4
        height: parent.height
        anchors.left: shopMenuItemArea.right

        onClicked: {
            if (StoryModeLogic.nextLevel()) {
                backToPage("letsGoPage")
                stackView.push( {item: Qt.resolvedUrl("../LetsGoPage.qml")
                                   , replace: true})
            }
            else {
                backToPage("selectChapterPage")
                stackView.push( {item: Qt.resolvedUrl("../SelectChapterPage.qml")
                                   , replace: true})
            }
        }
    }

}

Repeater {
    id : achievementStars

    model : 3
    Image {
        visible: false
        source : Resources.getLevelCompletedStarImageResource()
    }

    function resize() {
        for(var i = 0; i < 3; ++i) {
            var star = achievementStars.itemAt(i)
            star.width = Resources.getLevelCompletedStarImageWidth()
            star.height = Resources.getLevelCompletedStarImageHeight()
            star.x = Resources.getStarOffsetX(i)
            star.y = Resources.getStarOffsetY()
        }
    }
}

onActualStarIndexChanged: {
    if ( 0 <= actualStarIndex ) {
        var star = achievementStars.itemAt(actualStarIndex)
        star.visible = true
    }
}

NumberAnimation on actualStarIndex {
    id: achievementStarsAnimation
    duration : 1500
    from: -1
    to : LevelCompleteLogic.getNumberOfStars()-1
}

Text {

    property int moneyEarned: 0
    property int animatedMoney : 0
    property int bonusMoney: 0

    id: moneyIndicator
    height : parent.height/7

    verticalAlignment: Text.AlignVCenter
    color : "white"
    font.bold: true
    fontSizeMode : Text.VerticalFit
    minimumPixelSize: 10
    font.pixelSize: 72
    font.family: oogieBoogieFont.name
    style: Text.Raised
    styleColor: "black"
    text: "X " + animatedMoney

    NumberAnimation on animatedMoney {
        running: false
        id: moneyIndicatorAnimation
        duration: 1500
        from: 0
        to : moneyIndicator.moneyEarned

        onStopped: { bonusIndicator.show() }
    }

    onBonusMoneyChanged: {
        text = "X " + (moneyEarned+bonusMoney)
    }
}

BonusIndicator {
    id: bonusIndicator
    anchors.horizontalCenter: parent.horizontalCenter
    anchors.bottom: levelCompletedImage.top
    anchors.margins: height/2

    maxBonus: Math.max(50, 10*(Math.round(moneyIndicator.moneyEarned/30)))

    onBonusGrabbed: {
        //            GameLogic.addIncome(amount)
        //            moneyIndicator.bonusMoney = amount
        //adMobInterstitial.show()
    }

    function rescale() {
        var area = Resources.getBonusArea()
        width = area.width
        height = area.height
    }
}

onWidthChanged: { resize() }
onHeightChanged: { resize() }
Component.onCompleted: {
    console.debug("onCompleted" )
    //        rewardedVideo.load()
    adMobInterstitial.load()
    resize()
    achievementStarsAnimation.start()
    StoryModeLogic.storeNumberOfStarsGot(LevelCompleteLogic.getNumberOfStars())
    moneyIndicator.moneyEarned = LevelCompleteLogic.getMoneyGot()
    GameLogic.addIncome(moneyIndicator.moneyEarned)
    moneyIndicatorAnimation.start()
}

function resize() {
    if ( 0 < width && 0 < height) {
        Scaling.storeActualScreenDimensions(width, height)

        levelCompletedImage.width = Resources.getLevelCompletedImageWidth()
        levelCompletedImage.height = Resources.getLevelCompletedImageHeight()

        levelCompletedButtons.width = Resources.getLevelCompletedButtonsWidth()
        levelCompletedButtons.height = Resources.getLevelCompletedButtonsHeight()

        moneyIndicator.x = Resources.getMoneyIndicatorOffsetX()
        moneyIndicator.y = Resources.getMoneyIndicatorOffsetY()

        achievementStars.resize()
        bonusIndicator.rescale()
    }
}

function backToPage(name) {
    stackView.pop(stackView.find(function(item) {
        return item.name === name
    }))
}

}

QT += quick QT += multimedia QT += svg QT += sql QT += purchasing

CONFIG += c++11

The following define makes your compiler emit warnings if you use

any Qt feature that has been marked deprecated (the exact warnings

depend on your compiler). Refer to the documentation for the

deprecated API to know how to port your code away from it.

DEFINES += QT_DEPRECATED_WARNINGS

You can also make your code fail to compile if it uses deprecated APIs.

In order to do so, uncomment the following line.

You can also select to disable deprecated APIs only up to a certain version of Qt.

DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \ gamemodel.cpp \ main.cpp

RESOURCES += qml.qrc \ sound.qrc \ visuals.qrc

Additional import path used to resolve QML modules in Qt Creator's code model

QML_IMPORT_PATH =

Additional import path used to resolve QML modules just for Qt Quick Designer

QML_DESIGNER_IMPORT_PATH =

Default rules for deployment.

qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target

DISTFILES += \ android/AndroidManifest.xml \ android/build.gradle \ android/gradle/wrapper/gradle-wrapper.jar \ android/gradle/wrapper/gradle-wrapper.properties \ android/gradlew \ android/gradlew.bat \ android/res/values/libs.xml

android { ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android DEFINES += \ QTAT_ADMOB_BANNER \ QTAT_ADMOB_INTERSTITIAL \ QTAT_ADMOB_REWARDED_VIDEO \ } android: !include( ../../android/QtAndroidTools/QtAndroidTools/QtAndroidTools.pri ) { error( "Couldn't find QtAndroidTools.pri file!" ) }

HEADERS += \ gamemodel.h

FalsinSoft commented 4 years ago

Hi

Sorry, didn't understand very well if you see the problem with both the demo app and your app or the demo app work well and your app not...

zlutor commented 4 years ago

Demo.app looks ok, intrstatial test ad is visible but mine shows black screen only... :(

Is there any setting I missed in my .pro file, manifest file, etc?

If I comment out everything related to QtAndroidTools from attached qml file, it shows up original content properly...

On Tuesday, May 12, 2020, Fabio Falsini wrote:

Hi

Sorry, didn't understand very well if you see the problem with both the demo app and your app or the demo app work well and your app not...

Il giorno mar 12 mag 2020 alle ore 19:20 zlutor notifications@github.com ha scritto:

Hi,

I try to reproduce demo AdMob examples in my application but I get nothing but blank screen (on emulators). It seems if "import QtAndroidTools 1.0" is in my QML file, original page will not be displayed but black screen only...

.pro file and given .qml file attached, permissions are set in manifest:

Thanks for your help in advance.

Zoltan

import QtQuick 2.7 import QtMultimedia 5.8 import QtAndroidTools 1.0

import "levelcompletedresource.js" as Resources import "levelcompleted.js" as LevelCompleteLogic import "../gamelogic.js" as GameLogic import "../gameoptions.js" as GameOptions import "../storymodelogic.js" as StoryModeLogic import "../scaling.js" as Scaling import "../forfictionmobile" import ".."

Item { id: levelCompletedPage / private / property int counter : 0 property int actualStarIndex : 0

focus: true

width: 240 height: 400

// Implements back key navigation // http://doc.qt.io/qt-5/qtquick-input-focus.html Keys.onReleased: { handleBackKey( event ) }

function handleBackKey( event ) { if (event.key === Qt.Key_Back) { event.accepted = true backToPage("selectLevelPage") } }

// QtAndroidAdMobRewardedVideo { // id: rewardedVideo // unitId: "ca-app-pub-3940256099942544/5224354917" // onRewarded: rewardedVideoResult.text = "Type: " + type + " - Amount: "

  • amount // onLoadError: rewardedVideoState.text = "Error " + errorId // onLoading: rewardedVideoState.text = "Loading" // onLoaded: rewardedVideoState.text = "Loaded" // onOpened: rewardedVideoState.text = "Opened" // onClosed: rewardedVideoState.text = "Closed" // onStarted: rewardedVideoState.text = "Started" // onCompleted: rewardedVideoState.text = "Completed" // onLeftApplication: rewardedVideoState.text = "LeftApplication" // }

QtAndroidAdMobInterstitial { id: adMobInterstitial unitId: "ca-app-pub-3940256099942544/1033173712" onLoading: { console.debug("Loading...") } onLoaded: { console.debug("Loaded" ) adMobInterstitial.show() } onLoadError: { console.debug("Error: " + errorId) } onClicked: { GameLogic.addIncome(amount) moneyIndicator.bonusMoney = amount } }

Audio { id: audioPlayer volume: 0.8

onStatusChanged: { if( Audio.Loaded === status && levelCompletedPage.visible ) { play() } }

Component.onCompleted: { if (GameOptions.isSoundOn()) { source = "qrc:/sound/complete.mp3" } } }

onVisibleChanged: { if ( !visible ) { audioPlayer.stop() } }

Rectangle { id: background anchors.fill: parent color: "black" }

Image { id: levelCompletedImage anchors.centerIn: parent source: Resources.getLevelCompletedImageResource() }

Image { id: levelCompletedButtons anchors.horizontalCenter: parent.horizontalCenter anchors.top : levelCompletedImage.bottom anchors.margins: height/5 source: Resources.getLevelCompletedButtonsResource()

ClickOnceArea { id : skipMenuItemArea width: parent.width/4 height: parent.height anchors.left: parent.left

onClicked: { backToPage("selectLevelPage") } }

ClickOnceArea { id : retryMenuItemArea width: parent.width/4 height: parent.height anchors.left: skipMenuItemArea.right

onClicked: { stackView.push( {item: Qt.resolvedUrl("../StoryGamePage.qml") , immediate: true , replace: true}) } }

ClickOnceArea { id : shopMenuItemArea width: parent.width/4 height: parent.height anchors.left: retryMenuItemArea.right

onClicked: { stackView.push(Qt.resolvedUrl("../shopping/ShoppingPage.qml")) } }

ClickOnceArea { id : nextLevelMenuItemArea width: parent.width/4 height: parent.height anchors.left: shopMenuItemArea.right

onClicked: { if (StoryModeLogic.nextLevel()) { backToPage("letsGoPage") stackView.push( {item: Qt.resolvedUrl("../LetsGoPage.qml") , replace: true}) } else { backToPage("selectChapterPage") stackView.push( {item: Qt.resolvedUrl("../SelectChapterPage.qml") , replace: true}) } } }

}

Repeater { id : achievementStars

model : 3 Image { visible: false source : Resources.getLevelCompletedStarImageResource() }

function resize() { for(var i = 0; i < 3; ++i) { var star = achievementStars.itemAt(i) star.width = Resources.getLevelCompletedStarImageWidth() star.height = Resources.getLevelCompletedStarImageHeight() star.x = Resources.getStarOffsetX(i) star.y = Resources.getStarOffsetY() } } }

onActualStarIndexChanged: { if ( 0 <= actualStarIndex ) { var star = achievementStars.itemAt(actualStarIndex) star.visible = true } }

NumberAnimation on actualStarIndex { id: achievementStarsAnimation duration : 1500 from: -1 to : LevelCompleteLogic.getNumberOfStars()-1 }

Text {

property int moneyEarned: 0 property int animatedMoney : 0 property int bonusMoney: 0

id: moneyIndicator height : parent.height/7

verticalAlignment: Text.AlignVCenter color : "white" font.bold: true fontSizeMode : Text.VerticalFit minimumPixelSize: 10 font.pixelSize: 72 font.family: oogieBoogieFont.name style: Text.Raised styleColor: "black" text: "X " + animatedMoney

NumberAnimation on animatedMoney { running: false id: moneyIndicatorAnimation duration: 1500 from: 0 to : moneyIndicator.moneyEarned

onStopped: { bonusIndicator.show() } }

onBonusMoneyChanged: { text = "X " + (moneyEarned+bonusMoney) } }

BonusIndicator { id: bonusIndicator anchors.horizontalCenter: parent.horizontalCenter anchors.bottom: levelCompletedImage.top anchors.margins: height/2

maxBonus: Math.max(50, 10*(Math.round(moneyIndicator.moneyEarned/30)))

onBonusGrabbed: { // GameLogic.addIncome(amount) // moneyIndicator.bonusMoney = amount //adMobInterstitial.show() }

function rescale() { var area = Resources.getBonusArea() width = area.width height = area.height } }

onWidthChanged: { resize() } onHeightChanged: { resize() } Component.onCompleted: { console.debug("onCompleted" ) // rewardedVideo.load() adMobInterstitial.load() resize() achievementStarsAnimation.start() StoryModeLogic.storeNumberOfStarsGot(LevelCompleteLogic.getNumberOfStars())

moneyIndicator.moneyEarned = LevelCompleteLogic.getMoneyGot() GameLogic.addIncome(moneyIndicator.moneyEarned) moneyIndicatorAnimation.start() }

function resize() { if ( 0 < width && 0 < height) { Scaling.storeActualScreenDimensions(width, height)

levelCompletedImage.width = Resources.getLevelCompletedImageWidth() levelCompletedImage.height = Resources.getLevelCompletedImageHeight()

levelCompletedButtons.width = Resources.getLevelCompletedButtonsWidth() levelCompletedButtons.height = Resources.getLevelCompletedButtonsHeight()

moneyIndicator.x = Resources.getMoneyIndicatorOffsetX() moneyIndicator.y = Resources.getMoneyIndicatorOffsetY()

achievementStars.resize() bonusIndicator.rescale() } }

function backToPage(name) { stackView.pop(stackView.find(function(item) { return item.name === name })) } }

QT += quick QT += multimedia QT += svg QT += sql QT += purchasing

CONFIG += c++11

The following define makes your compiler emit warnings if you use

any Qt feature that has been marked deprecated (the exact warnings

depend on your compiler). Refer to the documentation for the

deprecated API to know how to port your code away from it.

DEFINES += QT_DEPRECATED_WARNINGS

You can also make your code fail to compile if it uses deprecated APIs.

In order to do so, uncomment the following line.

You can also select to disable deprecated APIs only up to a certain

version of Qt.

DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs

deprecated before Qt 6.0.0

SOURCES += \ gamemodel.cpp \ main.cpp

RESOURCES += qml.qrc \ sound.qrc \ visuals.qrc

Additional import path used to resolve QML modules in Qt Creator's code

model QML_IMPORT_PATH =

Additional import path used to resolve QML modules just for Qt Quick

Designer QML_DESIGNER_IMPORT_PATH =

Default rules for deployment.

qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target

DISTFILES += \ android/AndroidManifest.xml \ android/build.gradle \ android/gradle/wrapper/gradle-wrapper.jar \ android/gradle/wrapper/gradle-wrapper.properties \ android/gradlew \ android/gradlew.bat \ android/res/values/libs.xml

android { ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android DEFINES += \ QTAT_ADMOB_BANNER \ QTAT_ADMOB_INTERSTITIAL \ QTAT_ADMOB_REWARDED_VIDEO \ } android: !include( ../../android/QtAndroidTools/QtAndroidTools/QtAndroidTools.pri ) { error( "Couldn't find QtAndroidTools.pri file!" ) }

HEADERS += \ gamemodel.h

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/FalsinSoft/QtAndroidTools/issues/13#issuecomment-627480229, or unsubscribe https://github.com/notifications/unsubscribe-auth/AC4FSZNTOHUW37CEVBVUU43RRGAPRANCNFSM4LYXN26Q .

-- You are receiving this because you commented. Reply to this email directly or view it on GitHub: https://github.com/FalsinSoft/QtAndroidTools/issues/13#issuecomment-62752770

FalsinSoft commented 4 years ago

Which log message do you see from the emulator when try to show up the ad but see black screen?

zlutor commented 4 years ago

I do not see any...

I use Blue Stacks...

On Tuesday, May 12, 2020, Fabio Falsini wrote:

Which log message do you see from the emulator when try to show up the ad but see black screen?

-- You are receiving this because you commented. Reply to this email directly or view it on GitHub: https://github.com/FalsinSoft/QtAndroidTools/issues/13#issuecomment-62754699

Allstar12345 commented 4 years ago

Download Android studio and set Qt Creator up to run an Android Virtual Device (AVD), Bluestacks for development purposes will be a nightmare, with an ADV you can see the console and debug the Application. Android Studio can also download the required additional libs the Ads may need.

Also, please create a separate issue for your topic as this one is closed :)

FalsinSoft commented 4 years ago

Without know why the ad is not showed is very difficult to find the problem. You should work with the official andoid emulator for get the full logs of the events accurred...