2
0
mirror of https://github.com/KDE/kdeconnect-android synced 2025-08-22 09:58:08 +00:00

Added preferences and the ability to enable and disable plugins from there

This commit is contained in:
Albert Vaca 2013-07-31 18:02:22 +02:00
parent cc947902f3
commit 4930a019d4
15 changed files with 408 additions and 161 deletions

View File

@ -10,13 +10,13 @@
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:label="KdeConnect "
android:theme="@style/AppTheme" >
<activity
android:name="org.kde.connect.MainActivity"
android:label="@string/app_name" >
android:label="KdeConnect " >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@ -26,9 +26,13 @@
<activity
android:name="org.kde.connect.MprisActivity"
android:label="KdeConnect - Mpris controls"
android:label="KdeConnect Mpris controls"
/>
<activity
android:name="org.kde.connect.SettingsActivity"
android:label="KdeConnect Settings"
/>
<service
android:enabled="true"

View File

@ -6,6 +6,7 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Binder;
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.util.Log;
import org.kde.connect.ComputerLinks.BaseComputerLink;
@ -17,42 +18,64 @@ import org.kde.connect.PackageInterfaces.CallPackageInterface;
import org.kde.connect.PackageInterfaces.ClipboardPackageInterface;
import org.kde.connect.PackageInterfaces.MprisControlPackageInterface;
import org.kde.connect.PackageInterfaces.PingPackageInterface;
import org.kde.kdeconnect.R;
import java.util.ArrayList;
import java.util.HashMap;
public class BackgroundService extends Service {
SharedPreferences settings;
ArrayList<BaseLinkProvider> linkProviders = new ArrayList<BaseLinkProvider>();
ArrayList<BasePackageInterface> packageInterfaces = new ArrayList<BasePackageInterface>();
HashMap<String, Device> devices = new HashMap<String, Device>();
private void registerPackageInterfaces() {
public void registerLinkProviders() {
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this);
if (settings.getBoolean("avahitcp_link", true)) {
linkProviders.add(new AvahiTcpLinkProvider(this));
}
}
public void registerPackageInterfacesFromSettings() {
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this);
Log.e("registerPackageInterfacesFromSettings","registerPackageInterfacesFromSettings");
if (settings.getBoolean("call_interface", true)) {
packageInterfaces.add(new CallPackageInterface(getApplicationContext()));
addPackageInterface(CallPackageInterface.class);
} else {
removePackageInterface(CallPackageInterface.class);
}
if (settings.getBoolean("ping_interface", true)) {
packageInterfaces.add(new PingPackageInterface(getApplicationContext()));
addPackageInterface(PingPackageInterface.class);
} else {
removePackageInterface(PingPackageInterface.class);
}
if (settings.getBoolean("clipboard_interface", true)) {
packageInterfaces.add(new ClipboardPackageInterface(getApplicationContext()));
addPackageInterface(ClipboardPackageInterface.class);
} else {
removePackageInterface(ClipboardPackageInterface.class);
}
if (settings.getBoolean("battery_interface", true)) {
packageInterfaces.add(new BatteryMonitorPackageInterface(getApplicationContext()));
addPackageInterface(BatteryMonitorPackageInterface.class);
} else {
removePackageInterface(BatteryMonitorPackageInterface.class);
}
if (settings.getBoolean("mpris_interface", true)) {
packageInterfaces.add(new MprisControlPackageInterface(getApplicationContext()));
addPackageInterface(MprisControlPackageInterface.class);
} else {
removePackageInterface(MprisControlPackageInterface.class);
}
}
public BasePackageInterface getPackageInterface(Class c) {
@ -62,12 +85,79 @@ public class BackgroundService extends Service {
return null;
}
public void registerLinkProviders() {
if (settings.getBoolean("avahitcp_link", true)) {
linkProviders.add(new AvahiTcpLinkProvider(this));
public BasePackageInterface addPackageInterface(Class c) {
BasePackageInterface pi = getPackageInterface(c);
if (pi != null) {
Log.e("addPackageInterface","package interface already existent");
return pi;
}
try {
pi = (BasePackageInterface)c.newInstance();
} catch(Exception e) {
e.printStackTrace();
Log.e("addPackageInterface","Error instantiating packageinterface");
return null;
}
packageInterfaces.add(pi);
pi.onCreate(getApplicationContext());
for (Device dev : devices.values()) {
dev.addPackageReceiver(pi);
pi.addDevice(dev);
}
return pi;
}
public boolean removePackageInterface(Class c) {
for (BasePackageInterface pi : packageInterfaces) {
if (c.isInstance(pi)) {
packageInterfaces.remove(pi);
for (Device dev : devices.values()) {
dev.removePackageReceiver(pi);
pi.removeDevice(dev);
}
pi.onDestroy();
return true;
}
}
Log.e("removePackageInterface","Unexistent preference");
return false;
}
public Device getDevice(String id) {
return devices.get(id);
}
private BaseLinkProvider.ConnectionReceiver deviceListener = new BaseLinkProvider.ConnectionReceiver() {
@Override
public void onConnectionAccepted(String deviceId, String name, BaseComputerLink link) {
Log.i("BackgroundService", "Connection accepted!");
if (devices.containsKey(deviceId)) {
Log.i("BackgroundService", "known device");
devices.get(deviceId).addLink(link);
} else {
Log.i("BackgroundService", "unknown device");
Device device = new Device(deviceId, name, link);
devices.put(deviceId, device);
for (BasePackageInterface pe : packageInterfaces) {
device.addPackageReceiver(pe);
pe.addDevice(device);
}
}
}
@Override
public void onConnectionLost(BaseComputerLink link) {
Device d = devices.get(link.getDeviceId());
if (d != null) {
d.removeLink(link);
//if (d.countLinkedDevices() == 0) devices.remove(link.getDeviceId);
}
}
};
public ArrayList<String> getVisibleDevices() {
ArrayList<String> list = new ArrayList<String>();
for(Device d : devices.values()) {
@ -90,36 +180,7 @@ public class BackgroundService extends Service {
private void startDiscovery() {
Log.i("StartDiscovery","Registering connection receivers");
for (BaseLinkProvider a : linkProviders) {
a.reachComputers(new BaseLinkProvider.ConnectionReceiver() {
@Override
public void onConnectionAccepted(String deviceId, String name, BaseComputerLink link) {
Log.i("BackgroundService", "Connection accepted!");
if (devices.containsKey(deviceId)) {
Log.i("BackgroundService", "known device");
devices.get(deviceId).addLink(link);
} else {
Log.i("BackgroundService", "unknown device");
Device device = new Device(deviceId, name, link);
devices.put(deviceId, device);
for (BasePackageInterface pe : packageInterfaces) {
device.addPackageReceiver(pe);
pe.addDevice(device);
}
}
}
@Override
public void onConnectionLost(BaseComputerLink link) {
Device d = devices.get(link.getDeviceId());
if (d != null) {
d.removeLink(link);
//if (d.countLinkedDevices() == 0) devices.remove(link.getDeviceId);
}
}
});
a.reachComputers(deviceListener);
}
}
@ -130,9 +191,7 @@ public class BackgroundService extends Service {
Log.i("BackgroundService","Service not started yet, initializing...");
settings = getSharedPreferences("KdeConnect", 0);
registerPackageInterfaces();
registerPackageInterfacesFromSettings();
registerLinkProviders();
startDiscovery();

View File

@ -67,6 +67,10 @@ public class Device {
receivers.add(receiver);
}
public void removePackageReceiver(BasePackageInterface receiver) {
receivers.remove(receiver);
}
public boolean sendPackage(final NetworkPackage np) {
Log.e("Device", "sendPackage");
@ -86,7 +90,7 @@ public class Device {
}
}.execute();
return true; //FIXME
return true; //FIXME: Detect when unable to send a package and try again somehow
}
}

View File

@ -4,6 +4,7 @@ import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
@ -94,4 +95,15 @@ public class MainActivity extends Activity {
return true;
}
@Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
switch(item.getItemId()){
case R.id.action_settings:
Intent intent = new Intent(this,SettingsActivity.class);
startActivity(intent);
return true;
default:
return super.onMenuItemSelected(featureId, item);
}
}
}

View File

@ -30,6 +30,7 @@ public class MprisActivity extends Activity {
public void onServiceStart(BackgroundService service) {
final MprisControlPackageInterface mpris = (MprisControlPackageInterface)service.getPackageInterface(MprisControlPackageInterface.class);
if (mpris == null) return;
mpris.setNowPlayingUpdatedHandler(new Handler() {
@Override
@ -84,6 +85,7 @@ public class MprisActivity extends Activity {
@Override
public void onServiceStart(BackgroundService service) {
MprisControlPackageInterface mpris = (MprisControlPackageInterface)service.getPackageInterface(MprisControlPackageInterface.class);
if (mpris == null) return;
mpris.sendAction("PlayPause");
}
});
@ -97,6 +99,7 @@ public class MprisActivity extends Activity {
@Override
public void onServiceStart(BackgroundService service) {
MprisControlPackageInterface mpris = (MprisControlPackageInterface)service.getPackageInterface(MprisControlPackageInterface.class);
if (mpris == null) return;
mpris.sendAction("Previous");
}
});
@ -110,6 +113,7 @@ public class MprisActivity extends Activity {
@Override
public void onServiceStart(BackgroundService service) {
MprisControlPackageInterface mpris = (MprisControlPackageInterface)service.getPackageInterface(MprisControlPackageInterface.class);
if (mpris == null) return;
mpris.sendAction("Next");
}
});

View File

@ -1,5 +1,7 @@
package org.kde.connect.PackageInterfaces;
import android.content.Context;
import org.kde.connect.Device;
import org.kde.connect.NetworkPackage;
@ -35,8 +37,9 @@ public abstract class BasePackageInterface {
return true;
}
//To override, returns true if package was handled
//To override
public abstract boolean onCreate(Context context);
public abstract void onDestroy();
public abstract boolean onPackageReceived(Device d, NetworkPackage np);
public abstract boolean onDeviceConnected(Device d);
}

View File

@ -14,39 +14,51 @@ public class BatteryMonitorPackageInterface extends BasePackageInterface {
NetworkPackage lastPackage = null;
public BatteryMonitorPackageInterface(final Context context) {
final IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
context.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Context context;
IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.e("BatteryMonitorPackageInterface", "Battery event");
Log.e("BatteryMonitorPackageInterface", "Battery event");
boolean isCharging = (0 != intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0));
boolean isCharging = (0 != intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0));
int currentCharge = 100;
int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
if (status != BatteryManager.BATTERY_STATUS_FULL) {
Intent batteryStatus = context.registerReceiver(null, ifilter);
int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
currentCharge = level*100 / scale;
}
//Only notify if change is meaningful enough
if (lastPackage == null || (
isCharging != lastPackage.getBoolean("isCharging")
|| currentCharge != lastPackage.getInt("currentCharge")
)
) {
NetworkPackage np = new NetworkPackage(NetworkPackage.PACKAGE_TYPE_BATTERY);
np.set("isCharging", isCharging);
np.set("currentCharge", currentCharge);
sendPackage(np);
lastPackage = np;
}
int currentCharge = 100;
int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
if (status != BatteryManager.BATTERY_STATUS_FULL) {
Intent batteryStatus = context.registerReceiver(null, filter);
int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
currentCharge = level*100 / scale;
}
}, ifilter);
//Only notify if change is meaningful enough
if (lastPackage == null || (
isCharging != lastPackage.getBoolean("isCharging")
|| currentCharge != lastPackage.getInt("currentCharge")
)
) {
NetworkPackage np = new NetworkPackage(NetworkPackage.PACKAGE_TYPE_BATTERY);
np.set("isCharging", isCharging);
np.set("currentCharge", currentCharge);
sendPackage(np);
lastPackage = np;
}
}
};
@Override
public boolean onCreate(final Context context) {
this.context = context;
context.registerReceiver(receiver, filter);
return true;
}
@Override
public void onDestroy() {
context.unregisterReceiver(receiver);
}
@Override

View File

@ -11,38 +11,36 @@ import org.kde.connect.NetworkPackage;
public class CallPackageInterface extends BasePackageInterface {
public CallPackageInterface(final Context ctx) {
private Context context;
//Log.i("CallPackageInterface", "Registered");
private PhoneStateListener callStateListener = new PhoneStateListener() {
PhoneStateListener callStateListener = new PhoneStateListener() {
int lastState = TelephonyManager.CALL_STATE_IDLE;
NetworkPackage lastPackage = null;
int lastState = TelephonyManager.CALL_STATE_IDLE;
NetworkPackage lastPackage = null;
@Override
public void onCallStateChanged(int state, String phoneNumber) {
@Override
public void onCallStateChanged(int state, String phoneNumber) {
switch (state) {
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
case TelephonyManager.CALL_STATE_RINGING:
//Log.i("IncomingCall", ":" + phoneNumber);
//Log.i("IncomingCall", ":" + phoneNumber);
lastPackage = new NetworkPackage(NetworkPackage.PACKAGE_TYPE_NOTIFICATION);
lastPackage = new NetworkPackage(NetworkPackage.PACKAGE_TYPE_NOTIFICATION);
lastPackage.set("notificationType", "ringing");
if (phoneNumber != null && !phoneNumber.isEmpty()) {
lastPackage.set("phoneNumber", phoneNumber);
}
lastPackage.set("notificationType", "ringing");
if (phoneNumber != null && !phoneNumber.isEmpty()) {
lastPackage.set("phoneNumber", phoneNumber);
}
sendPackage(lastPackage);
sendPackage(lastPackage);
break;
break;
case TelephonyManager.CALL_STATE_OFFHOOK: //Ongoing call
case TelephonyManager.CALL_STATE_OFFHOOK: //Ongoing call
//Log.i("OngoingCall", ":"+phoneNumber);
//Log.i("OngoingCall", ":"+phoneNumber);
/*
//Actually we do not want to cancel it
@ -53,51 +51,64 @@ public class CallPackageInterface extends BasePackageInterface {
}
*/
//Emit a "call" package
lastPackage = new NetworkPackage(NetworkPackage.PACKAGE_TYPE_CALL);
if (phoneNumber != null && !phoneNumber.isEmpty()) {
lastPackage.set("phoneNumber",phoneNumber);
}
//Emit a "call" package
lastPackage = new NetworkPackage(NetworkPackage.PACKAGE_TYPE_CALL);
if (phoneNumber != null && !phoneNumber.isEmpty()) {
lastPackage.set("phoneNumber",phoneNumber);
}
sendPackage(lastPackage);
break;
case TelephonyManager.CALL_STATE_IDLE:
if (lastState != TelephonyManager.CALL_STATE_IDLE && lastPackage != null) {
//Log.i("EndedCall", ":"+phoneNumber);
//End last notification (can either be a ring notification or a call event)
lastPackage.set("isCancel","true");
sendPackage(lastPackage);
break;
case TelephonyManager.CALL_STATE_IDLE:
if (lastState != TelephonyManager.CALL_STATE_IDLE && lastPackage != null) {
//Log.i("EndedCall", ":"+phoneNumber);
//End last notification (can either be a ring notification or a call event)
lastPackage.set("isCancel","true");
sendPackage(lastPackage);
if (lastState == TelephonyManager.CALL_STATE_RINGING) {
//Emit a missed call notification
NetworkPackage missed = new NetworkPackage(NetworkPackage.PACKAGE_TYPE_NOTIFICATION);
missed.set("notificationType","missedCall");
if (phoneNumber != null && !phoneNumber.isEmpty()) {
missed.set("phoneNumber", lastPackage.getString("phoneNumber"));
}
sendPackage(missed);
if (lastState == TelephonyManager.CALL_STATE_RINGING) {
//Emit a missed call notification
NetworkPackage missed = new NetworkPackage(NetworkPackage.PACKAGE_TYPE_NOTIFICATION);
missed.set("notificationType","missedCall");
if (phoneNumber != null && !phoneNumber.isEmpty()) {
missed.set("phoneNumber", lastPackage.getString("phoneNumber"));
}
lastPackage = null;
sendPackage(missed);
}
break;
lastPackage = null;
}
}
lastState = state;
break;
}
};
TelephonyManager tm = (TelephonyManager) ctx.getSystemService(Context.TELEPHONY_SERVICE);
lastState = state;
}
};
@Override
public boolean onCreate(final Context context) {
this.context = context;
TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
tm.listen(callStateListener, PhoneStateListener.LISTEN_CALL_STATE);
return true;
}
@Override
public void onDestroy() {
TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
tm.listen(callStateListener, PhoneStateListener.LISTEN_NONE);
}
@Override

View File

@ -9,31 +9,43 @@ import org.kde.connect.NetworkPackage;
public class ClipboardPackageInterface extends BasePackageInterface {
ClipboardManager cm;
boolean ignore_next_clipboard_change = false;
public ClipboardPackageInterface(final Context ctx) {
cm = (ClipboardManager)ctx.getSystemService(Context.CLIPBOARD_SERVICE);
cm.addPrimaryClipChangedListener(new ClipboardManager.OnPrimaryClipChangedListener() {
@Override
public void onPrimaryClipChanged() {
try {
if (ignore_next_clipboard_change) {
ignore_next_clipboard_change = false;
return;
}
NetworkPackage np = new NetworkPackage(NetworkPackage.PACKAGE_TYPE_CLIPBOARD);
ClipData.Item item = cm.getPrimaryClip().getItemAt(0);
np.set("content",item.coerceToText(ctx).toString());
sendPackage(np);
} catch(Exception e) {
//Probably clipboard was not text
Context context;
ClipboardManager cm;
ClipboardManager.OnPrimaryClipChangedListener listener = new ClipboardManager.OnPrimaryClipChangedListener() {
@Override
public void onPrimaryClipChanged() {
try {
if (ignore_next_clipboard_change) {
ignore_next_clipboard_change = false;
return;
}
NetworkPackage np = new NetworkPackage(NetworkPackage.PACKAGE_TYPE_CLIPBOARD);
ClipData.Item item = cm.getPrimaryClip().getItemAt(0);
np.set("content",item.coerceToText(context).toString());
sendPackage(np);
} catch(Exception e) {
//Probably clipboard was not text
}
});
}
};
@Override
public boolean onCreate(Context context) {
this.context = context;
cm = (ClipboardManager)context.getSystemService(Context.CLIPBOARD_SERVICE);
cm.addPrimaryClipChangedListener(listener);
return false;
}
@Override
public void onDestroy() {
cm.removePrimaryClipChangedListener(listener);
}
@Override

View File

@ -26,8 +26,15 @@ public class MprisControlPackageInterface extends BasePackageInterface {
String player = "";
public MprisControlPackageInterface(Context ctx) {
@Override
public boolean onCreate(Context ctx) {
context = ctx;
return true;
}
@Override
public void onDestroy() {
playerList.clear();
}
public void sendAction(String s) {

View File

@ -14,8 +14,15 @@ public class PingPackageInterface extends BasePackageInterface {
Context context;
public PingPackageInterface(Context ctx) {
@Override
public boolean onCreate(Context ctx) {
context = ctx;
return true;
}
@Override
public void onDestroy() {
}
public void sendPing() {

View File

@ -0,0 +1,21 @@
package org.kde.connect;
import android.app.Activity;
import android.os.Bundle;
public class SettingsActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Display the fragment as the main content.
getFragmentManager().beginTransaction()
.replace(android.R.id.content, new SettingsFragment())
.commit();
}
}

View File

@ -0,0 +1,50 @@
package org.kde.connect;
import android.app.Activity;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceFragment;
import android.util.Log;
import org.kde.kdeconnect.R;
public class SettingsFragment extends PreferenceFragment {
SharedPreferences.OnSharedPreferenceChangeListener preferenceChangeListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
Log.e("onSharedPreferenceChanged",key+"->"+sharedPreferences.getBoolean(key,true));
Activity activity = getActivity();
if (activity == null) return;
BackgroundService.RunCommand(activity, new BackgroundService.InstanceCallback() {
@Override
public void onServiceStart(BackgroundService service) {
service.registerPackageInterfacesFromSettings();
}
});
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.settings);
}
@Override
public void onResume() {
super.onResume();
getPreferenceManager().getSharedPreferences()
.registerOnSharedPreferenceChangeListener(preferenceChangeListener);
}
@Override
public void onPause() {
getPreferenceManager().getSharedPreferences()
.unregisterOnSharedPreferenceChangeListener(preferenceChangeListener);
super.onPause();
}
}

View File

@ -1,11 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name" >KdeConnect
</string>
<string name="action_settings" >Settings
</string>
<string name="hello_world" >Hello world!
</string>
<string name="action_settings" >Settings</string>
<string name="pref_enable_call_interface">Call notifications</string>
<string name="pref_enable_call_interface_desc">Send incoming and missed call notifications</string>
<string name="pref_enable_clipboard_interface">Clipboard sync</string>
<string name="pref_enable_clipboard_interface_desc">Share the clipboard content</string>
<string name="pref_enable_battery_interface">Battery report</string>
<string name="pref_enable_battery_interface_desc">Periodically report battery status</string>
<string name="pref_enable_mpris_interface">MPRIS controls</string>
<string name="pref_enable_mpris_interface_desc">Control audio/video from your phone</string>
<string name="pref_enable_ping_interface">Pings</string>
<string name="pref_enable_ping_interface_desc">Enable sending and receiving ping notifications</string>
</resources>

View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android">
<CheckBoxPreference
android:key="call_interface"
android:title="@string/pref_enable_call_interface"
android:summary="@string/pref_enable_call_interface_desc"
android:defaultValue="true" />
<CheckBoxPreference
android:key="ping_interface"
android:title="@string/pref_enable_ping_interface"
android:summary="@string/pref_enable_ping_interface_desc"
android:defaultValue="true" />
<CheckBoxPreference
android:key="clipboard_interface"
android:title="@string/pref_enable_clipboard_interface"
android:summary="@string/pref_enable_clipboard_interface_desc"
android:defaultValue="true" />
<CheckBoxPreference
android:key="battery_interface"
android:title="@string/pref_enable_battery_interface"
android:summary="@string/pref_enable_battery_interface_desc"
android:defaultValue="true" />
<CheckBoxPreference
android:key="mpris_interface"
android:title="@string/pref_enable_mpris_interface"
android:summary="@string/pref_enable_mpris_interface_desc"
android:defaultValue="true" />
</PreferenceScreen>