views:

115

answers:

1

I am creating a replacement Car Home app for Android 2.0+ devices. The app needs to launch when the phone is inserted into the car dock, as well as terminate when it is removed from the dock. It also needs to be able to be launched from the app drawer.

I'm having a problem right now where once the phone is inserted and removed from the dock, I can no longer launch the app from the app drawer because every time I launch the app my BroadcastReceiver picks up a DOCK_EVENT action for some reason. I created a test project that only registers my BroadcastReceiver, and the same thing happens.

Here's the code for the BroadcastReceiver:

public class CarDockBroadcastReceiver extends BroadcastReceiver {
/**
 * @see android.content.BroadcastReceiver#onReceive(Context,Intent)
 */
@Override
public void onReceive(Context context, Intent intent) {
    // TODO Put your code here

    if(intent.getExtras().containsKey("android.intent.extra.DOCK_STATE")){
        int state = intent.getExtras().getInt("android.intent.extra.DOCK_STATE",1);
        if(state == 0){
            Log.i("Dock", "Removed from dock!");    
            ((Activity)context).finish();
        }
    }
}

}

My main Activity is as follows:

public class MainActivity extends Activity {
/** Called when the activity is first created. */
CarDockBroadcastReceiver receiver;
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    IntentFilter filter = new IntentFilter("android.intent.action.DOCK_EVENT");
    receiver = new CarDockBroadcastReceiver();
    registerReceiver(receiver, filter);
}

@Override
protected void onDestroy() {
    // TODO Auto-generated method stub
    unregisterReceiver(receiver);
    super.onDestroy();
}

}

The main Activity has an intent filter for action.MAIN, category.LAUNCHER, category.DEFAULT, and category.CAR_DOCK. Any ideas on why this is happening?

+1  A: 

Intent.ACTION_DOCK_EVENT is a sticky broadcast. This means that when you register a receiver for it, you will immediately get the last-broadcast Intent for that action, then all subsequent broadcasts until it is unregistered. There is nothing much you can do about it, other than finding a way of dealing with the situation.

BTW, I recommend using Intent.ACTION_DOCK_EVENT rather than "android.intent.action.DOCK_EVENT" in your IntentFilter. This way, if for some goofy reason they change the actual string, your code does not need to change.

CommonsWare
Thanks for the help, you have saved me many hours of beating my head against the wall. I have it halfway working now using SharedPreferences to store the previous value of the dock and comparing that to the current dock state.
BigFwoosh
Another thing you can do is look at the return value from `registerReceiver()`. For a sticky broadcast, that is the last-broadcast `Intent`, the same one your receiver will get shortly. However, since broadcast receivers are invoked on the main application thread, if you call `registerReceiver()` on the main application thread, your current code will continue in control, and only later (e.g., after you return from `onCreate()`) will the receiver get the somewhat-fake broadcast. I'm not sure if that will help you, but it might let you avoid mucking up your prefs with this dock-related flag.
CommonsWare