mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-01-08 05:24:39 +01:00
add pref to disable use of bluetooth
It's buggy enough on some devices that a user might need to disable it.
This commit is contained in:
parent
04000ddf7e
commit
157332d2cc
11 changed files with 223 additions and 45 deletions
|
@ -0,0 +1,69 @@
|
|||
/* -*- compile-command: "find-and-gradle.sh inXw4dDeb"; -*- */
|
||||
/*
|
||||
* Copyright 2009 - 2012 by Eric House (xwords@eehouse.org). All
|
||||
* rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package org.eehouse.android.xw4;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import org.eehouse.android.xw4.DlgDelegate.Action;
|
||||
import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnType;
|
||||
import org.eehouse.android.xw4.loc.LocUtils;
|
||||
|
||||
public class BTCheckBoxPreference extends ConfirmingCheckBoxPreference {
|
||||
private static final String TAG = BTCheckBoxPreference.class.getSimpleName();
|
||||
private static WeakReference<BTCheckBoxPreference> s_this = null;
|
||||
|
||||
public BTCheckBoxPreference( Context context, AttributeSet attrs )
|
||||
{
|
||||
super( context, attrs );
|
||||
s_this = new WeakReference<>( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void checkIfConfirmed()
|
||||
{
|
||||
PrefsActivity activity = (PrefsActivity)getContext();
|
||||
String msg = LocUtils.getString( activity,
|
||||
R.string.warn_bt_havegames );
|
||||
|
||||
int count = DBUtils
|
||||
.getGameCountUsing( activity, CommsConnType.COMMS_CONN_BT );
|
||||
if ( 0 < count ) {
|
||||
msg += LocUtils.getQuantityString( activity, R.plurals.warn_bt_games_fmt,
|
||||
count, count );
|
||||
}
|
||||
activity.makeConfirmThenBuilder( msg, Action.DISABLE_BT_DO )
|
||||
.setPosButton( R.string.button_disable_bt )
|
||||
.show();
|
||||
}
|
||||
|
||||
protected static void setChecked()
|
||||
{
|
||||
if ( null != s_this ) {
|
||||
BTCheckBoxPreference self = s_this.get();
|
||||
if ( null != self ) {
|
||||
self.super_setChecked( true );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -47,6 +47,7 @@ import java.util.Set;
|
|||
import java.util.UUID;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.eehouse.android.xw4.DbgUtils.DeadlockWatch;
|
||||
import org.eehouse.android.xw4.MultiService.DictFetchOwner;
|
||||
|
@ -99,7 +100,7 @@ public class BTUtils {
|
|||
|
||||
public static boolean BTAvailable()
|
||||
{
|
||||
BluetoothAdapter adapter = getAdapterIf();
|
||||
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
|
||||
return null != adapter;
|
||||
}
|
||||
|
||||
|
@ -109,22 +110,38 @@ public class BTUtils {
|
|||
return null != adapter && adapter.isEnabled();
|
||||
}
|
||||
|
||||
public static void enable()
|
||||
public static void enable( Context context )
|
||||
{
|
||||
BluetoothAdapter adapter = getAdapterIf();
|
||||
if ( null != adapter ) {
|
||||
// Only do this after explicit action from user -- Android guidelines
|
||||
adapter.enable();
|
||||
}
|
||||
XWPrefs.setBTDisabled( context, false );
|
||||
}
|
||||
|
||||
public static void setEnabled( Context context, boolean enabled )
|
||||
{
|
||||
if ( enabled ) {
|
||||
onResume( context );
|
||||
} else {
|
||||
stopThreads();
|
||||
}
|
||||
}
|
||||
|
||||
public static void disabledChanged( Context context )
|
||||
{
|
||||
boolean disabled = XWPrefs.getBTDisabled( context );
|
||||
setEnabled( context, !disabled );
|
||||
}
|
||||
|
||||
static BluetoothAdapter getAdapterIf()
|
||||
{
|
||||
BluetoothAdapter result = null;
|
||||
// Later this will change to include at least a test whether we're
|
||||
// running as background user account, a situation in which BT crashes
|
||||
// a lot inside the OS.
|
||||
if ( !sBackUser.get() ) {
|
||||
// BT crashes a lot inside the OS when running on behalf of a
|
||||
// background user account. We catch exceptions that indicate that's
|
||||
// going on and set this flag.
|
||||
if ( ! XWPrefs.getBTDisabled( getContext() ) && !sBackUser.get() ) {
|
||||
result = BluetoothAdapter.getDefaultAdapter();
|
||||
}
|
||||
return result;
|
||||
|
@ -195,6 +212,12 @@ public class BTUtils {
|
|||
sBackUser.set( false );
|
||||
}
|
||||
|
||||
private static void stopThreads()
|
||||
{
|
||||
ListenThread.stopSelf();
|
||||
ReadThread.stopSelf();
|
||||
}
|
||||
|
||||
private static String nameForAddr( BluetoothAdapter adapter, String btAddr )
|
||||
{
|
||||
String result = null;
|
||||
|
@ -316,14 +339,14 @@ public class BTUtils {
|
|||
|
||||
private static void updateStatusIn( boolean success )
|
||||
{
|
||||
Context context = XWApp.getContext();
|
||||
Context context = getContext();
|
||||
ConnStatusHandler
|
||||
.updateStatusIn( context, CommsConnType.COMMS_CONN_BT, success );
|
||||
}
|
||||
|
||||
private static void updateStatusOut( boolean success )
|
||||
{
|
||||
Context context = XWApp.getContext();
|
||||
Context context = getContext();
|
||||
ConnStatusHandler
|
||||
.updateStatusOut( context, CommsConnType.COMMS_CONN_BT, success );
|
||||
}
|
||||
|
@ -398,32 +421,36 @@ public class BTUtils {
|
|||
return btAddr;
|
||||
}
|
||||
|
||||
private static void clearInstance( Thread[] holder, Thread instance )
|
||||
private static void clearInstance( AtomicReference<Thread> holder,
|
||||
Thread instance )
|
||||
{
|
||||
synchronized ( holder ) {
|
||||
if ( holder[0] == null ) {
|
||||
Thread curThread = holder.get();
|
||||
if ( null == curThread ) {
|
||||
// nothing to do
|
||||
} else if ( holder[0] == instance ) {
|
||||
holder[0] = null;
|
||||
} else if ( instance == curThread ) {
|
||||
holder.set( null );
|
||||
} else {
|
||||
Log.e( TAG, "clearInstance(): cur instance %s not == %s",
|
||||
holder[0], instance );
|
||||
curThread, instance );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Save a few keystrokes...
|
||||
private static Context getContext() { return XWApp.getContext(); }
|
||||
|
||||
private static class ScanThread extends Thread {
|
||||
private static Thread[] sInstance = {null};
|
||||
private static AtomicReference<Thread> sInstance = new AtomicReference<>();
|
||||
private int mTimeoutMS;
|
||||
private Set<BluetoothDevice> mDevs;
|
||||
|
||||
static void startOnce( int timeoutMS, Set<BluetoothDevice> devs )
|
||||
{
|
||||
synchronized ( sInstance ) {
|
||||
if ( sInstance[0] == null ) {
|
||||
if ( null == sInstance.get() ) {
|
||||
ScanThread thread = new ScanThread( timeoutMS, devs );
|
||||
sInstance[0] = thread;
|
||||
Assert.assertTrueNR( thread == sInstance.get() );
|
||||
thread.start();
|
||||
}
|
||||
}
|
||||
|
@ -433,12 +460,13 @@ public class BTUtils {
|
|||
{
|
||||
mTimeoutMS = timeoutMS;
|
||||
mDevs = devs;
|
||||
sInstance.set( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
Assert.assertTrueNR( this == sInstance[0] );
|
||||
Assert.assertTrueNR( this == sInstance.get() );
|
||||
Map<BluetoothDevice, PacketAccumulator> pas = new HashMap<>();
|
||||
|
||||
for ( BluetoothDevice dev : mDevs ) {
|
||||
|
@ -1049,12 +1077,14 @@ public class BTUtils {
|
|||
} // class PacketAccumulator
|
||||
|
||||
private static class ListenThread extends Thread {
|
||||
private static Thread[] sInstance = {null};
|
||||
private static AtomicReference<Thread> sInstance = new AtomicReference<>();
|
||||
private BluetoothAdapter mAdapter;
|
||||
private BluetoothServerSocket mServerSocket;
|
||||
|
||||
private ListenThread( BluetoothAdapter adapter )
|
||||
{
|
||||
mAdapter = adapter;
|
||||
sInstance.set( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1062,32 +1092,31 @@ public class BTUtils {
|
|||
{
|
||||
Log.d( TAG, "ListenThread: %s.run() starting", this );
|
||||
|
||||
BluetoothServerSocket serverSocket;
|
||||
try {
|
||||
Assert.assertTrueNR( null != sAppName && null != sUUID );
|
||||
serverSocket = mAdapter
|
||||
mServerSocket = mAdapter
|
||||
.listenUsingRfcommWithServiceRecord( sAppName, sUUID );
|
||||
} catch ( IOException ioe ) {
|
||||
Log.ex( TAG, ioe );
|
||||
serverSocket = null;
|
||||
mServerSocket = null;
|
||||
} catch ( SecurityException ex ) {
|
||||
// Got this with a message saying not allowed to call
|
||||
// listenUsingRfcommWithServiceRecord() in background (on
|
||||
// Android 9)
|
||||
sBackUser.set( true ); // two-user system: disable BT
|
||||
Log.d( TAG, "set sBackUser; outta here (first case)" );
|
||||
serverSocket = null;
|
||||
mServerSocket = null;
|
||||
}
|
||||
|
||||
while ( null != serverSocket ) {
|
||||
while ( null != mServerSocket && this == sInstance.get() ) {
|
||||
Log.d( TAG, "%s.run(): calling accept()", this );
|
||||
try {
|
||||
BluetoothSocket socket = serverSocket.accept(); // blocks
|
||||
BluetoothSocket socket = mServerSocket.accept(); // blocks
|
||||
Log.d( TAG, "%s.run(): accept() returned", this );
|
||||
ReadThread.handle( socket );
|
||||
} catch ( IOException ioe ) {
|
||||
Log.ex( TAG, ioe );
|
||||
serverSocket = null;
|
||||
mServerSocket = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1100,20 +1129,41 @@ public class BTUtils {
|
|||
ListenThread result = null;
|
||||
BluetoothAdapter adapter = getAdapterIf();
|
||||
if ( null != adapter ) {
|
||||
synchronized (sInstance) {
|
||||
result = (ListenThread)sInstance[0];
|
||||
synchronized ( sInstance ) {
|
||||
result = (ListenThread)sInstance.get();
|
||||
if ( null == result ) {
|
||||
sInstance[0] = result = new ListenThread( adapter );
|
||||
result = new ListenThread( adapter );
|
||||
Assert.assertTrueNR( result == sInstance.get() );
|
||||
result.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void stopSelf()
|
||||
{
|
||||
synchronized ( sInstance ) {
|
||||
ListenThread self = (ListenThread)sInstance.get();
|
||||
Log.d( TAG, "ListenThread.stopSelf(): self: %s", self );
|
||||
if ( null != self ) {
|
||||
sInstance.set( null );
|
||||
|
||||
BluetoothServerSocket serverSocket = self.mServerSocket;
|
||||
if ( null != serverSocket ) {
|
||||
try {
|
||||
serverSocket.close();
|
||||
} catch ( IOException ioe ) {
|
||||
Log.ex( TAG, ioe );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class ReadThread extends Thread {
|
||||
private static Thread[] sInstance = {null};
|
||||
private static AtomicReference<Thread> sInstance = new AtomicReference<>();
|
||||
private LinkedBlockingQueue<BluetoothSocket> mQueue;
|
||||
private BTMsgSink mBTMsgSink;
|
||||
|
||||
|
@ -1128,13 +1178,14 @@ public class BTUtils {
|
|||
{
|
||||
mQueue = new LinkedBlockingQueue<>();
|
||||
mBTMsgSink = new BTMsgSink();
|
||||
sInstance.set( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
Log.d( TAG, "ReadThread: %s.run() starting", this );
|
||||
for ( ; ; ) {
|
||||
while ( this == sInstance.get() ) {
|
||||
try {
|
||||
BluetoothSocket socket = mQueue.take();
|
||||
DataInputStream inStream =
|
||||
|
@ -1144,7 +1195,7 @@ public class BTUtils {
|
|||
BTInviteDelegate.onHeardFromDev( socket.getRemoteDevice() );
|
||||
parsePacket( proto, inStream, socket );
|
||||
updateStatusIn( true );
|
||||
TimerReceiver.restartBackoff( XWApp.getContext() );
|
||||
TimerReceiver.restartBackoff( getContext() );
|
||||
// nBadCount = 0;
|
||||
} else {
|
||||
writeBack( socket, BTCmd.BAD_PROTO );
|
||||
|
@ -1210,7 +1261,7 @@ public class BTUtils {
|
|||
case INVITE:
|
||||
NetLaunchInfo nli;
|
||||
if ( isOldProto ) {
|
||||
nli = NetLaunchInfo.makeFrom( XWApp.getContext(),
|
||||
nli = NetLaunchInfo.makeFrom( getContext(),
|
||||
dis.readUTF() );
|
||||
} else {
|
||||
data = new byte[dis.readShort()];
|
||||
|
@ -1258,7 +1309,7 @@ public class BTUtils {
|
|||
{
|
||||
Log.d( TAG, "receivePing()" );
|
||||
boolean deleted = 0 != gameID
|
||||
&& !DBUtils.haveGame( XWApp.getContext(), gameID );
|
||||
&& !DBUtils.haveGame( getContext(), gameID );
|
||||
|
||||
DataOutputStream os = new DataOutputStream( socket.getOutputStream() );
|
||||
os.writeByte( BTCmd.PONG.ordinal() );
|
||||
|
@ -1314,18 +1365,30 @@ public class BTUtils {
|
|||
{
|
||||
ReadThread result;
|
||||
synchronized ( sInstance ) {
|
||||
result = (ReadThread)sInstance[0];
|
||||
result = (ReadThread)sInstance.get();
|
||||
if ( null == result ) {
|
||||
sInstance[0] = result = new ReadThread();
|
||||
result = new ReadThread();
|
||||
Assert.assertTrueNR( result == sInstance.get() );
|
||||
result.start();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void stopSelf()
|
||||
{
|
||||
synchronized ( sInstance ) {
|
||||
ReadThread self = (ReadThread)sInstance.get();
|
||||
if ( null != self ) {
|
||||
sInstance.set( null );
|
||||
self.interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class BTMsgSink extends MultiMsgSink {
|
||||
public BTMsgSink() { super( XWApp.getContext() ); }
|
||||
public BTMsgSink() { super( getContext() ); }
|
||||
|
||||
@Override
|
||||
public int sendViaBluetooth( byte[] buf, String msgID, int gameID,
|
||||
|
@ -1348,7 +1411,7 @@ public class BTUtils {
|
|||
private CommsAddrRec mReturnAddr;
|
||||
private Context mContext;
|
||||
|
||||
private BTHelper() { super( XWApp.getContext() ); }
|
||||
private BTHelper() { super( BTUtils.getContext() ); }
|
||||
|
||||
BTHelper( CommsAddrRec from )
|
||||
{
|
||||
|
|
|
@ -819,7 +819,8 @@ public class DBUtils {
|
|||
return result;
|
||||
}
|
||||
|
||||
public static int getRelayGameCount( Context context ) {
|
||||
public static int getGameCountUsing( Context context, CommsConnType typ )
|
||||
{
|
||||
int result = 0;
|
||||
String[] columns = { DBHelper.CONTYPE };
|
||||
String selection = String.format( "%s = 0", DBHelper.GAME_OVER );
|
||||
|
@ -829,7 +830,7 @@ public class DBUtils {
|
|||
int indx = cursor.getColumnIndex( DBHelper.CONTYPE );
|
||||
while ( cursor.moveToNext() ) {
|
||||
CommsConnTypeSet typs = new CommsConnTypeSet( cursor.getInt(indx) );
|
||||
if ( typs.contains(CommsConnType.COMMS_CONN_RELAY) ) {
|
||||
if ( typs.contains( typ ) ) {
|
||||
++result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -776,7 +776,7 @@ public abstract class DelegateBase implements DlgClickNotify,
|
|||
XWPrefs.setNBSEnabled( m_activity, true );
|
||||
break;
|
||||
case ENABLE_BT_DO:
|
||||
BTUtils.enable();
|
||||
BTUtils.enable( m_activity );
|
||||
break;
|
||||
case ENABLE_RELAY_DO:
|
||||
RelayService.setEnabled( m_activity, true );
|
||||
|
|
|
@ -123,6 +123,7 @@ public class DlgDelegate {
|
|||
ENABLE_RELAY_DO,
|
||||
ENABLE_RELAY_DO_OR,
|
||||
DISABLE_RELAY_DO,
|
||||
DISABLE_BT_DO,
|
||||
ASKED_PHONE_STATE,
|
||||
PERMS_QUERY,
|
||||
PERMS_BANNED_INFO,
|
||||
|
|
|
@ -61,6 +61,7 @@ public class PrefsDelegate extends DelegateBase
|
|||
R.string.key_disable_nag,
|
||||
R.string.key_disable_nag_solo,
|
||||
R.string.key_disable_relay,
|
||||
R.string.key_disable_bt,
|
||||
R.string.key_force_tablet,
|
||||
R.string.key_mqtt_host,
|
||||
R.string.key_mqtt_port,
|
||||
|
@ -237,6 +238,9 @@ public class PrefsDelegate extends DelegateBase
|
|||
case R.string.key_disable_relay:
|
||||
RelayService.enabledChanged( m_activity );
|
||||
break;
|
||||
case R.string.key_disable_bt:
|
||||
BTUtils.disabledChanged( m_activity );
|
||||
break;
|
||||
case R.string.key_force_tablet:
|
||||
makeOkOnlyBuilder( R.string.after_restart ).show();
|
||||
break;
|
||||
|
@ -265,6 +269,10 @@ public class PrefsDelegate extends DelegateBase
|
|||
RelayService.setEnabled( m_activity, false );
|
||||
RelayCheckBoxPreference.setChecked();
|
||||
break;
|
||||
case DISABLE_BT_DO:
|
||||
BTUtils.setEnabled( m_activity, false );
|
||||
BTCheckBoxPreference.setChecked();
|
||||
break;
|
||||
default:
|
||||
handled = super.onPosButton( action, params );
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ import android.util.AttributeSet;
|
|||
import java.lang.ref.WeakReference;
|
||||
|
||||
import org.eehouse.android.xw4.DlgDelegate.Action;
|
||||
import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnType;
|
||||
import org.eehouse.android.xw4.loc.LocUtils;
|
||||
|
||||
public class RelayCheckBoxPreference extends ConfirmingCheckBoxPreference {
|
||||
|
@ -45,7 +46,8 @@ public class RelayCheckBoxPreference extends ConfirmingCheckBoxPreference {
|
|||
String msg = LocUtils.getString( activity,
|
||||
R.string.warn_relay_havegames );
|
||||
|
||||
int count = DBUtils.getRelayGameCount( activity );
|
||||
int count = DBUtils
|
||||
.getGameCountUsing( activity, CommsConnType.COMMS_CONN_RELAY );
|
||||
if ( 0 < count ) {
|
||||
msg += LocUtils.getQuantityString( activity, R.plurals.warn_relay_games_fmt,
|
||||
count, count );
|
||||
|
|
|
@ -161,6 +161,18 @@ public class XWPrefs {
|
|||
return enabled;
|
||||
}
|
||||
|
||||
public static boolean getBTDisabled( Context context )
|
||||
{
|
||||
boolean disabled = getPrefsBoolean( context, R.string.key_disable_bt,
|
||||
false );
|
||||
return disabled;
|
||||
}
|
||||
|
||||
public static void setBTDisabled( Context context, boolean disabled )
|
||||
{
|
||||
setPrefsBoolean( context, R.string.key_disable_bt, disabled );
|
||||
}
|
||||
|
||||
public static boolean getSkipToWebAPI( Context context )
|
||||
{
|
||||
return getPrefsBoolean( context, R.string.key_relay_via_http_first, false );
|
||||
|
|
|
@ -68,6 +68,7 @@
|
|||
<string name="key_default_timerenabled">key_default_timerenabled</string>
|
||||
<string name="key_notify_sound">key_notify_sound</string>
|
||||
<string name="key_disable_relay">key_disable_relay</string>
|
||||
<string name="key_disable_bt">key_disable_bt</string>
|
||||
<string name="key_notify_vibrate">key_notify_vibrate</string>
|
||||
<string name="key_enable_nbs">key_enable_nbs</string>
|
||||
<string name="key_enable_p2p">key_enable_p2p</string>
|
||||
|
|
|
@ -967,6 +967,8 @@
|
|||
networked games</string>
|
||||
<string name="disable_relay">Disable play via the relay </string>
|
||||
<string name="disable_relay_summary">Disable all internet communication</string>
|
||||
<string name="disable_bt">Disable play via Bluetooth</string>
|
||||
<string name="disable_bt_summary">Disable all Bluetooth communication</string>
|
||||
<!--
|
||||
############################################################
|
||||
# :Screens:
|
||||
|
@ -1874,9 +1876,9 @@
|
|||
disabled. No moves will be sent via Data SMS.\n\nYou can enable
|
||||
play via Data SMS now, or later.
|
||||
</string>
|
||||
<string name="warn_bt_disabled">Bluetooth is currently off on this
|
||||
device. No moves will be sent via Bluetooth.\n\nYou can enable
|
||||
Bluetooth now, or later.
|
||||
<string name="warn_bt_disabled">Bluetooth play is currently
|
||||
disabled, and no moves will be exchanged via Bluetooth until it is
|
||||
enabled.\n\nYou can enable Bluetooth now, or later.
|
||||
</string>
|
||||
<string name="warn_relay_disabled">Relay play is currently disable
|
||||
on this device. No moves will be sent or received via the
|
||||
|
@ -1891,14 +1893,26 @@
|
|||
Most networked games exchange moves via the relay, so only do this
|
||||
if you plan to play ALL games against a robot on this same
|
||||
device.</string>
|
||||
<string name="warn_bt_havegames">Are you sure you want to
|
||||
disable play using Bluetooth?
|
||||
\n\nBluetooth is useful for exchanging moves, and especially
|
||||
invitations, with devices physically close to you. Unless you’re
|
||||
certain you won’t play against anybody nearby there’s little harm
|
||||
in leaving it on.
|
||||
</string>
|
||||
<plurals name="warn_relay_games_fmt">
|
||||
<item quantity="one">\n\n(You have one active game using the relay now.)</item>
|
||||
<item quantity="other">\n\n(You have %1$d active games using the relay now.)</item>
|
||||
</plurals>
|
||||
<plurals name="warn_bt_games_fmt">
|
||||
<item quantity="one">\n\n(You have one active game using Bluetooth.)</item>
|
||||
<item quantity="other">\n\n(You have %1$d active games using Bluetooth.)</item>
|
||||
</plurals>
|
||||
<string name="button_enable_sms">Enable Data SMS</string>
|
||||
<string name="button_enable_bt">Enable Bluetooth</string>
|
||||
<string name="button_enable_relay">Enable Relay play</string>
|
||||
<string name="button_disable_relay">Disable Relay play</string>
|
||||
<string name="button_disable_bt">Disable Bluetooth play</string>
|
||||
<string name="button_later">Later</string>
|
||||
<!-- -->
|
||||
<string name="gamel_menu_checkupdates">Check for updates</string>
|
||||
|
|
|
@ -369,6 +369,13 @@
|
|||
android:defaultValue="false"
|
||||
/>
|
||||
|
||||
<org.eehouse.android.xw4.BTCheckBoxPreference
|
||||
android:key="@string/key_disable_bt"
|
||||
android:title="@string/disable_bt"
|
||||
android:summary="@string/disable_bt_summary"
|
||||
android:defaultValue="false"
|
||||
/>
|
||||
|
||||
</PreferenceScreen>
|
||||
|
||||
<!-- For Debugging -->
|
||||
|
|
Loading…
Reference in a new issue