How to Add Window -- Token Android.Os.Binderproxy Is Not Valid; Is Your Activity Running

Unable to add window -- token android.os.BinderProxy is not valid; is your activity running?

This can occur when you are showing the dialog for a context that no longer exists. A common case - if the 'show dialog' operation is after an asynchronous operation, and during that operation the original activity (that is to be the parent of your dialog) is destroyed. For a good description, see this blog post and comments:

http://dimitar.me/android-displaying-dialogs-from-background-threads/

From the stack trace above, it appears that the facebook library spins off the auth operation asynchronously, and you have a Handler - Callback mechanism (onComplete called on a listener) that could easily create this scenario.

When I've seen this reported in my app, its pretty rare and matches the experience in the blog post. Something went wrong for the activity/it was destroyed during the work of the the AsyncTask. I don't know how your modification could result in this every time, but perhaps you are referencing an Activity as the context for the dialog that is always destroyed by the time your code executes?

Also, while I'm not sure if this is the best way to tell if your activity is running, see this answer for one method of doing so:

Check whether activity is active

Unable to add window -- token null is not valid; is your activity running error. How can I solve it?

You're trying to show the popup too early. The view on OnCreate is still not created so try to move the popup() to OnViewCreated()

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
popup()
}

or use View.post so it goes into the main thread queue and gets executed after the other pending tasks are finished

override fun onCreate(savedInstanceState: Bundle?) {
...
binding.root.post {
popup()
}
}

Android 'BadTokenException window token android.os.BinderProxy@4250d6d8 is not valid' with foreground service running

Observations

    notification = notificationBuilder!!.setOngoing(true)
.setOnlyAlertOnce(true)
.setContentText(textToShowInNotification)
.setContentIntent(contentIntent)
.build()
notificationManager!!.notify(NOTIFICATION_ID, notification)

Clicking on this notification may not start an Activity because notification is missing setSmallIcon or similar setIcon call. To fix it, set some icon as below:

     notification = notificationBuilder!!.setOngoing(true)
.setOnlyAlertOnce(true)
.setContentText(textToShowInNotification)
.setContentIntent(contentIntent)
.setSmallIcon(R.drawable.ic_launcher_background)
.build()
notificationManager!!.notify(NOTIFICATION_ID, notification)

previous activity is not destroyed

That's doubtful because you're using flags Intent.FLAG_ACTIVITY_NEW_TASK|FLAG_ACTIVITY_CLEAR_TASK when starting an Activity,and that will finish all previous Activities. Otherwise, please show the relevant code.

When the connection with device is established and data is listened
from service at that time when I kill the app and open it from
foreground service notification, the dialog which has to show up
saying that my device is still connected and data is being received is
not shown

This sounds quite confusing. It sounds like you're showing it from your Activity, but then it's unlikely to fail, especially, if you show it from onCreate of your Activity:

override fun onCreate(savedInstanceState: Bundle?) {
...
showAlertDialog()
}

D/DialogExecption: Unable to add window -- token null is not valid; is
your activity running? D/DialogExecption: Unable to add window token
android.os.BinderProxy@4250d6d8 is not valid; is your activity
running?

The error message is quite clear - you're trying to show a dialog based on an invalid Context here AlertDialog.Builder(<context>). For instance, if you use applicationContext or a Service context there, it will fail with such exception.

You claim to start your dialog with an Activity context as below:

...
val dialogAlertDialog = AlertDialog.Builder(<Activity Context>)
...

However, it's not clear from your code from where showAlertDialog() is called, and the context object is not shown either. So, I created a sample project to test the described behaviour.

Suggestion

Preparation

I tried reproducing the issue by building a minimalistic project based on the information that you provided in your question. Please note that I'm not using any BLE functionality for this example, even though Bluetooth is used as a prefix for each component.

I created a foreground service BluetoothDeviceService responsible for starting an Activity, when a notification is clicked.

BluetoothDeviceService.kt

class BluetoothDeviceService: Service() {
private val SERVICE_NOTIFICATION_ID = 123
private val SERVICE_NOTIFICATION_CHANNEL_ID = "channel_01"

override fun onCreate() {
super.onCreate()

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
SERVICE_NOTIFICATION_CHANNEL_ID,
"Bluetooth service",
NotificationManager.IMPORTANCE_DEFAULT)
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(channel)

val pendingIntent = Intent()
pendingIntent.setClass(this,BluetoothDeviceActivity::class.java)
pendingIntent.flags = Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
val contentIntent = PendingIntent.getActivity(this, 0,
pendingIntent, 0)

val notification = NotificationCompat.Builder(this, SERVICE_NOTIFICATION_CHANNEL_ID)
.setOnlyAlertOnce(true)
.setOngoing(true)
.setContentText("Bluetooth service running...")
.setContentIntent(contentIntent)
.setSmallIcon(R.drawable.ic_launcher_background)
.build()
startForeground(SERVICE_NOTIFICATION_ID, notification)
}
}

override fun onBind(intent: Intent?): IBinder? {
TODO("Not yet implemented")
}

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
return START_STICKY
}
}

I created a MainActivity that had to start the foreground service.

MainActivity.kt

class MainActivity : AppCompatActivity() {

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

val startServiceIntent = Intent(this, BluetoothDeviceService::class.java)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(startServiceIntent)
} else {
startService(startServiceIntent)
}
finish()
}
}

Please note that the Service could also be started by BroadcastReceiver, and that would be more appropriate, but I used the Activity for simplicity.

Also, I introduced a BluetoothDeviceActivity that was started by the service with help of PendingIntent:

BluetoothDeviceActivity.kt

class BluetoothDeviceActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

setContentView(R.layout.activity_main)
showAlertDialog()
}
}

private fun showAlertDialog() {
val dialogAlertDialog = AlertDialog.Builder(this)
.setCancelable(false)
.setMessage("This is a test")
.setTitle("Information")
.create()

dialogAlertDialog.show()
}

Just in case, I also put my manifest.

AndroidManifest.xml

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

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

<application
android:name=".MainApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.StackOverflowQuestion2"
android:fullBackupContent="@xml/backup_descriptor">
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:theme="@style/Theme.StackOverflowQuestion2.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>

<activity android:name=".BluetoothDeviceActivity"/>

<service android:name=".BluetoothDeviceService"/>
</application>

</manifest>

Result

This worked as expected without any problems.

Further suggestion

One other idea - you could convert your AlertDialog to Activity and use it as a Dialog. For this, you need to do 2 things:

  1. Create a new Àctivity as below:

    class AlertDialogActivity: AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    val dialogAlertDialog = AlertDialog.Builder(this)
    .setCancelable(false)
    .setMessage("This is a test")
    .setTitle("Information")
    .setPositiveButton("OK") { dialog, which -> finish() }
    .create()

    dialogAlertDialog.show()
    }
    }
  2. Add it to your manifest and set its theme as Dialog:

    <activity android:name=".AlertDialogActivity" android:theme="@style/Theme.AppCompat.Dialog"/>
  3. Then, create a method in your Service, and use it any time it's needed:

    private fun showAlertDialog() {
    val intent = Intent(applicationContext, AlertDialogActivity::class.java)
    intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
    applicationContext.startActivity(intent)
    }

Result

That's what it looks like:

Sample Image



Related Topics



Leave a reply



Submit