jcarnide jcarnide - 2 months ago 21
Android Question

Custom Quick Settings Tile Remains in Unavailable State when Bound to Activity

I'm trying to add a custom quick settings tile for my application. I've followed the sample code/documentation from Google but I'm running into some issues. After searching for some time I couldn't find any solutions.

When I run my app, the tile is visible in the quick settings tray, but it remains in an unavailable state.

I need a two-way flow of communication with the tile, i.e., when the user selects the tile, the app responds and when the user does a certain action within the app, the tile UI is toggled.

The problem seems to come from attempting to bind my custom

TileService
class to my
MainActivity
-- whenever I bind it is when the tile goes into a consistently unavailable state. I can't seem to figure out why though because it's being bound successfully. If I don't bind it (i.e. just have the one way communication of the tile commanding the app), the tile is active and the app responds to selecting it.

Ultimately I do the binding to attain a reference to my custom
TileService
class to be able to call it's method
toggleTileUI()
. I'm not looking to use a singleton or static member variable as a solution to getting a reference to my service.

Here's what I have in my
AndroidManifest.xml
:

<service
android:name=".ConnectionQuickSettingsService"
android:label="@string/quick_setting_tile_connect"
android:icon="@drawable/tile_icon"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE" />
</intent-filter>
</service>


Here's my
ConnectionQuickSettingsService.java
:

@TargetApi(24)
public class ConnectionQuickSettingsService extends TileService {
private static final String TAG = "ConnectionQuickSettingsService";
private final IBinder mBinder = new LocalBinder();

public class LocalBinder extends Binder {
ConnectionQuickSettingsService getService() {
return ConnectionQuickSettingsService.this;
}
}

@Override
public IBinder onBind(Intent i) {
return mBinder;
}

@Override
public void onTileAdded() {
L.d(TAG, "onTileAdded()");
}

@Override
public void onStartListening() {
L.d(TAG, "onStartListening()");
}

@Override
public void onClick() {
L.d(TAG, "Quick Settings tile selected");
toggleInAppSwitch();
toggleTileUI();
}

private void toggleInAppSwitch() {
doStuff();
}

public void toggleTileUI() {
Tile tile = this.getQsTile();
doStuffWithTile();
}

}




and lastly (the relevant parts of) my
MainActivity.java
:

@Override
protected void onStart() {
super.onStart();
Intent i = new Intent(this, ConnectionQuickSettingsService.class);
bindService(i, mConnection, Context.BIND_AUTO_CREATE);
}

@Override
protected void onStop() {
super.onStop();
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}

private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className,
IBinder service) {
ConnectionQuickSettingsService.LocalBinder binder = (ConnectionQuickSettingsService.LocalBinder) service;
mQSService = binder.getService();
mBound = true;
L.d(TAG, "Bound to QS service successfully");
}

@Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
L.d(TAG, "Disconnected from QS service");
}
};

public void onOnOff(){
L.d(TAG, "On/Off switch toggled");
if (mBound) {
mQSService.toggleTileUI();
}
}




Any input would be greatly appreciated, thanks!

Answer

Part of your problem is that you are overriding onBind(), which clobbers the TileService implementation of onBind(), preventing Android from working with your ConnectionQuickSettingsService. I would expect that there would be error messages in LogCat from a system process complaining about this.

The other part of your problem is that you assume that getQsTile() works at arbitrary points in time. It doesn't.

I recommend finding some other interaction pattern with your tile, such as using META_DATA_ACTIVE_TILE and requestListeningState(), and getting rid of your Binder and onBind() method.

Comments