title: Prevent onDestroy when Bluetooth connection state changes
body: <p><strong>Goal</strong></p>
  
  <ul>
  <li>If an already connected bluetooth device disconnects, and an Activity is already running, close the Activity</li>
  </ul>
  
  <p><strong>Problem</strong></p>
  
  <ul>
  <li>When the bluetooth device connection state changes through <em>BluetoothAdapterProperties: CONNECTION_STATE_CHANGE</em>, it seems like a new Activity is created or the current one restarts.</li>
  </ul>
  
  <p>There is nothing in the code that listens and/or should react to bluetooth connection state changes.</p>
  
  <p>The problem manifests itself in the use of BroadcastReceivers which in turn starts the Activity using intents. For some reason the Activity keep running through its lifecycle, spawning up new windows, even if the only change in bluetooth connectivity is <em>BluetoothAdapterProperties: CONNECTION_STATE_CHANGE</em></p>
  
  <p>I've tested this solely on a Nexus 6P with Android N. I have no idea yet what kind of implications this implementation means for any other devices yet. But I at least need to get this working on <em>one</em> device.</p>
  
  <p><strong>UPDATE</strong></p>
  
  <p>I have done a fair bit of experimentation and found that if I don't register the BroadcastReceiver in AndroidManifest, the problem with onDestroy being called disappears. But, I want to be able to react to Bluetooth connecting devices, so that I can launch my activity and then process input. If the activity gets destroyed every time a new device connects/disconnects, this won't work at all. What's the reasoning for having the BroadcastReceiver finishing an activity if it's already running and can I control that behaviour?</p>
  
  <p><strong>UPDATE 2</strong></p>
  
  <p>I can also conclude that disabling the statically declared BroadcastReceiver using this method <a href="https://stackoverflow.com/a/6529365/975641">https://stackoverflow.com/a/6529365/975641</a> doesn't improve things. As soon as the Manifest-BroadcastReceiver catches the ACL_CONNECTED intent from Android, and start my custom activity, it will ruthlessly call onDestroy on it when the connection state changes (which is usually just before an ACL_DISCONNECTED). It does not matter if I have ACL_DISCONNECTED declared in the Manifest or not. As long as I have my receiver listening for ACL_CONNECTED intents and I launch my Activity based on that, onDestroy will be called when the connection state changes. So frustrating.</p>
  
  <p><em>Manifest</em></p>
  
  <pre><code>&lt;uses-permission android:name="android.permission.BLUETOOTH" /&gt;
  &lt;uses-permission android:name="android.permission.VIBRATE" /&gt;
  
  &lt;application
      android:allowBackup="true"
      android:icon="@mipmap/ic_launcher"
      android:label="@string/app_name"
      android:supportsRtl="true"
      android:theme="@style/AppTheme"&gt;
      &lt;activity android:name=".MainActivity"&gt;
          &lt;intent-filter&gt;
              &lt;action android:name="android.intent.action.MAIN" /&gt;
  
              &lt;category android:name="android.intent.category.LAUNCHER" /&gt;
          &lt;/intent-filter&gt;
      &lt;/activity&gt;
      &lt;activity
          android:name=".BtActivity"
          android:launchMode="singleTop" /&gt;
      &lt;receiver android:name=".BtConnectionBroadcastReceiver" android:priority="100000"&gt;
          &lt;intent-filter&gt;
              &lt;action android:name="android.bluetooth.device.action.ACL_CONNECTED" /&gt;
              &lt;action android:name="android.bluetooth.device.action.ACL_DISCONNECTED" /&gt;
              &lt;action android:name="android.bluetooth.device.action.ACL_DISCONNECT_REQUESTED" /&gt;
              &lt;action android:name="android.intent.action.MEDIA_BUTTON" /&gt;
              &lt;action android:name="android.media.VOLUME_CHANGED_ACTION" /&gt;
          &lt;/intent-filter&gt;
      &lt;/receiver&gt;
  &lt;/application&gt;
  </code></pre>
  
  <p><em>BtConnectionBroadcastReceiver</em></p>
  
  <pre><code>public class BtConnectionBroadcastReceiver extends BroadcastReceiver {
      private static final String TAG = "BT";
      public static final String BROADCAST_ACTION_CONNECTED = "CONNECTED";
      public static final String BROADCAST_ACTION_DISCONNECTED = "DISCONNECTED";
      SharedPreferences mSharedPreferences;
  
      @Override
      public void onReceive(Context context, Intent intent) {
          String action = intent.getAction();
  
          // When discovery finds a device
          if (BluetoothDevice.ACTION_ACL_CONNECTED.equals(action)) {
              // Get the BluetoothDevice object from the Intent
              Log.d(TAG, "DEVICE CONNECTED");
              BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
              Log.d("DEVICE NAME", device.getName());
              Log.d("DEVICE ADDRESS", device.getAddress());
              Intent i = new Intent(context, BtActivity.class);
              i.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
              context.startActivity(i);
          } else if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)) {
              Log.d(TAG, "DEVICE DISCONNECTED");
              intent = new Intent();
              intent.setAction(BtConnectionBroadcastReceiver.BROADCAST_ACTION_DISCONNECTED);
              context.sendBroadcast(intent);
          }
      }
  </code></pre>
  
  <p><em>BtActivity</em></p>
  
  <pre><code>public class BtActivity extends AppCompatActivity {
  private static final String TAG = "BT";
  Window mWindow;
  
  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
  
      setContentView(R.layout.activity_bt);
  
      Log.d(TAG, "onCreate");
      IntentFilter filter = new IntentFilter(BtConnectionBroadcastReceiver.INTENT_FILTER);
      filter.addAction(BtConnectionBroadcastReceiver.BROADCAST_ACTION_CONNECTED);
      filter.addAction(BtConnectionBroadcastReceiver.BROADCAST_ACTION_DISCONNECTED);
      //registerReceiver(mReceiver, filter);
  
      mWindow = getWindow();
      WindowManager.LayoutParams params = new WindowManager.LayoutParams();
      //params.screenBrightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_OFF;
      params.screenBrightness = 0.2f;
      mWindow.setAttributes(params);
      mWindow.addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
      mWindow.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
      mWindow.addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
      mWindow.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
      mWindow.addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
      mWindow.getDecorView().setSystemUiVisibility(
              View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
                      View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
                      View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
                      View.SYSTEM_UI_FLAG_FULLSCREEN |
                      View.SYSTEM_UI_FLAG_IMMERSIVE);
      }
  
  @Override
  protected void onResume() {
      super.onResume();
      Log.d(TAG, "onResume");
  }
  
  @Override
  protected void onDestroy() {
      super.onDestroy();
      Log.d(TAG, "onDestroy");
  }
  
  BroadcastReceiver mReceiver = new BroadcastReceiver() {
  
      @Override
      public void onReceive(Context context, Intent intent) {
          Log.d(TAG, "BROADCAST RECEIVED IN ACTIVITY");
          String mac;
          if(intent.getAction().equals(BtConnectionBroadcastReceiver.BROADCAST_DEVICE_CONNECTED)) {
              Log.d(TAG, "CONNECT BROADCAST RECEIVED");
              mac = intent.getStringExtra("mac");
              checkConnectedDevice(mac, true); // This adds a device to an internal list
              Log.d(TAG, "Activity nr of devices:" +mNrOfDevices);
          }
          if(intent.getAction().equals(BtConnectionBroadcastReceiver.BROADCAST_DEVICE_DISCONNECTED)) {
              Log.d(TAG, "DISCONNECT BROADCAST RECEIVED");
              mac = intent.getStringExtra("mac");
              checkConnectedDevice(mac, false); // This removes a device from an internal list
              Log.d(TAG, "Activity nr of devices:" +mNrOfDevices);
              if(mNrOfDevices &lt; 1) {
                  Log.d(TAG, "No more connected devices");
                  finish();
              }
          }
          abortBroadcast();
      }
  };
  }
  </code></pre>
  
  <p>When I run this code, I get the following chain:</p>
  
  <ol>
  <li>Start MainActivity (not included, it only contains an activity with the default main layout, so that the applications receiver is registered)</li>
  <li>Switch on a bluetooth device (This has been paired earlier, so android knows about it)</li>
  <li>Wait until it connects and get this:
  
  <ul>
  <li>DEVICE CONNECTED</li>
  <li>onCreate</li>
  <li>onResume</li>
  </ul></li>
  <li>Switch off the bluetooth device and I then get this:
  
  <ul>
  <li>DEVICE DISCONNECTED</li>
  <li>onDestroy</li>
  <li>onCreate</li>
  <li>onResume</li>
  </ul></li>
  </ol>
  
  <p>I can't grasp why the activity is getting destroyed restarting at this point. The activity is already running, the BroadcastReceiver only sends a broadcast to an already running activity. I can't figure out why there's a reason for the Activity to kill itself and <em>then</em> restart again. This leaves me in a state of the Activity still running, but it is not the original Activity that was started.</p>
  
  <p>I do however see something in the logcats that seem to have something to do with this, and it's in this sequencing;</p>
  
  <p><em>06-02 15:45:09.156 26431 26431 D BT : DEVICE DISCONNECTED</em></p>
  
  <p><em>06-02 15:45:09.213 19547 19547 D BluetoothAdapterService: handleMessage() - MESSAGE_PROFILE_CONNECTION_STATE_CHANGED</em></p>
  
  <p><em>06-02 15:45:09.213 26431 26431 D BT : onDestroy</em></p>
  
  <p><em>06-02 15:45:09.214 19547 19547 D BluetoothAdapterProperties: CONNECTION_STATE_CHANGE: FF:FF:20:00:C1:47: 2 -> 0</em></p>
  
  <p><em>06-02 15:45:09.216  3502  3805 D CachedBluetoothDevice: onProfileStateChanged: profile HID newProfileState 0</em></p>
  
  <p><em>06-02 15:45:09.237   414   414 W SurfaceFlinger: couldn't log to binary event log: overflow.</em></p>
  
  <p><em>06-02 15:45:09.239 26431 26431 D BT : onCreate</em></p>
  
  <p><em>06-02 15:45:09.243 26431 26431 D BT : onResume</em></p>