Wear OS und WakeLock-Problem

N

no1Ltan

Fortgeschrittenes Mitglied
7
Android Studio 2023.3.1
compileSdk = 34
Windows 10 Pro 64 Bit
TicWatch Pro 3

Hallo zusammen,

ich versuche seit über 1 Woche einen WakeLock in meine WearOS-App einzubinden.
Aktuell habe ich nur die Standard-App, die mit Android Studio kommt.
(Schwarzer Hintergrund mit TextView und Uhr-Anzeige.)

Das Problem ist, dass nach rund 30 Sekunden Inaktivität die App nicht mehr im Vordergrund ist,
wenn ich die Uhr reaktiviere.
Nutze ich hingegen einen Full WakeLock, ist die App dauerhaft im Vordergrund, aber der Bildschirm geht nicht aus.

Mein Ziel ist es, dass der Bildschirm der Uhr ausgehen kann und die App beim Reaktivieren wieder im Vordergrund ist,
selbst wenn sie 5 Minuten inaktiv war.

Bin für jede Hilfe dankbar.


Code:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

    <uses-feature android:name="android.hardware.type.watch" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@android:style/Theme.DeviceDefault">

        <service
            android:name=".tile.MainTileService"
            android:exported="true"
            android:label="@string/tile_label"
            android:permission="com.google.android.wearable.permission.BIND_TILE_PROVIDER">
            <intent-filter>
                <action android:name="androidx.wear.tiles.action.BIND_TILE_PROVIDER" />
            </intent-filter>

            <meta-data
                android:name="androidx.wear.tiles.PREVIEW"
                android:resource="@drawable/tile_preview" />
        </service>
        <uses-library
            android:name="com.google.android.wearable"
            android:required="false" />

        <meta-data
            android:name="com.google.android.wearable.standalone"
            android:value="true" />

        <activity
            android:name=".presentation.MainActivity"
            android:exported="true"
            android:taskAffinity=""
            android:theme="@style/MainActivityTheme.Starting">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

-----------------------------------------------------------------------------

Java:
package com.example.testapp.presentation

import android.content.Context
import android.os.Bundle
import android.os.PowerManager
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Devices
import androidx.compose.ui.tooling.preview.Preview
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.wear.compose.material.MaterialTheme
import androidx.wear.compose.material.Text
import androidx.wear.compose.material.TimeText
import com.example.testapp.R
import com.example.testapp.presentation.theme.TestAppTheme

class MainActivity : ComponentActivity() {

    private var mWakeLock: PowerManager.WakeLock? = null
    private val TAG = "MyApp::WakeLockTag"

    override fun onCreate(savedInstanceState: Bundle?) {
        installSplashScreen()
        super.onCreate(savedInstanceState)

        setTheme(android.R.style.Theme_DeviceDefault)

        val pm    = getSystemService(Context.POWER_SERVICE) as PowerManager
        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG)
        mWakeLock?.acquire(10*60*1000L /*10 minutes*/)

        setContent {
            WearApp("Android")
        }
    }

    override fun onDestroy() {
        mWakeLock?.let {
            if (it.isHeld) {
                it.release()
            }
        }
        super.onDestroy()
    }
}

@Composable
fun WearApp(greetingName: String) {
    TestAppTheme {
        Box(
            modifier = Modifier
                .fillMaxSize()
                .background(MaterialTheme.colors.background),
            contentAlignment = Alignment.Center
        ) {
            TimeText()
            Greeting(greetingName = greetingName)
        }
    }
}

@Composable
fun Greeting(greetingName: String) {
    Text(
        modifier = Modifier.fillMaxWidth(),
        textAlign = TextAlign.Center,
        color = MaterialTheme.colors.primary,
        text = stringResource(R.string.hello_world, greetingName)
    )
}

@Preview(device = Devices.WEAR_OS_SMALL_ROUND, showSystemUi = true)
@Composable
fun DefaultPreview() {
    WearApp("Preview Android")
}
 
Ich verstehe leider nicht ganz , was du vorhast

Das Problem ist, dass nach rund 30 Sekunden Inaktivität die App nicht mehr im Vordergrund ist,
wenn ich die Uhr reaktiviere.
Welche App von beiden ?

Nutze ich hingegen einen Full WakeLock, ist die App dauerhaft im Vordergrund, aber der Bildschirm geht nicht aus.
Auch hier : Welche App von Beiden ?

Mein Ziel ist es, dass der Bildschirm der Uhr ausgehen kann und die App beim Reaktivieren wieder im Vordergrund ist,
selbst wenn sie 5 Minuten inaktiv war.
??
Wie Reaktivieren ?
Wenn du von der Device-Activity sprichst, so ist es mir unbekannt , dass eine App nur durch ein WakeLock in den Vordergrund kommt und Launched
I.d.R. dient ein WakeLock dazu , das Device z.b. aus dem DOZE aufzuwecken , nicht eine App in den Vordergrund zu schickem

Erkläre bitte einmal detailliert , was genau der Ablauf sein soll - So macht das leider keinen Sinn
 
Zuletzt bearbeitet:
Hi und danke für deine Antwort.

Es geht hier um eine App, nicht um Zwei :)
Mit Reaktivieren meine ich lediglich "Uhr aus dem StandBy-Modus zurückholen".
Dies ist entweder per Touch, Buttonklick oder durch Neigung nach oben möglich.

Wenn meine App aktiv (und im Vordergrund) ist und ich mit der Uhr nicht mehr interagiere, geht der Bildschirm nach wenigen Sekunden aus.
Reaktiviere ich die Uhr innerhalb von 30 Sekunden, geht der Bildschirm an und die App ist
weiterhin im Vordergrund - alles korrekt soweit.

Ist die Uhr aber länger als 30 Sekunden inaktiv, dann ist die App nach reaktivieren
der Uhr nicht mehr im Vordergrund.
Stattdessen sehe ich lediglich das Watchface.

Bei vielen anderen Apps ist das nicht so - da kann ich die Uhr selbst nach einem halben Tag aus dem StandBy-Modus zurückholen -> App ist weiterhin im Vordergrund.

Anders formuliert:
Meine App soll nicht in den Vordergrund geschickt werden, sondern es soll verhindert werden, dass sie nach mehr als 30 Sekunden Inaktivität in den Hintergrund versetzt wird.

Viele Grüße
 
Okeee, kommt schon besser rüber :)


Nutze ich hingegen einen Full WakeLock, ist die App dauerhaft im Vordergrund, aber der Bildschirm geht nicht aus.
Vorschlag 1)
Hier auf alle Fälle den WakeLOck mit einer Zeit acquiren, ansonsten ist es logisch , dass das Ding immer oben bleibt.
(Natürlich hier FULL_WAKE_LOCK anwenden )

Code:
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, "no1Ltan::WakeLockTag");

privat void acquireWL() {
        if (mWakeLock != null && !mWakeLock.isHeld()) {
            mWakeLock.acquire(6000L /* =  1 Minute*/);
        }
    }

   private void releaseWL() {
        if (mWakeLock != null && mWakeLock.isHeld()) {
            mWakeLock.release();
        }
    }


Vorschlag 2)
Ich persönlich würde mal ganz ohne WakeLock arbeiten und mit einem BroadcastReceiver, der ACTION_SCREEN_OFF/ON nimmt und ein Intent auf die Activity auslost (Intent.FLAG_ACTIVITY_NEW_TASK);

Dabei peinlichst auf das unregister achten .
 
Zuletzt bearbeitet:
Hi und Danke nochmals für deine Unterstützung.

Ich habe viel rumprobiert und gute Fortschritte gemacht.
Die Sache mit dem Full_Wakelock hat sich als nicht zielführend erwiesen.
Anders hingegen der BroadcastReceiver -> damit funktioniert es fast perfekt.

Es nun so, dass der BroadCastReceiver bei "Screen_On" prüft,
ob die Activity bereits läuft bzw im Vordergrund ist.
Ist dem so, passiert nichts, was auch korrekt ist.

Wenn die Uhr mehr als 30 Sekunden inaktiv war und daher in den Schlafmodus ging,
dann setzt der BroadcastReceiver die Activity in den Vordergrund, wenn man die Uhr aus dem Ruhemodus holt.

Einziges kleines Manko: Man sieht das Watchface für ca. 0,5 bis 1 Sekunde,
bevor die App wieder wieder in den Vordergrund geschoben wird (bei Inaktivität > 30 Sek).

Es wäre super, wenn die App sofort im Vordergrund wäre und nicht nach einer kurzen Verzögerung.
Vielleicht gibt es noch eine andere Möglichkeit, dies zu implementieren?

Anbei die aktuellen Codes:

Java:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

    <uses-feature android:name="android.hardware.type.watch" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.REORDER_TASKS"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@android:style/Theme.DeviceDefault">

        <uses-library
            android:name="com.google.android.wearable"
            android:required="false" />

        <meta-data
            android:name="com.google.android.wearable.standalone"
            android:value="true" />

        <activity
            android:name=".presentation.MainActivity"
            android:exported="true"
            android:taskAffinity=""
            android:theme="@style/MainActivityTheme.Starting">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <receiver android:name=".presentation.ScreenReceiver"
            android:exported="true">
            <intent-filter android:priority="1000">
                <action android:name="android.intent.action.SCREEN_ON" />
            </intent-filter>
        </receiver>
    </application>

</manifest>

Java:
package com.example.testapp.presentation

import android.app.Activity
import android.content.Intent
import android.content.IntentFilter
import android.os.Bundle
import android.widget.TextView
import com.example.testapp.R

class MainActivity : Activity() {
    private val screenReceiver = ScreenReceiver()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setTheme(android.R.style.Theme_DeviceDefault)
        setContentView(R.layout.activity_main)

        val filter = IntentFilter(Intent.ACTION_SCREEN_ON)
        registerReceiver(screenReceiver, filter)

        val textView: TextView = findViewById(R.id.textView)
        textView.text = getString(R.string.hello_world, "Android")
    }

    override fun onDestroy() {
        super.onDestroy()
        unregisterReceiver(screenReceiver)
    }
}

Java:
package com.example.testapp.presentation

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent

class ScreenReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        if (intent?.action == Intent.ACTION_SCREEN_ON) {
            if (!isAppInForeground(context)) {
                val activityIntent = Intent(context, MainActivity::class.java).apply {
                    addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_RECEIVER_FOREGROUND)
                }
                context?.startActivity(activityIntent)
            }
        }
    }
    private fun isAppInForeground(context: Context?): Boolean {
        val activityManager = context?.getSystemService(Context.ACTIVITY_SERVICE) as? android.app.ActivityManager
        val runningAppProcesses = activityManager?.runningAppProcesses ?: return false
        for (processInfo in runningAppProcesses) {
            if (processInfo.importance == android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
                for (activeProcess in processInfo.pkgList) {
                    if (activeProcess == context.packageName) {
                        return true
                    }
                }
            }
        }
        return false
    }
}


Viele Grüße
 
Es wäre super, wenn die App sofort im Vordergrund wäre und nicht nach einer kurzen Verzögerung.
Vielleicht gibt es noch eine andere Möglichkeit, dies zu implementieren?
An dem Punkt muss ich leider passen, da ich bis jetzt nur 2 WearOS Apps auf dem Markt habe , die allerdings dein Szenario nicht benötigen.
 

Ähnliche Themen

D
Antworten
3
Aufrufe
92
daveCrhis
D
M
  • MikelKatzengreis
Antworten
5
Aufrufe
306
swa00
swa00
koje71
Antworten
0
Aufrufe
87
koje71
koje71
Zurück
Oben Unten