When registering a BroadcastReceiver with the IntentFilter Intent.ACTION_CLOSE_SYSTEM_DIALOGS, the homekey pressed event is received twice, however the other events like recentapps is received only once. I'm not registering any receivers in the AndroidManifest.xml file.
Following is the code snippet I'm trying to use:
MainActivity.kt
private const val HOME_KEY = "homekey"
private const val RECENT_APPS = "recentapps"
private const val REASON = "reason"
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
findViewById<Button>(R.id.press_me).setOnClickListener {
registerReceiver(
navigationEventReceiver,
IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)
)
}
}
private val navigationEventReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
if (intent?.action != Intent.ACTION_CLOSE_SYSTEM_DIALOGS) return
val pressedKey = intent.getStringExtra(REASON)
if (pressedKey == HOME_KEY) {
Log.d("Event ", "home key")
}
if (pressedKey == RECENT_APPS) {
Log.d("Event ", "recent apps")
}
}
}
}
The logs that get printed in the logcat after this are as follows:
When pressing home button
D/Event: home key
D/Event: home key
When pressing recent apps button
D/Event: recent apps
Related
How do you detect a user pressing the call button on a connected Bluetooth Headset?
While multiple posts address the topic I think I have tried most (if not all) and still have not found a solution which works
The following simplified code connects to the Bluetooth headset in onResume()
It then logs a message if ANY intent is received (which it never does)
class MainActivity : AppCompatActivity() {
private lateinit var audioManager : AudioManager
private var headsetDevice: AudioDeviceInfo? = null // device used for audio input
private lateinit var mediaSession: MediaSession
private lateinit var headsetButtonIntentReceiver: HeadsetButtonIntentReceiver
private lateinit var headsetButtonIntentFilter: IntentFilter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager
mediaSession = MediaSession(this, packageName)
headsetButtonIntentFilter = IntentFilter(Intent.ACTION_CALL_BUTTON)
headsetButtonIntentReceiver = HeadsetButtonIntentReceiver()
}
class HeadsetButtonIntentReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent) {
Log.d(TAG, "HeadsetButtonIntentReceiver() !!!!")
abortBroadcast()
}
}
override fun onResume() {
super.onResume()
val devices = audioManager.availableCommunicationDevices
Log.d(TAG, "audioManager.availableCommunicationDevices found ${devices.size} devices")
headsetDevice = devices.firstOrNull { it.type == AudioDeviceInfo.TYPE_BLUETOOTH_SCO }
if (headsetDevice != null) {
Log.d(TAG, "setCommunicationsDevice ${headsetDevice!!.productName}")
if (!audioManager.setCommunicationDevice(headsetDevice!!)) Log.d(TAG, "Failed to connect to headset")
}
mediaSession.isActive = true
this.registerReceiver(headsetButtonIntentReceiver, headsetButtonIntentFilter)
}
override fun onStop() {
super.onStop()
if (headsetDevice != null)
audioManager.clearCommunicationDevice() // disconnect from the headset
mediaSession.release()
mediaSession.isActive = false
this.unregisterReceiver(headsetButtonIntentReceiver)
}
companion object {
const val TAG = "MediaButton"
}
}
I have tried adding different Button actions to the intent filter - also without success
headsetButtonIntentFilter = IntentFilter()
headsetButtonIntentFilter.addAction(Intent.ACTION_MEDIA_BUTTON)
headsetButtonIntentFilter.addAction(Intent.ACTION_CALL_BUTTON)
I have tried adding the intent into the Manifest (although several posts suggest this is not required)
<intent-filter>
<action android:name="android.intent.action.CALL_BUTTON" />
</intent-filter>
I have tried specifying the receiver in the Manifest - but also nothing
<receiver android:name=".MainActivity$HeadsetButtonIntentReceiver" android:exported="false">
<intent-filter>
<action android:name="android.intent.action.CALL_BUTTON"/>
</intent-filter>
</receiver>
For completeness I even tried overriding the onKeyDown() and dispatchKeyEvent() but these are also not being triggered
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
Log.d(TAG, "onKeyDown() KEYCODE $keyCode Event ${event?.action}")
return super.onKeyDown(keyCode, event)
}
override fun dispatchKeyEvent(event: KeyEvent?): Boolean {
Log.d(TAG, "dispatchKeyEvent() KEYCODE ${event?.keyCode} Event ${event?.action}")
return super.dispatchKeyEvent(event)
}
Frustratingly there are indications the code is close to working. Specifically a double press of the headset call button dials the previous number but when the above code is running that no longer occurs indicating the App is consuming the call button press. Unfortunately the App is not being notified of this action!
Happy to try solutions posted in previous questions I may have missed!
I have a started service app. It intent to activity from another app, but still running in foreground. After a button click in that activity, I want to send data (for example a string "potato") to service without startService() in order to continue, not restart. That's how service keeps running till get the data, while(requiredData != "potato"){}.start. How can I send it, or return response ? I think to use Messenger or Broadcast, but I'm not sure it fits well and how to do.
Note: Service App connected to an activity from another app.
Service App
class RegistryService : Service() {
override fun onBind(p0: Intent?): IBinder? = null
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val i = packageManager.getLaunchIntentForPackage("com.myexample.potatoactivity")
if (i!=null) {
i.flags = Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(i)
} else {
Toast.makeText(this,"Fail",Toast.LENGTH_SHORT).show()
}
while (true) { // requiredData != "potato"
//Log.d("MyService", "Wait for potato")
}
return START_STICKY
}
}
Potato Activity
class PotatoActivity : AppCompatActivity() {
private lateinit var binding: ActivityPotatoBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityPotatoBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
binding.buttonSendData.setOnClickListener {
//it.putExtra("REQUIRED_DATA", "potato")
}
}
}
I am trying out the new Activity Results API by trying to return a parcelable dataesque class from a child activity. Using Alpha4 of the library.
I have setup the Intent with a custom contract 'AddAttendeeContract' as per my understanding of the docs. It compiles and runs and as far as I can see the correct methods are being called but the data is just null.
What might I be missing?
class MainActivity : AppCompatActivity() {
...
override fun onCreate(savedInstanceState: Bundle?) {
... //boilerplate setup nonsense
fab.setOnClickListener {
addAttendee()
}
}
private val addAttendee = registerForActivityResult(AddAttendeeContract()) { attendee: AttendeeData? ->
println("Attendee") // this does not print out
println(attendee) // this does not either
}
}
And the contract
class AddAttendeeContract : ActivityResultContract<Void?, AttendeeData?>() {
override fun createIntent(
context: Context,
input: Void?
): Intent =
Intent(context, AddAttendeeActivity::class.java)
override fun parseResult(
resultCode: Int,
intent: Intent?
): AttendeeData? = when {
resultCode != Activity.RESULT_OK -> null
else -> intent?.getParcelableExtra<AttendeeData>("attendee")
}
}
Finally is the invocation in the child activity class.
class AddAttendeeActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
... //boilerplate
add.setOnClickListener { //button on a form
val name: String = view.name.text.toString().trim()
val rate: Double = view.rate.text.toString().trim().toDouble()
val number: Int = view.number.text.toString().trim().toInt()
val intent = Intent(this, MainActivity::class.java).apply {
putExtra("attendee", AttendeeData(name=name, rate=rate, number=number))
}
setResult(Activity.RESULT_OK, intent)
startActivity(intent)
}
}
}
Any insights as to what is going on?
This is solved. The problem was that the second activity was startign a new intent, rather than finishing and returning to the old one.
In the second/child activity had to change the line:
startActivity(intent)
to
finish() and things all worked as expected.
How to save string message from BroadcastReceiver and use saved variable in Activity? I'm finding only Toast.makeText examples.
What i'm actually have: working, registered BroadcastReceiver. My app running in DocumentActivity, when i'm hitting Scan button on my DataCollectionTerminal (DTC on Android 7.0), DTC takes message and toast it. I can catch messages from DTC in opened EditText and save it onClick save button.
But what i'm need: Scan button pressed => DTC takes barcode message => send to Activity and save it to some variable => and i can use this var.value in whole Activity, set it TextView, write it to the txt document and etc.
DocumentActivity
class DocumentActivity : AppCompatActivity() {
private val customBroadcastReceiver = CustomBroadcastReceiver()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(exp..R.layout.activity_document)
}
override fun onResume() {
super.onResume()
registerReceiver(
customBroadcastReceiver,
IntentFilter ("com.xcheng.scanner.action.BARCODE_DECODING_BROADCAST")
)
}
override fun onStop() {
super.onStop()
unregisterReceiver(customBroadcastReceiver)
}
fun saveMessage(mes: String){
var code = mes
Toast.makeText(applicationContext, code, Toast.LENGTH_SHORT).show()
...
}}
BroadcastReceiver
class CustomBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val type = intent.getStringExtra("EXTRA_BARCODE_DECODING_SYMBOLE")
val barcode = intent.getStringExtra("EXTRA_BARCODE_DECODING_DATA")
val sb = StringBuilder()
sb.append("Type: $type, Barcode:$barcode\n")
Toast.makeText(context, sb.toString(), Toast.LENGTH_SHORT).show()
// Save mes, doesnt work
DocumentActivity().saveCell(barcode)
}}
You are creating another object of DocumentActivity and saving the value in variable for that object, so it will not reflect in cuurent object. Try to make variable static and then update it from broadcasteceiver. For eg variable in DocumentActivity is barCodeVal so,
in DocumentActivity
companion object{
var barcodeVal = //some default value
}
Then from broabcastreceiver
DocumentActivity.barcodeVal = barcode
Im working on an android app which uses notifications frequently.
I chose to set the alarms via setting activity rather then Main Activity but I couldn't manage to find out how to cancel the Alarm Manager via the settingActivity immediately after pressing the switch.
I only found out how to cancel the notifications on the MainActivity, which stops them only after closing and opening the app.
what is the preferred way to do it?
from SettingActivity.kt:
class NotificationPreferenceFragment : PreferenceFragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
addPreferencesFromResource(R.xml.pref_notification)
setHasOptionsMenu(false)
var switchPref: Preference = findPreference(getString(R.string.pref_notifications_switch_key))
switchPref.onPreferenceChangeListener = OnPreferenceChangeListener { preference, isChecked ->
var toast: Toast = if (isChecked as Boolean) {
Toast.makeText(activity, "switch is ON", Toast.LENGTH_SHORT)
} else {
Toast.makeText(activity, "notifications is OFF", Toast.LENGTH_SHORT)
}
toast.show()
true
}
}
cancel method from MainActivity:
fun cancelAlarm() {
alarmMgr = applicationContext.getSystemService(Context.ALARM_SERVICE) as AlarmManager
val intent1 = Intent(applicationContext, AlarmReceiver::class.java)
alarmIntent = PendingIntent.getBroadcast(applicationContext, 0, intent1, PendingIntent.FLAG_UPDATE_CURRENT)
alarmMgr!!.cancel(alarmIntent)
}
As said by a commenter, just use BroadcastReceiver
NotificationPreferenceFragment.java
class NotificationPreferenceFragment : PreferenceFragment() {
val broadcaster: LocalBroadcastManager? = null;
override fun onCreate(savedInstanceState: Bundle?) {
broadcaster = LocalBroadcastManager.getInstance(this);
}
// Inside your onPreferenceChangeListener, depends on when you want to call it, either ON or OFF
Intent intent = new Intent("YOUR_DATA_STRING");
intent.putExtra(ANY_EXTRAS_STRING, DATA_ITSELF);
broadcaster.sendBroadcast(intent);
}
MainActivity.java
import android.support.v4.content.LocalBroadcastManager;
override fun onStart() {
super.onStart()
LocalBroadcastManager.getInstance(this).registerReceiver(MYReceiver,
IntentFilter("YOUR_DATA_STRING")
)
}
private val MYReceiver = object : BroadcastReceiver() {
fun onReceive(context: Context, intent: Intent) {
if (intent.extras != null) {
// get any extras if neccessary
// intent.extras!!.getString("ANY_EXTRAS_STRING")
cancelAlarm()
}
}
}
override fun onStop() {
super.onStop()
LocalBroadcastManager.getInstance(this).unregisterReceiver(MYReceiver)
}