Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Infinite Activity Loop when toggling Bluetooth

I have created an app that checks a payload of an NFC tag, and when it matches the app toggles Bluetooth.

Unfortunately the app seems to be entering into an infinite loop, where it asks the user for permission to manipulate Bluetooth, ignores the choice and launches again (asking the same question/Activity again). onActivityResult seems to not be getting called.

Output from my console log calls is:

Payload: 'quicktags-togglebluetooth'
Bluetooth should now be on

If I continue to hit 'Yes' on the permission Activity then Bluetooth toggles indefnitely, and the console log (logcat) looks like:

Payload: quicktags-togglebluetooth
Bluetooth should now be on
Bluetooth should now be off
Bluetooth should now be on
Bluetooth should now be off
Bluetooth should now be on
Bluetooth should now be off

and so on.

AndroidManifest lists the correct permissions, please see below:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.getquicktags.qt"
    android:versionCode="1"
    android:versionName="1.0" android:installLocation="auto">

    <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="14" />

    <uses-permission android:name="android.permission.NFC" />
    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-feature android:name="android.hardware.nfc" android:required="true" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >

        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

         <activity
            android:name=".CardActivity"
            android:label="@string/app_name" >

            <!-- Handle a collectable card NDEF record -->
            <intent-filter>
                <action android:name="android.nfc.action.NDEF_DISCOVERED"/>
                <data android:mimeType="application/vnd.getquicktags.qt"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
         </activity>

    </application>

</manifest>

The CardActivity.java file, which is what launches this Bluetooth chaos can be found below:

package com.getquicktags.qt;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.Log;
import android.bluetooth.*;

public class CardActivity extends Activity implements OnClickListener {

    private static final String TAG = null;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.card_activity);

        // see if app was started from a tag and show game console
        Intent intent = getIntent();

        if(intent.getType() != null && intent.getType().equals(MimeType.NFC_DEMO)) {
            Parcelable[] rawMsgs = getIntent().getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
            NdefMessage msg = (NdefMessage) rawMsgs[0];
            NdefRecord cardRecord = msg.getRecords()[0];
            String payload = new String(cardRecord.getPayload());

            Log.d(TAG, "Payload: '"+ payload +"'");

            if(payload.equals("quicktags-togglebluetooth")) {
                toggleBluetooth();
            }
        }
    }

    private void toggleBluetooth() {

        BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        if (mBluetoothAdapter == null) {
            // Device does not support Bluetooth
            Log.d(TAG, "No Bluetooth on device");
            closeApp();
        }
        if (!mBluetoothAdapter.isEnabled()) {
            Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableBtIntent, 1);
            Log.d(TAG, "Bluetooth should now be on");
        } else {
            // Turn it off
            mBluetoothAdapter.disable();
            Log.d(TAG, "Bluetooth should now be off");
            closeApp();
        }

    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        // Close the app
        Log.d(TAG, "Close the app call");
        closeApp();
    }


    private void closeApp() {
        Log.d(TAG, "And... close it. This is inside closeApp()");
        android.os.Process.killProcess(android.os.Process.myPid());
    }

    public void onClick(DialogInterface dialog, int which) {
        // TODO Auto-generated method stub

    }
}

You can see that, according to logcat, onActivityResults and thus closeApp do not get called.

I am testing on a Nexus 7. Tag is fine, I've tested with various NFC readers.

There are some errors from logcat when the tag is scanned, but they don't seem to make much sense to me. See below:

01-07 00:18:41.595: E/bt-btif(5830): btif_enable_service: current services:0x100020
01-07 00:18:41.605: E/bt-btif(5830): btif_enable_service: current services:0x140020
01-07 00:18:41.605: E/bt-btif(5830): btif_enable_service: current services:0x140020
01-07 00:18:42.415: E/bt-btif(5830): Calling BTA_HhEnable
01-07 00:18:42.415: E/btif_config.c(5830): ## btif_config_get assert section && *section && key && *key && name && *name && bytes && type failed at line:186 ##
01-07 00:18:42.415: E/bt-btif(5830): btif_storage_get_adapter_property service_mask:0x140020
01-07 00:18:42.435: E/btif_config.c(5830): ## btif_config_get assert section && *section && key && *key && name && *name && bytes && type failed at line:186 ##
01-07 00:18:42.445: E/bt_h4(5830): vendor lib postload completed
01-07 00:18:42.545: E/BluetoothServiceJni(5830): SOCK FLAG = 1 ***********************
01-07 00:18:42.605: E/BluetoothServiceJni(5830): SOCK FLAG = 0 ***********************
01-07 00:18:42.715: E/BtOppRfcommListener(5830): Error accept connection java.io.IOException: read failed, socket might closed, read ret: -1
01-07 00:18:42.915: E/bt-btif(5830): BTA AG is already disabled, ignoring ...
01-07 00:18:42.935: E/bt-btif(5830): btif_disable_service: Current Services:0x140020
01-07 00:18:42.945: E/bt-btif(5830): btif_disable_service: Current Services:0x100020
01-07 00:18:42.945: E/bt-btif(5830): btif_disable_service: Current Services:0x100020

Massive thanks for any help on this. As you can probably imagine, it is driving me mad :)

like image 883
Mike Avatar asked Jan 07 '13 00:01

Mike


1 Answers

Why are you killing the process in closeApp()? I imagine this is part of your problem. Just call finish() on the activity and let Android deal with cleaning up your process when it wants to.

When you kill your Process, Android thinks something bad happened and tries to recover. As part of this recovery it may be redelivering Intents which is probably not what you want

like image 89
David Wasser Avatar answered Oct 18 '22 22:10

David Wasser