2

I am trying to connect my android app to an MS Band and the I am getting the following error:

java.lang.IllegalArgumentException: Service Intent must be explicit: Intent { act=com.microsoft.band.service.action.BIND_BAND_SERVICE }

The code snippet I am using is as follows:

private View.OnClickListener mButtonConnectClickListener = new View.OnClickListener() {
    @Override
    public void onClick(View button) {

        pairedBands = BandClientManager.getInstance().getPairedBands();
        bandClient = BandClientManager.getInstance().create(getApplicationContext(), pairedBands[0]);

        // Connect must be called on a background thread.
         new ConnectTask().execute();
        }

};


private class ConnectTask extends AsyncTask<BandClient, Void, Void> {
    @Override
    protected Void doInBackground(BandClient... clientParams) {

            BandPendingResult<ConnectionResult> pendingResult = null;
        try {
            pendingResult = bandClient.connect();
        } catch (BandIOException e) {
            e.printStackTrace();
        }

        try {
            ConnectionResult result = pendingResult.await();
            if(result == ConnectionResult.OK) {

                BandConnection.setText("Connection Worked");

            } else {
                BandConnection.setText("Connection Failed");
            }
        } catch(InterruptedException ex) {
            // handle InterruptedException
        } catch(BandException ex) {
            // handle BandException
        }
        return null;
    }

    protected void onPostExecute(Void result) {

    }
}

I am following the example given in the Microsft Band SDK, and I am new to this. Any help would be greatly appreciated.

Phil Hoff -- MSFT
  • 2,006
  • 12
  • 9
kasun61
  • 83
  • 2
  • 7
  • 2
    I hate to be a bearer of bad new but it looks like microsoft did not update their sdk for android 5.0 compatibility. in 5.0 you can no longer do implicit intents and thats what it looks like the sdk is doing somewhere. They need to update the sdk – tyczj Apr 09 '15 at 18:29
  • Possible duplicate of [Android L (API 21) - java.lang.IllegalArgumentException: Service Intent must be explicit](https://stackoverflow.com/questions/27183164/android-l-api-21-java-lang-illegalargumentexception-service-intent-must-be) – rds Oct 16 '17 at 13:02

2 Answers2

4

Although @tyczj's comment is absolutely true, it's missing a workaround. I'll attempt to describe the problem, its origin and a (temporary) workaround in this answer.

Let's identify the problem first. Somewhere in the internals of the Band SDK a call like this is happening:

Intent service = new Intent("com.microsoft.band.service.action.BIND_BAND_SERVICE");
context.bindService(service, connections, flags);

An implicit intent is created and it is used to bind up to a service. Unfortunately, starting Android 5.0 it is no longer allowed to bind to services uses implicit intents (as described in the API changes here). Instead, the intent should be explicit.

Since the above is happening deep inside the obfuscated band SDK and we don't have the sources for it, it's not trivial to 'update' the code to use an explicit intent. If you're savvy enough, you can probably change the Java byte code to do so, but I'd like to propose a different workaround:

Since the exception is thrown by bindService() and the intent is one of its parameters, we can override the method to ensure that whatever intent is supplied, ends up being explicit.

For example: the code below ensures that any intent with an action that starts with com.microsoft.band (which includes, but isn't limited to com.microsoft.band.service.action.BIND_BAND_SERVICE), is made explicit by setting the package name.

ContextWrapper bandContextWrapper = new ContextWrapper(getApplicationContext()) {
    @Override public boolean bindService(Intent service, ServiceConnection conn, int flags) {
        final String action = service.getAction();
        if (!TextUtils.isEmpty(action) && action.startsWith("com.microsoft.band")) {
            service.setPackage("com.microsoft.band");
        }
        return super.bindService(service, conn, flags);
    }
};

You can now use this wrapper to intercept the problematic call and update the intent (if required) by passing it to the BandClientManager as the 'context' to start the service on. Like so:

bandClient = BandClientManager.getInstance().create(bandContextWrapper, pairedBands[0]);

Now you should no longer get the IllegalArgumentException. I don't have a Microsoft Band myself so can't guarantee that everything will be fully working after this, but it should at least solve the problem outlined in your question.

Do note that this should only be considered a temporary workaround. As pointed out in one of the comments, Microsoft should really update its SDK to comply with Android 5+. That's the only proper solution. Until then, hopefully this helps.

MH.
  • 45,303
  • 10
  • 103
  • 116
  • This works if you use the Health App's package name instead: "com.microsoft.kapp" – Matthew Apr 12 '15 at 19:50
  • @Matthew: Ah yes, I should've made it more clear that the package name is supposed to be the app package name to which the Intent should limit its resolve scope. I was using the Band SDK sample app, which is why `com.microsoft.band` worked for me. – MH. Apr 13 '15 at 07:24
  • I'd like to confirm that this works wonderfully. Awesome solution @MH – Wyatt Apr 29 '15 at 00:47
0

In case anyone is using Xamarin.Android:

private class BandContextWrapper : ContextWrapper
{
    public BandContextWrapper(Context baseContext)
        : base (baseContext)
    {
    }

    public override bool BindService(Intent service, IServiceConnection conn, Bind flags)
    {
        var action = service.Action;
        if (!string.IsNullOrEmpty(action) && action.StartsWith("com.microsoft.band"))
        {
            service.SetPackage("com.microsoft.kapp");
        }
        return base.BindService(service, conn, flags);
    }
}

Then to use it:

var bandContextWrapper = new BandContextWrapper(Application.Context);
var client = BandClientManager.Instance.Create(bandContextWrapper, info);

Here I am using the http://components.xamarin.com/view/microsoft-band-sdk

Matthew
  • 4,832
  • 2
  • 29
  • 55