Android - how to receive broadcast intents ACTION_SCREEN_ON/OFF?
Asked Answered
P

6

68
    <application>
         <receiver android:name=".MyBroadcastReceiver" android:enabled="true">
                <intent-filter>
                      <action android:name="android.intent.action.ACTION_SCREEN_ON"></action>
                      <action android:name="android.intent.action.ACTION_SCREEN_OFF"></action>
                </intent-filter>
         </receiver>
...
    </application>

MyBroadcastReceiver is set just to spit foo to the logs. Does nothing. Any suggestions please? Do I need to assign any permissions to catch the intent?

Philcox answered 19/10, 2009 at 11:1 Comment(0)
L
71

I believe that those actions can only be received by receivers registered in Java code (via registerReceiver()) rather than through receivers registered in the manifest.

Lecturer answered 19/10, 2009 at 11:55 Comment(7)
OK, I just figured that. What's the rationale behind this?Philcox
Android does not seem to support manifest-registered receivers for cases where they really do not want to start up a new process. For example, you will see the same effect with the battery info actions (e.g., BATTERY_LOW). Beyond that, though, I don't have much rationale -- I didn't write it. :-)Lecturer
@Lecturer So how can i registerReceiver() when Power button is pressed?Distrain
@Lecturer Is there a list somewhere of these type of intents that can not be received from manifest, I am kinda facing same problem with CONNECTIVITY_ACTION and PHONE_STATE also.Untoward
@dirtydexter: No, there is no such list, and those two broadcasts should be able to be picked up from either the manifest or receivers registered via registerReceiver(), AFAIK.Lecturer
So then, how do we know which ones need to be registered programatically?Graf
@PrimožKralj: Well, on Android 8.0+, most have to be registered programmatically -- the exceptions are on a whitelist. For prior versions of Android, in general, you try it. If it does not work when registered in the manifest, confirm your results by researching the broadcast action in Stack Overflow and similar resources. Ideally, this would have better documentation.Lecturer
H
32

Alternatively you can use the power manager to detect screen locking.

@Override
protected void onPause()
{
    super.onPause();

    // If the screen is off then the device has been locked
    PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
    boolean isScreenOn;
    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
        isScreenOn = powerManager.isInteractive();
    } else {
        isScreenOn = powerManager.isScreenOn();
    }

    if (!isScreenOn) {

        // The screen has been locked 
        // do stuff...
    }
}
Hepato answered 7/9, 2011 at 9:55 Comment(4)
+1 for approach with PowerManager Very nice touch if somebody don't want to use BroadcastReceiverSeymour
just wanted to add that although this will work nicely for 99% of cases out there, this can actually fail in specific circumstances. In devices that can turn the screen on and off very fast, such as Galaxy S4, you can check this behavior failing by combining it with a proximityLock. If you trigger the lock to turn the screen off and back on quickly, isScreenOn will actually return true in onPause().Cirilo
@iCode4Food What you described is right,but how to solve it?Ranna
@SimonDorociak where can I add this in a service? (for a service)Amaranthaceous
S
30
"android.intent.action.HEADSET_PLUG"
"android.intent.action.ACTION_SCREEN_ON"
"android.intent.action.ACTION_SCREEN_OFF"

Three of them above, They cannot register using Manifest. Android core added "Intent.FLAG_RECEIVER_REGISTERED_ONLY" to them (maybe.. I checked codes only in case of "HEADSET_PLUG".

So, We should use "dynamic register". Like below...

private BroadcastReceiver mPowerKeyReceiver = null;

private void registBroadcastReceiver() {
    final IntentFilter theFilter = new IntentFilter();
    /** System Defined Broadcast */
    theFilter.addAction(Intent.ACTION_SCREEN_ON);
    theFilter.addAction(Intent.ACTION_SCREEN_OFF);

    mPowerKeyReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String strAction = intent.getAction();

            if (strAction.equals(Intent.ACTION_SCREEN_OFF) || strAction.equals(Intent.ACTION_SCREEN_ON)) {
                // > Your playground~!
            }
        }
    };

    getApplicationContext().registerReceiver(mPowerKeyReceiver, theFilter);
}

private void unregisterReceiver() {
    int apiLevel = Build.VERSION.SDK_INT;

    if (apiLevel >= 7) {
        try {
            getApplicationContext().unregisterReceiver(mPowerKeyReceiver);
        }
        catch (IllegalArgumentException e) {
            mPowerKeyReceiver = null;
        }
    }
    else {
        getApplicationContext().unregisterReceiver(mPowerKeyReceiver);
        mPowerKeyReceiver = null;
    }
}
Softball answered 22/4, 2013 at 7:34 Comment(2)
+1, nice. Only thing to note is Build.VERSION.SDK is not deprecated.Refresh
The unregisterReceiver() code portion was really useful to me. Thanx @cmcromance !! +1Fic
B
7

The way I implemented this is by registering the receiver in my main activity in onCreate(), just define the receiver somewhere beforehand:

    lockScreenReceiver = new LockScreenReceiver();
    IntentFilter lockFilter = new IntentFilter();
    lockFilter.addAction(Intent.ACTION_SCREEN_ON);
    lockFilter.addAction(Intent.ACTION_SCREEN_OFF);
    lockFilter.addAction(Intent.ACTION_USER_PRESENT);
    registerReceiver(lockScreenReceiver, lockFilter);

And then onDestroy():

    unregisterReceiver(lockScreenReceiver);

In receiver you must catch the following cases:

public class LockScreenReceiver extends BroadcastReceiver
{
    @Override
    public void onReceive(Context context, Intent intent)
    {
        if (intent != null && intent.getAction() != null)
        {
            if (intent.getAction().equals(Intent.ACTION_SCREEN_ON))
            {
                // Screen is on but not unlocked (if any locking mechanism present)
            }
            else if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF))
            {
                // Screen is locked
            }
            else if (intent.getAction().equals(Intent.ACTION_USER_PRESENT))
            {
                // Screen is unlocked
            }
        }
    }
}
Bicycle answered 13/7, 2016 at 8:25 Comment(0)
O
0

Here is the kotlin version of @cmcromance (Thanks for your answer. Please don't forget to upvote the original answer)

private var mPowerKeyReceiver: BroadcastReceiver? = null

    private fun registBroadcastReceiver() {
        val theFilter = IntentFilter()
        /** System Defined Broadcast  */
        theFilter.addAction(Intent.ACTION_SCREEN_ON)
        theFilter.addAction(Intent.ACTION_SCREEN_OFF)

        mPowerKeyReceiver = object : BroadcastReceiver() {
            override fun onReceive(context: Context?, intent: Intent?) {

                Log.e("onReceive", "onReceive called")
                val strAction = intent!!.action

//                if (strAction == Intent.ACTION_SCREEN_OFF || strAction == Intent.ACTION_SCREEN_ON) {
                if (strAction == Intent.ACTION_SCREEN_ON) {
                    // > Your playground~!
                    Log.e("strAction", strAction)
                    val intent = Intent(context, SplashScreenMainAppActivity::class.java)
                    startActivity(intent)
                }

            }
        }

        applicationContext.registerReceiver(mPowerKeyReceiver, theFilter)
    }

    private fun unregisterReceiver() {
        val apiLevel = Build.VERSION.SDK_INT

        if (apiLevel >= 7) {
            try {
                applicationContext.unregisterReceiver(mPowerKeyReceiver)
            } catch (e: IllegalArgumentException) {
                mPowerKeyReceiver = null
            }

        } else {
            applicationContext.unregisterReceiver(mPowerKeyReceiver)
            mPowerKeyReceiver = null
        }
    }
Outermost answered 28/11, 2019 at 6:37 Comment(0)
G
0

New action key updated!

<intent-filter>
    <action android:name="android.intent.action.SCREEN_ON" />
    <action android:name="android.intent.action.SCREEN_OFF" />
</intent-filter>
Gal answered 3/5, 2023 at 7:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.