-1

I am making a library that can be used to incorporate breaking and entering detection into any application

There is an arduino set to the alarm of the house which sends an SMS to a specific phone upon trigger

Within my sdk I register an sms receiver which upon receiving an sms with a specific text, should show a full screen activity (on top of the lockscreen too) that will alert the user

I created an application to test this behaviour

the application's package is : com.example.demo

the library's package is : com.example.sdk

the sms receiver looks like this:

class SMSReceiver : BroadcastReceiver() {
    companion object {
        const val TAG = "SMSReceiver"
    }

    private val logger by lazy { Injections.logger }

    override fun onReceive(context: Context?, intent: Intent?) {
        logger.log(TAG) { "Got sms" }
        val ctx = context ?: return
        val bundle = intent?.extras ?: return
        val format = bundle.getString("format") ?: return
        val pdus = (bundle["pdus"] as? Array<*>) ?: return
        for (idx in pdus.indices) {
            val pdu = pdus[idx] as? ByteArray ?: continue
            val msg = SmsMessage.createFromPdu(pdu, format)
            if (msg.messageBody.startsWith("theft event", true)) {
                logger.log(TAG) { "Got theft event" }
                abortBroadcast()
                showTheftActivity(ctx, msg.messageBody)
                break
            }
        }
    }

    private fun showTheftActivity(context: Context, messageBody: String) {
        val intent = Intent(context, TheftActivity::class.java)
        intent.addFlags(Intent.FLAG_FROM_BACKGROUND)
            .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
//            .addCategory(Intent.CATEGORY_LAUNCHER)

        val location = messageBody.split(" ").getOrNull(2)
        if (location != null) {
            val coords = location.split(",")
            if (coords.size == 2) {
                val x = coords[0].toBigDecimalOrNull()
                val y = coords[1].toBigDecimalOrNull()
                if (x != null && y != null) {
                    intent.putExtra(TheftActivity.X, x.toString())
                    intent.putExtra(TheftActivity.Y, y.toString())
                }
            }
        }
        context.startActivity(intent)
    }
}

the activity that should show on top of everything is this :

class TheftActivity : Activity() {
    companion object {
        const val X = "locationX"
        const val Y = "locationY"
    }

    private val x: String? by lazy { intent.getStringExtra(X) }
    private val y: String? by lazy { intent.getStringExtra(Y) }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_theft)
        val location = findViewById<Button>(R.id.locate)
        if (x != null && y != null) {
            location.setOnClickListener { Toast.makeText(applicationContext, "Going to $x , $y", Toast.LENGTH_SHORT).show() }
            location.isEnabled = true
            finish()
        } else {
            location.isEnabled = false
        }
        findViewById<Button>(R.id.cancel).setOnClickListener {
            finish()
        }
        turnScreenOnAndKeyguardOff()
    }

    private fun turnScreenOnAndKeyguardOff() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
            setShowWhenLocked(true)
            setTurnScreenOn(true)
        } else {
            window.addFlags(
                WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
                        or WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
            )
        }

        with(getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                requestDismissKeyguard(this@TheftActivity, null)
            }
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        turnScreenOffAndKeyguardOn()
    }

    private fun turnScreenOffAndKeyguardOn() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
            setShowWhenLocked(false)
            setTurnScreenOn(false)
        } else {
            window.clearFlags(
                WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
                        or WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
            )
        }
    }
}

and the sdk's android manifest contains this:

   <application>
        <activity
            android:name=".ui.TheftActivity"
            android:configChanges="orientation|keyboardHidden|screenSize"
            android:excludeFromRecents="true"
            android:label="@string/title_activity_theft"
            android:showOnLockScreen="true"
            android:theme="@style/Theme.Sdk.Fullscreen" />

        <receiver
            android:name=".receivers.SMSReceiver"
            android:enabled="true"
            android:exported="true"
            android:permission="android.permission.BROADCAST_SMS">
            <intent-filter>
                <action android:name="android.provider.Telephony.SMS_RECEIVED" />
            </intent-filter>
        </receiver>
    </application>

when testing this on an emulator I send the sms to trigger the theft event

if the activity for testing (the one in the com.example.demo package) is not closed then it is brought to the front , but if it is closed nothing happens (though I do see the log messages from the receiver)

how can I make my sms receiver open the TheftActivity instead of the main activity from the main package?

edit: if it helps, the theft activity seems to start and then get immediately destroyed

Cruces
  • 3,029
  • 1
  • 26
  • 55

1 Answers1

1

It looks like the system can't bring the activity to the foreground due to the restrictions implemented in Android Q

With Android Q, it is impossible to start an activity from the background automatically if your app does not include those exceptions listed in the link below.

https://developer.android.com/guide/components/activities/background-starts

For possible solutions :

https://stackoverflow.com/a/59421118/11982611

Eren Tüfekçi
  • 2,463
  • 3
  • 16
  • 35
  • I am running it on an emulator targeting api version 23, I added the permission mentioned but it doesn't seem to make a difference, the behaviour is the same – Cruces Feb 07 '21 at 11:20
  • Did you also grant the permission programmatically beside adding it to the manifest ? – Eren Tüfekçi Feb 07 '21 at 11:45
  • no, but after I added it and gotten the permission the behaviour was still the same, theft activity starts and gets immediately destroyed – Cruces Feb 07 '21 at 12:03
  • I'm sorry for wasting your time, it was a stupid coding mistake, I marked your answer as the correct one because it did help me when I tested it on api Q + – Cruces Feb 07 '21 at 13:16