Search code examples
androidbroadcastreceiverandroid-bluetoothandroid-uiautomatorandroid-instrumentation

How to register broadcast receiver inside instrumentation?


I am trying to get bluetooth discovery results through an apk which runs as android junit runner. Everything works fine but while registerReciever I get below error. What could be the reason ?

java.lang.SecurityException: Given caller package com.ex.test is not running in process ProcessRecord{d740580 19462:com.ex/u0a302}

Code-

@Test
public void demo() throws Exception {

    Context ctx = InstrumentationRegistry.getInstrumentation().getContext();
    BluetoothAdapter mBtAdapter = BluetoothAdapter.getDefaultAdapter();

    if (mBtAdapter.isDiscovering()) {
        System.out.println("Stop ongoing discovery");
        mBtAdapter.cancelDiscovery();
    }
    System.out.println("Start fresh discovery");
    mBtAdapter.startDiscovery();

    DisciveryRecv dReceiver = new DisciveryRecv ();
    // Register for broadcasts when a device is discovered
    IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
    ctx.registerReceiver(dReceiver, filter);
}


public class DisciveryRecv extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction(); 
        if (BluetoothDevice.ACTION_FOUND.equals(action)) {
            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            String dev = device.getName() + " - " + device.getAddress();
            mUtils.log("Found: " + dev);
        }
    }
}

startDiscovery works fine, but at ctx.registerReceiver(dReceiver, filter); , app is throwing exception.

Instrumentation cmd-

adb shell am instrument -w -r -e debug false -e class com.ex.main#demo com.ex/android.support.test.runner.AndroidJUnitRunner


Solution

  • InstrumentationRegistry.getTargetContext() returns the Context of the application under test.

    InstrumentationRegistry.getContext() returns the Context of the Instrumentation running the tests.

    Then, if you want to register a receiver as in the case you described you need you application Context. However, this is not really testing your application receives the broadcast as the receiver is not part of your it.

    Anyway, and answering your second question, the reason to use InstrumentationRegistry.getContext() is when your tests need access to resources or files that are not part of the application but only used in tests.

    EDIT

    Here there's an example. Two files, one in the app the other in tests

    src/androidTest/assets/sometestfile
    src/main/assets/someappfile
    

    then you can access them depending on the context

    @Test
    public final void testAccessToAppAssetsFromTest() throws IOException {
        final AssetManager assetManager = mInstrumentation.getTargetContext().getAssets();
        assetManager.open("someappfile");
    }
    
    @Test
    public final void testAccessToTestAssetsFromTest() throws IOException {
        final AssetManager assetManager = mInstrumentation.getContext().getAssets();
        assetManager.open("sometestfile");
    }
    

    If you try the opposite the test will fail.