mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-01-07 05:24:46 +01:00
use NBSProxy if available
Lots of work dealing with banned permissions (SEND_SMS and RECEIVE_SMS). First, if they're banned and NBSProxy is installed, just use it as if the permissions had been granted. When it's not there, explain at various points where users will otherwise be confused: when they try to invite using data sms, or when they open a game that already uses it.)
This commit is contained in:
parent
c59e86b724
commit
5bdc473e02
25 changed files with 445 additions and 170 deletions
|
@ -47,6 +47,8 @@ android {
|
|||
// variant.buildConfigField "String", "FIELD_NAME", "\"my String\""
|
||||
variant.buildConfigField "String", "FABRIC_API_KEY", "\"$FABRIC_API_KEY\""
|
||||
|
||||
// We need both of these because xwprefs.xml can't reference
|
||||
// the BuildConfig constant
|
||||
resValue "string", "git_rev", "$GITREV"
|
||||
variant.buildConfigField "String", "GIT_REV", "\"$GITREV\""
|
||||
|
||||
|
@ -68,9 +70,9 @@ android {
|
|||
buildConfigField "String", "BUILD_INFO_NAME", "\"${BUILD_INFO_NAME}\""
|
||||
buildConfigField "boolean", "IS_TAGGED_BUILD", "${CURTAG}" == '' ? "false" : "true"
|
||||
resValue "string", "invite_prefix", "/and/"
|
||||
buildConfigField "int[]", "SMS_BANNED_EXPL", "null"
|
||||
buildConfigField "boolean", "UDP_ENABLED", "true"
|
||||
buildConfigField "boolean", "REPORT_LOCKS", "false"
|
||||
buildConfigField "boolean", "SMS_BANNED", "false"
|
||||
buildConfigField "boolean", "UDP_ENABLED", "true"
|
||||
buildConfigField "boolean", "REPORT_LOCKS", "false"
|
||||
}
|
||||
|
||||
xw4 {
|
||||
|
@ -82,8 +84,7 @@ android {
|
|||
buildConfigField "boolean", "WIDIR_ENABLED", "false"
|
||||
buildConfigField "boolean", "RELAYINVITE_SUPPORTED", "false"
|
||||
buildConfigField "String", "VARIANT_NAME", "\"Google Play Store\""
|
||||
buildConfigField "int[]", "SMS_BANNED_EXPL", "null"
|
||||
// "{R.string.key_notagain_sms_banned, R.string.sms_banned_expl}"
|
||||
buildConfigField "boolean", "SMS_BANNED", "false"
|
||||
}
|
||||
|
||||
xw4fdroid {
|
||||
|
@ -117,8 +118,7 @@ android {
|
|||
buildConfigField "boolean", "WIDIR_ENABLED", "true"
|
||||
buildConfigField "boolean", "RELAYINVITE_SUPPORTED", "true"
|
||||
buildConfigField "String", "VARIANT_NAME", "\"Dev/Debug sans SMS\""
|
||||
buildConfigField "int[]", "SMS_BANNED_EXPL", "null"
|
||||
// "{R.string.key_notagain_sms_banned, R.string.sms_banned_expl}"
|
||||
buildConfigField "boolean", "SMS_BANNED", "true"
|
||||
}
|
||||
|
||||
// WARNING: "all" breaks things. Seems to be a keyword. Need
|
||||
|
@ -246,7 +246,7 @@ dependencies {
|
|||
implementation 'com.google.firebase:firebase-messaging:17.3.4' // rm-for-fdroid
|
||||
implementation 'com.google.firebase:firebase-core:16.0.6' // rm-for-fdroid
|
||||
|
||||
implementation 'com.github.eehouse:nbsproxy:v0.0.2'
|
||||
implementation 'com.github.eehouse:nbsproxy:v0.0.5'
|
||||
}
|
||||
|
||||
task mkImages(type: Exec) {
|
||||
|
|
|
@ -46,10 +46,8 @@ import java.io.Serializable;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
import org.eehouse.android.xw4.DBUtils.SentInvitesInfo;
|
||||
import org.eehouse.android.xw4.DlgDelegate.Action;
|
||||
import org.eehouse.android.xw4.DlgDelegate.ActionPair;
|
||||
|
@ -147,6 +145,16 @@ public class BoardDelegate extends DelegateBase
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// Quick hack to manage a series of alerts meant to be presented
|
||||
// one-at-a-time in order. Each tests whether it's its turn, and if so
|
||||
// checks its conditions for being shown (e.g. NO_MEANS for no way to
|
||||
// communicate). If the conditions aren't met (no need to show alert), it
|
||||
// just sets the StartAlertOrder ivar to the next value and
|
||||
// exits. Otherwise it needs to ensure that however the alert it's posting
|
||||
// exits that ivar is incremented as well.
|
||||
private static enum StartAlertOrder { NBS_PERMS, NO_MEANS, INVITE, DONE, };
|
||||
|
||||
private static class MySIS implements Serializable {
|
||||
MySIS() { nMissing = -1; }
|
||||
String toastStr;
|
||||
|
@ -155,9 +163,22 @@ public class BoardDelegate extends DelegateBase
|
|||
int nMissing;
|
||||
int nAlerts;
|
||||
boolean inTrade;
|
||||
StartAlertOrder mAlertOrder = StartAlertOrder.values()[0];
|
||||
}
|
||||
private MySIS m_mySIS;
|
||||
|
||||
private boolean alertOrderAt( StartAlertOrder ord )
|
||||
{
|
||||
return m_mySIS.mAlertOrder == ord;
|
||||
}
|
||||
|
||||
private void alertOrderIncrIfAt( StartAlertOrder ord )
|
||||
{
|
||||
if ( alertOrderAt( ord ) ) {
|
||||
m_mySIS.mAlertOrder = ord.values()[ord.ordinal() + 1];
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Dialog makeDialog( DBAlert alert, Object[] params )
|
||||
{
|
||||
|
@ -694,6 +715,7 @@ public class BoardDelegate extends DelegateBase
|
|||
setBackgroundColor();
|
||||
setKeepScreenOn();
|
||||
} else {
|
||||
warnIfNoTransport();
|
||||
showInviteAlertIf();
|
||||
}
|
||||
}
|
||||
|
@ -1063,6 +1085,7 @@ public class BoardDelegate extends DelegateBase
|
|||
deleteAndClose();
|
||||
break;
|
||||
case DROP_SMS_ACTION: // do nothing; work done in onNegButton case
|
||||
alertOrderIncrIfAt( StartAlertOrder.NBS_PERMS );
|
||||
break;
|
||||
|
||||
case INVITE_SMS_DATA:
|
||||
|
@ -1157,6 +1180,20 @@ public class BoardDelegate extends DelegateBase
|
|||
case ASKED_PHONE_STATE:
|
||||
showInviteChoicesThen( params );
|
||||
break;
|
||||
case INVITE_SMS_DATA:
|
||||
Perms23.Perm[] perms = (Perms23.Perm[])params[2];
|
||||
if ( Perms23.bannedWithWorkaround( m_activity, perms ) ) {
|
||||
int nMissing = (Integer)params[0];
|
||||
SentInvitesInfo info = (SentInvitesInfo)params[1];
|
||||
launchPhoneNumberInvite( nMissing, info, InviteMeans.SMS_DATA,
|
||||
RequestCode.SMS_DATA_INVITE_RESULT );
|
||||
} else if ( Perms23.anyBanned( perms ) ) {
|
||||
makeOkOnlyBuilder( R.string.sms_banned_ok_only )
|
||||
.setActionPair(new ActionPair( Action.PERMS_BANNED_INFO,
|
||||
R.string.button_more_info ) )
|
||||
.show();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
handled = super.onNegButton( action, params );
|
||||
}
|
||||
|
@ -1222,10 +1259,10 @@ public class BoardDelegate extends DelegateBase
|
|||
RequestCode.BT_INVITE_RESULT );
|
||||
break;
|
||||
case SMS_DATA:
|
||||
Perms23.tryGetPerms( this, new Perm[] { Perm.SEND_SMS,
|
||||
Perm.RECEIVE_SMS },
|
||||
R.string.sms_invite_rationale,
|
||||
Action.INVITE_SMS_DATA, m_mySIS.nMissing, info );
|
||||
Perm[] perms = { Perm.SEND_SMS, Perm.RECEIVE_SMS };
|
||||
Perms23.tryGetPerms( this, perms, R.string.sms_invite_rationale,
|
||||
Action.INVITE_SMS_DATA, m_mySIS.nMissing,
|
||||
info, perms );
|
||||
break;
|
||||
case SMS_USER: // like an email invite, but we want the phone #
|
||||
launchPhoneNumberInvite( m_mySIS.nMissing, info, means,
|
||||
|
@ -2211,7 +2248,7 @@ public class BoardDelegate extends DelegateBase
|
|||
|
||||
Utils.cancelNotification( m_activity, (int)m_rowid );
|
||||
|
||||
askPermissions();
|
||||
askNBSPermissions();
|
||||
|
||||
if ( m_gi.serverRole != DeviceRole.SERVER_STANDALONE ) {
|
||||
warnIfNoTransport();
|
||||
|
@ -2221,23 +2258,51 @@ public class BoardDelegate extends DelegateBase
|
|||
}
|
||||
} // resumeGame
|
||||
|
||||
private void askPermissions()
|
||||
private void askNBSPermissions()
|
||||
{
|
||||
if ( m_summary.conTypes.contains( CommsConnType.COMMS_CONN_SMS )
|
||||
&& null == m_permCbck ) { // already asked?
|
||||
m_permCbck = new Perms23.PermCbck() {
|
||||
@Override
|
||||
public void onPermissionResult( Map<Perm, Boolean> perms ) {
|
||||
if ( ! perms.get(Perm.SEND_SMS) ) {
|
||||
makeConfirmThenBuilder( R.string.missing_perms,
|
||||
Action.DROP_SMS_ACTION )
|
||||
.setNegButton(R.string.remove_sms)
|
||||
.show();
|
||||
final StartAlertOrder thisOrder = StartAlertOrder.NBS_PERMS;
|
||||
if ( alertOrderAt( thisOrder ) // already asked?
|
||||
&& m_summary.conTypes.contains( CommsConnType.COMMS_CONN_SMS ) ) {
|
||||
Perm[] nbsPerms = { Perm.SEND_SMS, Perm.RECEIVE_SMS };
|
||||
if ( Perms23.havePermissions( m_activity, nbsPerms ) ) {
|
||||
// We have them or a workaround; cool! proceed
|
||||
alertOrderIncrIfAt( thisOrder );
|
||||
} else {
|
||||
// Make sure these can be treated the same!!!
|
||||
Assert.assertTrue( nbsPerms.length == 2 &&
|
||||
nbsPerms[0].isBanned() == nbsPerms[1].isBanned() );
|
||||
|
||||
m_permCbck = new Perms23.PermCbck() {
|
||||
@Override
|
||||
public void onPermissionResult( boolean allGood,
|
||||
Map<Perm, Boolean> perms )
|
||||
{
|
||||
if ( allGood ) {
|
||||
// Yay! nothing to do
|
||||
alertOrderIncrIfAt( thisOrder );
|
||||
} else {
|
||||
Log.d( TAG, "askNBSPermissions(): posting alert" );
|
||||
boolean banned = Perm.SEND_SMS.isBanned();
|
||||
int explID = banned
|
||||
? R.string.banned_nbs_perms : R.string.missing_sms_perms;
|
||||
DlgDelegate.ConfirmThenBuilder builder =
|
||||
makeConfirmThenBuilder( explID, Action.DROP_SMS_ACTION );
|
||||
if ( banned ) {
|
||||
ActionPair pr = new ActionPair( Action.PERMS_BANNED_INFO,
|
||||
R.string.button_more_info );
|
||||
builder.setActionPair( pr );
|
||||
}
|
||||
builder.setNegButton( R.string.remove_sms )
|
||||
.show();
|
||||
Log.d( TAG, "askNBSPermissions(): DONE posting alert" );
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
new Perms23.Builder(Perm.SEND_SMS)
|
||||
.asyncQuery( m_activity, m_permCbck );
|
||||
};
|
||||
new Perms23.Builder( nbsPerms )
|
||||
.asyncQuery( m_activity, m_permCbck );
|
||||
}
|
||||
} else {
|
||||
alertOrderIncrIfAt( thisOrder );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2385,17 +2450,21 @@ public class BoardDelegate extends DelegateBase
|
|||
private void showInviteAlertIf()
|
||||
{
|
||||
DbgUtils.assertOnUIThread();
|
||||
if ( ! m_haveStartedShowing && null == m_inviteAlert
|
||||
&& m_mySIS.nMissing > 0 && !isFinishing() ) {
|
||||
InviteAlertState ias = new InviteAlertState();
|
||||
ias.summary = m_summary;
|
||||
ias.gi = m_gi;
|
||||
ias.relayMissing = m_relayMissing;
|
||||
ias.connTypes = m_connTypes;
|
||||
ias.rowid = m_rowid;
|
||||
ias.nMissing = m_mySIS.nMissing;
|
||||
showDialogFragment( DlgID.DLG_INVITE, ias );
|
||||
m_haveStartedShowing = true;
|
||||
if ( alertOrderAt( StartAlertOrder.INVITE ) ) {
|
||||
if ( ! m_haveStartedShowing && null == m_inviteAlert
|
||||
&& m_mySIS.nMissing > 0 && !isFinishing() ) {
|
||||
InviteAlertState ias = new InviteAlertState();
|
||||
ias.summary = m_summary;
|
||||
ias.gi = m_gi;
|
||||
ias.relayMissing = m_relayMissing;
|
||||
ias.connTypes = m_connTypes;
|
||||
ias.rowid = m_rowid;
|
||||
ias.nMissing = m_mySIS.nMissing;
|
||||
showDialogFragment( DlgID.DLG_INVITE, ias );
|
||||
m_haveStartedShowing = true;
|
||||
} else {
|
||||
alertOrderIncrIfAt( StartAlertOrder.INVITE );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2455,24 +2524,32 @@ public class BoardDelegate extends DelegateBase
|
|||
|
||||
private void warnIfNoTransport()
|
||||
{
|
||||
if ( m_connTypes.contains( CommsConnType.COMMS_CONN_SMS ) ) {
|
||||
if ( !XWPrefs.getNBSEnabled( m_activity ) ) {
|
||||
makeConfirmThenBuilder( R.string.warn_sms_disabled,
|
||||
Action.ENABLE_NBS_ASK )
|
||||
.setPosButton( R.string.button_enable_sms )
|
||||
.setNegButton( R.string.button_later )
|
||||
.show();
|
||||
if ( alertOrderAt( StartAlertOrder.NO_MEANS ) ) {
|
||||
if ( m_connTypes.contains( CommsConnType.COMMS_CONN_SMS ) ) {
|
||||
if ( !XWPrefs.getNBSEnabled( m_activity ) ) {
|
||||
makeConfirmThenBuilder( R.string.warn_sms_disabled,
|
||||
Action.ENABLE_NBS_ASK )
|
||||
.setPosButton( R.string.button_enable_sms )
|
||||
.setNegButton( R.string.button_later )
|
||||
.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( m_connTypes.contains( CommsConnType.COMMS_CONN_RELAY ) ) {
|
||||
if ( !RelayService.relayEnabled( m_activity ) ) {
|
||||
m_dropRelayOnDismiss = false;
|
||||
String msg = getString( R.string.warn_relay_disabled )
|
||||
+ "\n\n" + getString( R.string.warn_relay_remove );
|
||||
makeConfirmThenBuilder( msg, Action.ENABLE_RELAY_DO_OR )
|
||||
.setPosButton( R.string.button_enable_relay )
|
||||
.setNegButton( R.string.newgame_drop_relay )
|
||||
.show();
|
||||
if ( m_connTypes.contains( CommsConnType.COMMS_CONN_RELAY ) ) {
|
||||
if ( !RelayService.relayEnabled( m_activity ) ) {
|
||||
m_dropRelayOnDismiss = false;
|
||||
String msg = getString( R.string.warn_relay_disabled )
|
||||
+ "\n\n" + getString( R.string.warn_relay_remove );
|
||||
makeConfirmThenBuilder( msg, Action.ENABLE_RELAY_DO_OR )
|
||||
.setPosButton( R.string.button_enable_relay )
|
||||
.setNegButton( R.string.newgame_drop_relay )
|
||||
.show();
|
||||
}
|
||||
}
|
||||
|
||||
if ( m_connTypes.isEmpty() ) {
|
||||
askNoAddrsDelete();
|
||||
} else {
|
||||
alertOrderIncrIfAt( StartAlertOrder.NO_MEANS );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -433,7 +433,8 @@ public class DBUtils {
|
|||
return result;
|
||||
}
|
||||
|
||||
public static int countOpenGamesUsingRelay( Context context )
|
||||
private static int countOpenGamesUsing( Context context,
|
||||
CommsConnType connTyp )
|
||||
{
|
||||
int result = 0;
|
||||
String[] columns = { DBHelper.CONTYPE };
|
||||
|
@ -446,16 +447,28 @@ 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( connTyp ) ) {
|
||||
++result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
// Log.d( TAG, "countOpenGamesUsingRelay() => %d", result );
|
||||
// Log.d( TAG, "countOpenGamesUsing(%s) => %d", connTyp, result );
|
||||
return result;
|
||||
}
|
||||
|
||||
public static int countOpenGamesUsingRelay( Context context )
|
||||
{
|
||||
int result = countOpenGamesUsing( context, CommsConnType.COMMS_CONN_RELAY );
|
||||
return result;
|
||||
}
|
||||
|
||||
public static int countOpenGamesUsingNBS( Context context )
|
||||
{
|
||||
int result = countOpenGamesUsing( context, CommsConnType.COMMS_CONN_SMS );
|
||||
// Log.d( TAG, "countOpenGamesUsingNBS() => %d", result );
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -755,6 +755,9 @@ public class DelegateBase implements DlgClickNotify,
|
|||
case PERMS_QUERY:
|
||||
Perms23.onGotPermsAction( this, true, params );
|
||||
break;
|
||||
case PERMS_BANNED_INFO:
|
||||
NetUtils.launchWebBrowserWith( m_activity, R.string.nbs_ban_url );
|
||||
break;
|
||||
default:
|
||||
Log.d( TAG, "unhandled action %s", action.toString() );
|
||||
// Assert.assertTrue( !BuildConfig.DEBUG );
|
||||
|
|
|
@ -181,7 +181,8 @@ public class DictUtils {
|
|||
// Note: if STORAGE permission is changed the set being returned here
|
||||
// will change. Might want to check for that and invalidate this list
|
||||
// if it's changed.
|
||||
boolean haveStorage = Perms23.havePermission( Perms23.Perm.STORAGE );
|
||||
boolean haveStorage = Perms23.havePermissions( context,
|
||||
Perms23.Perm.STORAGE );
|
||||
boolean permsChanged = null == s_hadStorage
|
||||
|| haveStorage != s_hadStorage;
|
||||
|
||||
|
|
|
@ -124,11 +124,12 @@ public class DlgDelegate {
|
|||
DISABLE_RELAY_DO,
|
||||
ASKED_PHONE_STATE,
|
||||
PERMS_QUERY,
|
||||
PERMS_BANNED_INFO,
|
||||
|
||||
// Sent when not-again checkbox checked
|
||||
SET_NA_DEFAULTNAME,
|
||||
SET_GOT_LANGDICT,
|
||||
}
|
||||
} // Action enum
|
||||
|
||||
public static class ActionPair implements Serializable {
|
||||
public ActionPair( Action act, int str ) {
|
||||
|
|
|
@ -44,7 +44,6 @@ import android.widget.LinearLayout;
|
|||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
|
||||
|
||||
import org.eehouse.android.xw4.DBUtils.GameChangeType;
|
||||
import org.eehouse.android.xw4.DBUtils.GameGroupInfo;
|
||||
import org.eehouse.android.xw4.DBUtils.SentInvitesInfo;
|
||||
|
@ -944,6 +943,7 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
@Override
|
||||
protected void init( Bundle savedInstanceState )
|
||||
{
|
||||
boolean isFirstLaunch = null == savedInstanceState;
|
||||
m_origTitle = getTitle();
|
||||
|
||||
m_handler = new Handler();
|
||||
|
@ -995,8 +995,12 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
// asking (OS will grant without user interaction) since they're in
|
||||
// the same group. So just do it now. This code can be removed
|
||||
// later...
|
||||
if ( Perms23.havePermission( Perm.SEND_SMS ) ) {
|
||||
Perms23.tryGetPerms( this, Perm.RECEIVE_SMS, 0, Action.SKIP_CALLBACK );
|
||||
if ( !Perm.RECEIVE_SMS.isBanned() ) {
|
||||
if ( Perms23.havePermissions( m_activity, Perm.SEND_SMS ) ) {
|
||||
Perms23.tryGetPerms( this, Perm.RECEIVE_SMS, 0, Action.SKIP_CALLBACK );
|
||||
}
|
||||
} else if ( isFirstLaunch ) {
|
||||
warnSMSBannedIf();
|
||||
}
|
||||
} // init
|
||||
|
||||
|
@ -1060,6 +1064,23 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
}
|
||||
}
|
||||
|
||||
private void warnSMSBannedIf()
|
||||
{
|
||||
if ( !Perms23.havePermissions( m_activity, Perm.SEND_SMS, Perm.RECEIVE_SMS )
|
||||
&& Perm.SEND_SMS.isBanned() ) {
|
||||
int smsGameCount = DBUtils.countOpenGamesUsingNBS( m_activity );
|
||||
if ( 0 < smsGameCount ) {
|
||||
String msg = LocUtils.getString( m_activity,
|
||||
R.string.not_again_nbsGamesOnUpgrade,
|
||||
smsGameCount );
|
||||
makeNotAgainBuilder( msg, R.string.key_notagain_nbsGamesOnUpgrade )
|
||||
.setActionPair( new ActionPair( Action.PERMS_BANNED_INFO,
|
||||
R.string.button_more_info ) )
|
||||
.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void moveGroup( long groupID, boolean moveUp )
|
||||
{
|
||||
m_adapter.moveGroup( groupID, moveUp );
|
||||
|
@ -1448,8 +1469,7 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
showItemsIf( ONEGAME_ITEMS, menu, 1 == nGamesSelected );
|
||||
showItemsIf( ONEGROUP_ITEMS, menu, 1 == nGroupsSelected );
|
||||
|
||||
boolean enable = showDbg && nothingSelected
|
||||
&& UpdateCheckReceiver.haveToCheck( m_activity );
|
||||
boolean enable = showDbg && nothingSelected;
|
||||
Utils.setItemVisible( menu, R.id.games_menu_checkupdates, enable );
|
||||
|
||||
int selGroupPos = -1;
|
||||
|
|
|
@ -21,9 +21,10 @@
|
|||
package org.eehouse.android.xw4;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.text.TextUtils;
|
||||
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
@ -203,6 +204,18 @@ public class NetUtils {
|
|||
return result;
|
||||
}
|
||||
|
||||
public static void launchWebBrowserWith( Context context, int uriResID )
|
||||
{
|
||||
String uri = context.getString( uriResID );
|
||||
launchWebBrowserWith( context, uri );
|
||||
}
|
||||
|
||||
public static void launchWebBrowserWith( Context context, String uri )
|
||||
{
|
||||
Intent intent = new Intent( Intent.ACTION_VIEW, Uri.parse(uri) );
|
||||
context.startActivity( intent );
|
||||
}
|
||||
|
||||
protected static HttpsURLConnection makeHttpsRelayConn( Context context,
|
||||
String proc )
|
||||
{
|
||||
|
|
|
@ -35,6 +35,8 @@ import java.util.Iterator;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eehouse.android.nbsplib.NBSProxy;
|
||||
|
||||
import org.eehouse.android.xw4.DlgDelegate.Action;
|
||||
import org.eehouse.android.xw4.DlgDelegate.DlgClickNotify;
|
||||
import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnType;
|
||||
|
@ -47,21 +49,20 @@ public class Perms23 {
|
|||
public static enum Perm {
|
||||
READ_PHONE_STATE(Manifest.permission.READ_PHONE_STATE),
|
||||
STORAGE(Manifest.permission.WRITE_EXTERNAL_STORAGE),
|
||||
SEND_SMS(Manifest.permission.SEND_SMS, BuildConfig.SMS_BANNED_EXPL),
|
||||
RECEIVE_SMS(Manifest.permission.RECEIVE_SMS, BuildConfig.SMS_BANNED_EXPL),
|
||||
SEND_SMS(Manifest.permission.SEND_SMS, BuildConfig.SMS_BANNED),
|
||||
RECEIVE_SMS(Manifest.permission.RECEIVE_SMS, BuildConfig.SMS_BANNED),
|
||||
READ_CONTACTS(Manifest.permission.READ_CONTACTS);
|
||||
|
||||
private String m_str;
|
||||
private int[] m_expl;
|
||||
private Perm(String str) { this(str, null); }
|
||||
private Perm(String str, int[] bannedExpl) {
|
||||
private boolean m_banned;
|
||||
private Perm(String str) { this(str, false); }
|
||||
private Perm(String str, boolean banned) {
|
||||
m_str = str;
|
||||
m_expl = bannedExpl;
|
||||
m_banned = banned;
|
||||
}
|
||||
|
||||
public String getString() { return m_str; }
|
||||
public boolean isBanned() { return m_expl != null; }
|
||||
public int[] getExpl() { Assert.assertTrue(isBanned()); return m_expl; }
|
||||
public boolean isBanned() { return m_banned; }
|
||||
public static Perm getFor( String str ) {
|
||||
Perm result = null;
|
||||
for ( Perm one : Perm.values() ) {
|
||||
|
@ -75,7 +76,7 @@ public class Perms23 {
|
|||
}
|
||||
|
||||
public interface PermCbck {
|
||||
void onPermissionResult( Map<Perm, Boolean> perms );
|
||||
void onPermissionResult( boolean allGood, Map<Perm, Boolean> perms );
|
||||
}
|
||||
public interface OnShowRationale {
|
||||
void onShouldShowRationale( Set<Perm> perms );
|
||||
|
@ -89,21 +90,12 @@ public class Perms23 {
|
|||
m_perms.addAll( perms );
|
||||
}
|
||||
|
||||
public Builder( Perm[] perms ) {
|
||||
public Builder( Perm... perms ) {
|
||||
for ( Perm perm : perms ) {
|
||||
m_perms.add( perm );
|
||||
}
|
||||
}
|
||||
|
||||
public Builder( Perm perm ) {
|
||||
m_perms.add( perm );
|
||||
}
|
||||
|
||||
public Builder add( Perm perm ) {
|
||||
m_perms.add( perm );
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setOnShowRationale( OnShowRationale onShow )
|
||||
{
|
||||
m_onShow = onShow;
|
||||
|
@ -115,6 +107,11 @@ public class Perms23 {
|
|||
asyncQuery( activity, null );
|
||||
}
|
||||
|
||||
// We have set of permissions. For any of them that needs asking (not
|
||||
// granted AND not banned) start an ask.
|
||||
//
|
||||
// PENDING: I suspect this'll crash if I ask for a banned and
|
||||
// non-banned at the same time (and don't have either)
|
||||
public void asyncQuery( Activity activity, PermCbck cbck )
|
||||
{
|
||||
Log.d( TAG, "asyncQuery(%s)", m_perms.toString() );
|
||||
|
@ -125,10 +122,13 @@ public class Perms23 {
|
|||
ArrayList<String> askStrings = new ArrayList<String>();
|
||||
for ( Perm perm : m_perms ) {
|
||||
String permStr = perm.getString();
|
||||
boolean haveIt = PackageManager.PERMISSION_GRANTED
|
||||
boolean haveIt = perm.isBanned() || PackageManager.PERMISSION_GRANTED
|
||||
== ContextCompat.checkSelfPermission( activity, permStr );
|
||||
|
||||
if ( !haveIt ) {
|
||||
// do not pass banned perms to the OS! They're not in
|
||||
// AndroidManifest.xml so may crash on some devices
|
||||
Assert.assertFalse( perm.isBanned() );
|
||||
askStrings.add( permStr );
|
||||
|
||||
if ( null != m_onShow && ActivityCompat
|
||||
|
@ -144,10 +144,13 @@ public class Perms23 {
|
|||
if ( haveAll ) {
|
||||
if ( null != cbck ) {
|
||||
Map<Perm, Boolean> map = new HashMap<>();
|
||||
boolean allGood = true;
|
||||
for ( Perm perm : m_perms ) {
|
||||
map.put( perm, true );
|
||||
boolean banned = perm.isBanned();
|
||||
map.put( perm, !banned );
|
||||
allGood = allGood & !banned;
|
||||
}
|
||||
cbck.onPermissionResult( map );
|
||||
cbck.onPermissionResult( allGood, map );
|
||||
}
|
||||
} else if ( 0 < needShow.size() && null != m_onShow ) {
|
||||
// Log.d( TAG, "calling onShouldShowRationale()" );
|
||||
|
@ -228,18 +231,10 @@ public class Perms23 {
|
|||
}
|
||||
builder.asyncQuery( m_delegate.getActivity(), new PermCbck() {
|
||||
@Override
|
||||
public void onPermissionResult( Map<Perm, Boolean> permsMap ) {
|
||||
public void onPermissionResult( boolean allGood,
|
||||
Map<Perm, Boolean> permsMap ) {
|
||||
if ( Action.SKIP_CALLBACK != m_action ) {
|
||||
|
||||
// We need all the sought perms to have been granted
|
||||
boolean allGranted = true;
|
||||
Iterator<Perm> iter = permsMap.keySet().iterator();
|
||||
while ( allGranted && iter.hasNext() ) {
|
||||
Perm perm = iter.next();
|
||||
allGranted = allGranted && permsMap.get( perm );
|
||||
}
|
||||
|
||||
if ( allGranted ) {
|
||||
if ( allGood ) {
|
||||
m_delegate.onPosButton( m_action, m_params );
|
||||
} else {
|
||||
m_delegate.onNegButton( m_action, m_params );
|
||||
|
@ -252,16 +247,11 @@ public class Perms23 {
|
|||
// Cons up a call with a "no" answer, and post it.
|
||||
private void doItFail( Set<Perm> bannedPerms )
|
||||
{
|
||||
int resID = 0;
|
||||
|
||||
final Perm[] perms = bannedPerms.toArray( new Perm[bannedPerms.size()] );
|
||||
int[] expls = perms[0].getExpl();
|
||||
m_delegate.makeNotAgainBuilder(expls[1], expls[0]).show();
|
||||
|
||||
m_delegate.post( new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
m_delegate.onNegButton( m_action, perms );
|
||||
Log.d( TAG, "doItFail(); passing perms to onNegButton(%s)", m_action );
|
||||
m_delegate.onNegButton( m_action, m_params );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
@ -338,11 +328,14 @@ public class Perms23 {
|
|||
String[] perms, int[] granteds )
|
||||
{
|
||||
// Log.d( TAG, "gotPermissionResult(%s)", perms.toString() );
|
||||
Map<Perm, Boolean> result = new HashMap<Perm, Boolean>();
|
||||
Map<Perm, Boolean> result = new HashMap<>();
|
||||
boolean shouldResend = false;
|
||||
boolean allGood = true;
|
||||
for ( int ii = 0; ii < perms.length; ++ii ) {
|
||||
Perm perm = Perm.getFor( perms[ii] );
|
||||
Assert.assertTrue( !perm.isBanned() || ! BuildConfig.DEBUG );
|
||||
boolean granted = PackageManager.PERMISSION_GRANTED == granteds[ii];
|
||||
allGood = allGood && granted;
|
||||
result.put( perm, granted );
|
||||
|
||||
// Hack. If SMS has been granted, resend all moves. This should be
|
||||
|
@ -364,16 +357,58 @@ public class Perms23 {
|
|||
|
||||
PermCbck cbck = s_map.remove( code );
|
||||
if ( null != cbck ) {
|
||||
cbck.onPermissionResult( result );
|
||||
cbck.onPermissionResult( allGood, result );
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean havePermission( Perm perm )
|
||||
public static boolean havePermissions( Context context, Perm... perms )
|
||||
{
|
||||
String permString = perm.getString();
|
||||
boolean result = PackageManager.PERMISSION_GRANTED
|
||||
== ContextCompat.checkSelfPermission( XWApp.getContext(), permString );
|
||||
// Log.d( TAG, "havePermission(%s) => %b", permString, result );
|
||||
boolean result = true;
|
||||
for ( int ii = 0; result && ii < perms.length; ++ii ) {
|
||||
Perm perm = perms[ii];
|
||||
boolean thisResult;
|
||||
if ( perm.isBanned() ) {
|
||||
thisResult = bannedWithWorkaround( context, perm );
|
||||
} else {
|
||||
thisResult = PackageManager.PERMISSION_GRANTED
|
||||
== ContextCompat.checkSelfPermission( XWApp.getContext(),
|
||||
perm.getString() );
|
||||
}
|
||||
result = result && thisResult;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static boolean anyBanned( Perms23.Perm... perms )
|
||||
{
|
||||
boolean anyBanned = false;
|
||||
for ( int ii = 0; !anyBanned && ii < perms.length; ++ii ) {
|
||||
anyBanned = perms[ii].isBanned();
|
||||
}
|
||||
return anyBanned;
|
||||
}
|
||||
|
||||
static boolean bannedWithWorkaround( Context context, Perms23.Perm... perms )
|
||||
{
|
||||
boolean allBanned = true;
|
||||
boolean workaroundKnown = true;
|
||||
for ( Perms23.Perm perm : perms ) {
|
||||
allBanned = allBanned && perm.isBanned();
|
||||
|
||||
switch ( perm ) {
|
||||
case SEND_SMS:
|
||||
case RECEIVE_SMS:
|
||||
workaroundKnown = workaroundKnown && NBSProxy.isInstalled( context );
|
||||
break;
|
||||
default:
|
||||
Log.e( TAG, "bannedWithWorkaround(): unexpected perm %s", perm );
|
||||
Assert.assertFalse( BuildConfig.DEBUG );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
boolean result = allBanned && workaroundKnown;
|
||||
Log.d( TAG, "bannedWithWorkaround() => %b", result );
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -557,8 +557,8 @@ public class RelayService extends XWJIService
|
|||
for ( outData = s_queue.poll( ts, TimeUnit.MILLISECONDS );
|
||||
null != outData;
|
||||
outData = s_queue.poll() ) { // doesn't block
|
||||
Log.d( TAG, "removed packet from queue (%d left): %s",
|
||||
s_queue.size(), outData );
|
||||
// Log.d( TAG, "removed packet from queue (%d left): %s",
|
||||
// s_queue.size(), outData );
|
||||
if ( outData == sEOQPacket ) {
|
||||
shouldGoOn = false;
|
||||
break;
|
||||
|
@ -691,7 +691,7 @@ public class RelayService extends XWJIService
|
|||
int sentLen = 0;
|
||||
|
||||
if ( packets.size() > 0 ) {
|
||||
Log.d( TAG, "sendViaUDP(): sending %d at once", packets.size() );
|
||||
// Log.d( TAG, "sendViaUDP(): sending %d at once", packets.size() );
|
||||
final RelayService service = this;
|
||||
service.noteSent( packets, true );
|
||||
for ( PacketData packet : packets ) {
|
||||
|
@ -1155,9 +1155,9 @@ public class RelayService extends XWJIService
|
|||
byte proto = dis.readByte();
|
||||
if ( XWPDevProto.XWPDEV_PROTO_VERSION_1.ordinal() == proto ) {
|
||||
int packetID = vli2un( dis );
|
||||
if ( 0 != packetID ) {
|
||||
Log.d( TAG, "readHeader(): got packetID %d", packetID );
|
||||
}
|
||||
// if ( 0 != packetID ) {
|
||||
// Log.d( TAG, "readHeader(): got packetID %d", packetID );
|
||||
// }
|
||||
byte ordinal = dis.readByte();
|
||||
XWRelayReg cmd = XWRelayReg.values()[ordinal];
|
||||
result = new PacketHeader( cmd, packetID );
|
||||
|
|
|
@ -376,8 +376,9 @@ public class SMSService extends XWJIService {
|
|||
|
||||
private void sendDiedPacket( String phone, int gameID )
|
||||
{
|
||||
if ( !s_sentDied.contains(gameID) ) {
|
||||
if ( !s_sentDied.contains( gameID ) ) {
|
||||
resendFor( phone, SMS_CMD.DEATH, gameID, null );
|
||||
s_sentDied.add( gameID );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -515,19 +516,25 @@ public class SMSService extends XWJIService {
|
|||
short nbsPort = getNBSPort();
|
||||
try {
|
||||
SmsManager mgr = SmsManager.getDefault();
|
||||
PendingIntent sent = makeStatusIntent( MSG_SENT );
|
||||
PendingIntent delivery = makeStatusIntent( MSG_DELIVERED );
|
||||
boolean useProxy = Perms23.Perm.SEND_SMS.isBanned()
|
||||
&& NBSProxy.isInstalled( this );
|
||||
PendingIntent sent = useProxy ? null : makeStatusIntent( MSG_SENT );
|
||||
PendingIntent delivery = useProxy ? null : makeStatusIntent( MSG_DELIVERED );
|
||||
for ( byte[] fragment : fragments ) {
|
||||
mgr.sendDataMessage( phone, null, nbsPort, fragment, sent,
|
||||
delivery );
|
||||
Log.i( TAG, "sendBuffers(): sent %d byte fragment to %s",
|
||||
fragment.length, phone );
|
||||
if ( useProxy ) {
|
||||
NBSProxy.send( this, phone, nbsPort, fragment );
|
||||
} else {
|
||||
mgr.sendDataMessage( phone, null, nbsPort, fragment,
|
||||
sent, delivery );
|
||||
}
|
||||
// Log.i( TAG, "sendBuffers(): sent %d byte fragment to %s",
|
||||
// fragment.length, phone );
|
||||
}
|
||||
success = true;
|
||||
} catch ( IllegalArgumentException iae ) {
|
||||
Log.w( TAG, "sendBuffers(%s): %s", phone, iae.toString() );
|
||||
} catch ( NullPointerException npe ) {
|
||||
Assert.fail(); // shouldn't be trying to do this!!!
|
||||
Assert.assertFalse( BuildConfig.DEBUG ); // shouldn't be trying to do this!!!
|
||||
} catch ( java.lang.SecurityException se ) {
|
||||
mHelper.postEvent( MultiEvent.SMS_SEND_FAILED_NOPERMISSION );
|
||||
} catch ( Exception ee ) {
|
||||
|
|
|
@ -52,6 +52,7 @@ public class UpdateCheckReceiver extends BroadcastReceiver {
|
|||
// constants that are also used in info.py
|
||||
private static final String k_NAME = "name";
|
||||
private static final String k_AVERS = "avers";
|
||||
private static final String k_VARIANT = "variant";
|
||||
private static final String k_GVERS = "gvers";
|
||||
private static final String k_GHASH = "ghash";
|
||||
private static final String k_INSTALLER = "installer";
|
||||
|
@ -66,6 +67,8 @@ public class UpdateCheckReceiver extends BroadcastReceiver {
|
|||
private static final String k_DEBUG = "dbg";
|
||||
private static final String k_XLATEINFO = "xlatinfo";
|
||||
private static final String k_STRINGSHASH = "strings";
|
||||
private static final String k_UPGRADE_TITLE = "title";
|
||||
private static final String k_UPGRADE_BODY = "body";
|
||||
|
||||
@Override
|
||||
public void onReceive( Context context, Intent intent )
|
||||
|
@ -99,16 +102,6 @@ public class UpdateCheckReceiver extends BroadcastReceiver {
|
|||
interval_millis, pi );
|
||||
}
|
||||
|
||||
// Is app upgradeable OR have we installed any dicts?
|
||||
public static boolean haveToCheck( Context context )
|
||||
{
|
||||
boolean result = !Utils.isGooglePlayApp( context );
|
||||
if ( !result ) { // give another chance
|
||||
result = null != getDownloadedDicts( context );
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void checkVersions( Context context, boolean fromUI )
|
||||
{
|
||||
JSONObject params = new JSONObject();
|
||||
|
@ -123,17 +116,22 @@ public class UpdateCheckReceiver extends BroadcastReceiver {
|
|||
}
|
||||
|
||||
// App update
|
||||
if ( BuildConfig.FOR_FDROID || Utils.isGooglePlayApp( context ) ) {
|
||||
// Do nothing; can't or mustn't upgrade app
|
||||
if ( BuildConfig.FOR_FDROID ) {
|
||||
// Do nothing; can't upgrade app
|
||||
} else {
|
||||
String installer = pm.getInstallerPackageName( packageName );
|
||||
if ( null == installer ) {
|
||||
installer = "none";
|
||||
}
|
||||
|
||||
try {
|
||||
JSONObject appParams = new JSONObject();
|
||||
|
||||
appParams.put( k_VARIANT, BuildConfig.VARIANT_NAME );
|
||||
appParams.put( k_AVERS, versionCode );
|
||||
// Look at whether server needs these duplicates. PENDING....
|
||||
appParams.put( k_GVERS, BuildConfig.GIT_REV );
|
||||
appParams.put( k_GHASH, context.getString( R.string.git_rev ) );
|
||||
appParams.put( k_GHASH, BuildConfig.GIT_REV );
|
||||
appParams.put( k_INSTALLER, installer );
|
||||
if ( devOK( context ) ) {
|
||||
appParams.put( k_DEVOK, true );
|
||||
|
@ -315,12 +313,17 @@ public class UpdateCheckReceiver extends BroadcastReceiver {
|
|||
.makeAppDownloadIntent( m_context, url );
|
||||
}
|
||||
|
||||
String title =
|
||||
LocUtils.getString( m_context, R.string.new_app_avail_fmt,
|
||||
label );
|
||||
String body =
|
||||
LocUtils.getString( m_context,
|
||||
R.string.new_app_avail );
|
||||
// title and/or body might be in the reply
|
||||
String title = app.optString( k_UPGRADE_TITLE, null );
|
||||
if ( null == title ) {
|
||||
title = LocUtils
|
||||
.getString( m_context, R.string.new_app_avail_fmt, label );
|
||||
}
|
||||
String body = app.optString( k_UPGRADE_BODY, null );
|
||||
if ( null == body ) {
|
||||
body = LocUtils
|
||||
.getString( m_context, R.string.new_app_avail );
|
||||
}
|
||||
Utils.postNotification( m_context, intent, title,
|
||||
body, url.hashCode() );
|
||||
gotOne = true;
|
||||
|
|
|
@ -125,7 +125,7 @@ public class Utils {
|
|||
public static boolean isGSMPhone( Context context )
|
||||
{
|
||||
boolean result = false;
|
||||
if ( Perms23.havePermission( Perm.READ_PHONE_STATE ) ) {
|
||||
if ( Perms23.havePermissions( context, Perm.READ_PHONE_STATE ) ) {
|
||||
SMSService.SMSPhoneInfo info = SMSService.getPhoneInfo( context );
|
||||
result = null != info && info.isPhone && info.isGSM;
|
||||
}
|
||||
|
@ -141,7 +141,7 @@ public class Utils {
|
|||
public static boolean deviceSupportsNBS( Context context )
|
||||
{
|
||||
boolean result = false;
|
||||
if ( Perms23.havePermission( Perm.READ_PHONE_STATE ) ) {
|
||||
if ( Perms23.havePermissions( context, Perm.READ_PHONE_STATE ) ) {
|
||||
TelephonyManager tm = (TelephonyManager)
|
||||
context.getSystemService( Context.TELEPHONY_SERVICE );
|
||||
if ( null != tm ) {
|
||||
|
@ -314,7 +314,7 @@ public class Utils {
|
|||
synchronized ( s_phonesHash ) {
|
||||
if ( s_phonesHash.containsKey( phone ) ) {
|
||||
name = s_phonesHash.get( phone );
|
||||
} else if ( Perms23.havePermission( Perm.READ_CONTACTS ) ) {
|
||||
} else if ( Perms23.havePermissions( context, Perm.READ_CONTACTS ) ) {
|
||||
try {
|
||||
ContentResolver contentResolver = context
|
||||
.getContentResolver();
|
||||
|
|
|
@ -40,7 +40,8 @@ import java.util.UUID;
|
|||
|
||||
import static android.arch.lifecycle.Lifecycle.Event.ON_ANY;
|
||||
|
||||
public class XWApp extends Application implements LifecycleObserver {
|
||||
public class XWApp extends Application
|
||||
implements LifecycleObserver, NBSProxy.Callbacks {
|
||||
private static final String TAG = XWApp.class.getSimpleName();
|
||||
|
||||
public static final boolean BTSUPPORTED = true;
|
||||
|
@ -62,6 +63,8 @@ public class XWApp extends Application implements LifecycleObserver {
|
|||
private static Boolean s_onEmulator = null;
|
||||
private static Context s_context = null;
|
||||
|
||||
private short mPort;
|
||||
|
||||
@Override
|
||||
public void onCreate()
|
||||
{
|
||||
|
@ -72,7 +75,7 @@ public class XWApp extends Application implements LifecycleObserver {
|
|||
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
|
||||
|
||||
android.util.Log.i( TAG, "onCreate(); git_rev="
|
||||
+ getString( R.string.git_rev ) );
|
||||
+ BuildConfig.GIT_REV );
|
||||
Log.enable( this );
|
||||
|
||||
OnBootReceiver.startTimers( this );
|
||||
|
@ -92,6 +95,11 @@ public class XWApp extends Application implements LifecycleObserver {
|
|||
RelayService.startService( this );
|
||||
FBMService.init( this );
|
||||
WiDirWrapper.init( this );
|
||||
|
||||
mPort = Short.valueOf( getString( R.string.nbs_port ) );
|
||||
if ( NBSProxy.isInstalled( this ) ) {
|
||||
NBSProxy.register( mPort, BuildConfig.APPLICATION_ID, this );
|
||||
}
|
||||
}
|
||||
|
||||
@OnLifecycleEvent(ON_ANY)
|
||||
|
@ -119,6 +127,24 @@ public class XWApp extends Application implements LifecycleObserver {
|
|||
super.onTerminate();
|
||||
}
|
||||
|
||||
// NBSProxy.Callbacks
|
||||
@Override
|
||||
public void onDataReceived( short port, String fromPhone, byte[] data )
|
||||
{
|
||||
Assert.assertTrue( port == mPort || !BuildConfig.DEBUG );
|
||||
SMSService.handleFrom( this, data, fromPhone );
|
||||
}
|
||||
|
||||
// NBSProxy.Callbacks
|
||||
@Override
|
||||
public void onRegResponse( boolean appReached )
|
||||
{
|
||||
if ( !appReached ) {
|
||||
String channelID = Channels.getChannelID( this, Channels.ID.FOREGROUND );
|
||||
NBSProxy.postLaunchNotification( this, channelID, R.drawable.notify );
|
||||
}
|
||||
}
|
||||
|
||||
public static UUID getAppUUID()
|
||||
{
|
||||
if ( null == s_UUID ) {
|
||||
|
|
|
@ -216,10 +216,8 @@ public class DUtilCtxt {
|
|||
|
||||
public void store( String key, byte[] data )
|
||||
{
|
||||
Log.d( TAG, "store(key=%s)", key );
|
||||
|
||||
if ( null == data ) {
|
||||
} else {
|
||||
// Log.d( TAG, "store(key=%s)", key );
|
||||
if ( null != data ) {
|
||||
DBUtils.setBytesFor( m_context, key, data );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -136,7 +136,7 @@
|
|||
<string name="key_invite_multi">key_invite_multi</string>
|
||||
<string name="key_na_rematch_two_only">key_notagain_rematch_two_only</string>
|
||||
<string name="key_notagain_dfltname">key_notagain_dfltname</string>
|
||||
<string name="key_notagain_sms_banned">key_notagain_sms_banned</string>
|
||||
<string name="key_notagain_nbsGamesOnUpgrade">key_notagain_nbsGamesOnUpgrade</string>
|
||||
<string name="key_na_comms_bt">key_na_comms_bt</string>
|
||||
<string name="key_na_comms_p2p">key_na_comms_p2p</string>
|
||||
<string name="key_na_comms_sms">key_na_comms_sms</string>
|
||||
|
@ -155,6 +155,7 @@
|
|||
<!--string name="invite_mime">text/plain</string-->
|
||||
|
||||
<string name="dict_url">https://eehouse.org/and_wordlists</string>
|
||||
<string name="nbs_ban_url">https://eehouse.org/sms.html</string>
|
||||
<string name="default_update_url">https://eehouse.org/xw4/info.py</string>
|
||||
<string name="default_relay_url">https://eehouse.org/xw4/relay.py</string>
|
||||
<!-- <string name="default_relay_url">http://10.0.3.2/xw4/relay.py</string> -->
|
||||
|
|
|
@ -2700,12 +2700,23 @@
|
|||
<string name="after_restart">This change will take effect after you
|
||||
restart CrossWords.</string>
|
||||
|
||||
<string name="missing_perms">This game is configured to communicate
|
||||
<string name="missing_sms_perms">This game is configured to communicate
|
||||
via Data SMS but CrossWords does not have permission to do so. You
|
||||
can still open the game, but it may not be able to send or receive
|
||||
moves.\n\nYou can re-open it to be asked for permission again. Or
|
||||
you can remove the Data SMS communication setting.</string>
|
||||
|
||||
<string name="not_again_nbsGamesOnUpgrade">The Google Play Store
|
||||
version of CrossWords is no longer allowed to support the
|
||||
Play-by-Data-SMS feature.
|
||||
\n\n
|
||||
You have %1$d open games that use this feature. They will not be
|
||||
able to send or receive moves via Data SMS as long as you are using
|
||||
the Google Play version of CrossWords, or until I can figure out a
|
||||
workaround that meets Store policies.
|
||||
\n\n
|
||||
You can read more using the button below.</string>
|
||||
|
||||
<string name="download_rationale">CrossWords needs access to
|
||||
temporary storage to keep what you\'re about to download.
|
||||
</string>
|
||||
|
|
|
@ -2318,7 +2318,7 @@
|
|||
<string name="dualpane_restart">Gnitixe ppa…</string>
|
||||
<string name="after_restart">Siht egnahc lliw ton ekat tceffe litnu
|
||||
uoy tratser Sdrowssorc.</string>
|
||||
<string name="missing_perms">Siht emag si derugifnoc ot
|
||||
<string name="missing_sms_perms">Siht emag si derugifnoc ot
|
||||
etacinummoc aiv SMS tub Sdrowssorc seod ton evah noissimrep ot od
|
||||
os. Uoy nac llits nepo eht ,emag tub ti yam ton eb elba ot dnes ro
|
||||
eviecer sevom.\n\nUoy nac nepo-er ti ot eb deksa rof noissimrep
|
||||
|
|
|
@ -2318,7 +2318,7 @@
|
|||
<string name="dualpane_restart">EXITING APP…</string>
|
||||
<string name="after_restart">THIS CHANGE WILL NOT TAKE EFFECT UNTIL
|
||||
YOU RESTART CROSSWORDS.</string>
|
||||
<string name="missing_perms">THIS GAME IS CONFIGURED TO
|
||||
<string name="missing_sms_perms">THIS GAME IS CONFIGURED TO
|
||||
COMMUNICATE VIA SMS BUT CROSSWORDS DOES NOT HAVE PERMISSION TO DO
|
||||
SO. YOU CAN STILL OPEN THE GAME, BUT IT MAY NOT BE ABLE TO SEND OR
|
||||
RECEIVE MOVES.\n\nYOU CAN RE-OPEN IT TO BE ASKED FOR PERMISSION
|
||||
|
|
|
@ -1128,7 +1128,7 @@
|
|||
<string name="disable_dualpane">Tablet-Layout deaktivieren</string>
|
||||
<string name="after_restart">Diese Änderung wird aktiv, wenn Sie CrossWords neu starten.</string>
|
||||
|
||||
<string name="missing_perms">Diese Partie ist konfiguriert über SMS zu kommunizieren, aber CrossWords hat keine Berechtigung dazu. Sie können die Partie immer noch öffnen, aber möglicherweise keine Züge senden oder empfangen.
|
||||
<string name="missing_sms_perms">Diese Partie ist konfiguriert über SMS zu kommunizieren, aber CrossWords hat keine Berechtigung dazu. Sie können die Partie immer noch öffnen, aber möglicherweise keine Züge senden oder empfangen.
|
||||
\n
|
||||
\nSie können sie neu öffnen, um wieder nach der Berechtigung gefragt zu werden. Oder Sie können die SMS-Verbindung aus den Einstellungen entfernen.</string>
|
||||
|
||||
|
@ -1341,4 +1341,4 @@
|
|||
\n • Starten Sie CrossWords auf dem anderen Gerät
|
||||
\n • Wenn alles nichts hilft, booten Sie dieses Gerät
|
||||
\n</string>
|
||||
</resources>
|
||||
</resources>
|
||||
|
|
|
@ -3533,7 +3533,7 @@ Merci de me faire savoir si vous aimez cette fonctionnalité, de signaler les pl
|
|||
|
||||
<string name="not_again_comms_p2p">Utiliser le WiFi Direct pour jouer contre un appareil faisant du WiFi Direct, sur lequel CrossWords est installé.</string>
|
||||
|
||||
<string name="missing_perms">Cette partie est configurée pour communiquer par SMS mais Crosswords n\'a pas la permission de le faire. Vous pouvez toujours ouvrir cette partie, mais elle pourrait ne pas être en capacité d\'envoyer ou recevoir des coups.
|
||||
<string name="missing_sms_perms">Cette partie est configurée pour communiquer par SMS mais Crosswords n\'a pas la permission de le faire. Vous pouvez toujours ouvrir cette partie, mais elle pourrait ne pas être en capacité d\'envoyer ou recevoir des coups.
|
||||
|
||||
Vous pouvez la ré-ouvrir pour que la permission soit redemandée. Ou vous pouvez retirer le réglage de communication par SMS.</string>
|
||||
|
||||
|
@ -3624,4 +3624,4 @@ Vous pouvez la ré-ouvrir pour que la permission soit redemandée. Ou vous pouve
|
|||
<string name="force_tablet_default">Utiliser par défaut pour mon appareil</string>
|
||||
<string name="button_close">Fermer</string>
|
||||
<string name="btservice_expl">Cette notification est présente dès que CrossWords tourne en tâche de fond pour recevoir des messages Bluetooth. Elle reste pendant environ 15 minutes après que CrossWords ait démarré ou qu\'un message Bluetooth ait été reçu.</string>
|
||||
</resources>
|
||||
</resources>
|
||||
|
|
|
@ -848,7 +848,9 @@
|
|||
WiFi ダイレクト経由で接続可能なデバイスはありません。</string>
|
||||
<string name="not_again_comms_p2p">WiFi ダイレクトを使用して、クロスワードがインストールされた
|
||||
近くの WiFi ダイレクト対応デバイスに対してプレイします。</string>
|
||||
<string name="missing_perms">このゲームは SMS 経由で通信するように構成されていますが、
|
||||
|
||||
<string name="missing_sms_perms">このゲームは SMS 経由で通信するように構成されていますが、
|
||||
|
||||
クロスワードにそれを行うアクセス許可がありません。
|
||||
まだ、ゲームを開くことができますが、移動を送信または受信できない場合があります。
|
||||
|
||||
|
|
|
@ -1279,7 +1279,7 @@
|
|||
|
||||
<string name="not_again_dfltname_fmt">Du bruker forvalgt spillernavn \"%1$s\". Ønsker du å personalisere med ditt eget navn før du oppretter dette spillet?</string>
|
||||
|
||||
<string name="missing_perms">Dette spillet er satt opp for kommunikasjon via SMS, men CrossWords mangler tilgangen. Du kan åpne spillet, men det kan hende du ikke vil kunne sende eller motta trekk.
|
||||
<string name="missing_sms_perms">Dette spillet er satt opp for kommunikasjon via SMS, men CrossWords mangler tilgangen. Du kan åpne spillet, men det kan hende du ikke vil kunne sende eller motta trekk.
|
||||
\n
|
||||
\nDu kan gjenåpne det for å bli spurt om tilgang igjen. Eller du kan fjerne SMS-kommunikasjonsinnstillingen.</string>
|
||||
|
||||
|
@ -1336,4 +1336,4 @@
|
|||
\n • Kjør CrossWords på den andre enheten
|
||||
\n • Hvis ingenting annet virker, start denne enheten på ny
|
||||
\n</string>
|
||||
</resources>
|
||||
</resources>
|
||||
|
|
|
@ -23,6 +23,7 @@ except ImportError:
|
|||
VERBOSE = False
|
||||
k_NAME = 'name'
|
||||
k_AVERS = 'avers'
|
||||
k_VARIANT = 'variant'
|
||||
k_GVERS = 'gvers'
|
||||
k_INSTALLER = 'installer'
|
||||
k_DEVOK = 'devOK'
|
||||
|
@ -35,6 +36,9 @@ k_LOCALE = 'locale'
|
|||
k_XLATPROTO = 'proto'
|
||||
k_XLATEVERS = 'xlatevers'
|
||||
k_STRINGSHASH = 'strings'
|
||||
k_UPGRADE_TITLE = 'title'
|
||||
k_UPGRADE_BODY = 'body'
|
||||
|
||||
|
||||
k_DICT_HEADER_MASK = 0x08
|
||||
|
||||
|
|
60
xwords4/android/website/sms.html
Normal file
60
xwords4/android/website/sms.html
Normal file
|
@ -0,0 +1,60 @@
|
|||
<html>
|
||||
<body style="max-width: 500px; width:100%; margin: 0px auto;"
|
||||
>
|
||||
<h2>CrossWords and Play-via-Data-SMS</h2>
|
||||
<p>Play-via-Data-SMS is one of my favorite features of
|
||||
CrossWords. It's super-reliable, and works between GSM phones
|
||||
round-the-world without requiring any kind of server. Most apps
|
||||
have servers in order to harvest saleable infomation about you
|
||||
or to show ads, but CrossWords doesn't care about that and so
|
||||
has always supported this feature.</p>
|
||||
|
||||
<p>Unfortunately, Google's decided there are security problems
|
||||
with SMS (or at least that's their claimed motivation) and is
|
||||
prohibiting most apps from continuing to send or receive SMS
|
||||
(including Data SMS) if they want to be listed on the Play
|
||||
Store. And so I've removed the feature from the CrossWords
|
||||
"variant" that's available there. The feature remains, however,
|
||||
in other variants, including those at:
|
||||
|
||||
<ul>
|
||||
<li><a href="https://github.com/eehouse/xwords/releases/">Github
|
||||
OpenSource repository</a></li>
|
||||
<li><a href="https://sourceforge.net/projects/xwords/">Sourceforge
|
||||
OpenSource repository</a></li>
|
||||
<li><a href="https://f-droid.org/en/packages/org.eehouse.android.xw4/">F-droid
|
||||
OpenSource "app store"</a></li>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
<p>(The GitHub and Sourceforge variants will install over the top
|
||||
of the Play Store variant without problems. With the F-droid
|
||||
variant, however, you'll have to uninstall your current
|
||||
variant first, losing your games and settings.)</p>
|
||||
|
||||
<p>I've also starting working on a data-SMS-forwarding app called
|
||||
NBSProxy. With NBSProxy installed, CrossWords can communicate
|
||||
using Data SMS without the SMS permissions (since NBSProxy has
|
||||
them, and is the one using Android's Data SMS functionality.)
|
||||
Google says that apps whose core functionality requires SMS
|
||||
permissions will be allowed on the Play Store, so NBSProxy
|
||||
should be available there soon. In the meantime, you
|
||||
can <a href="https://github.com/eehouse/nbsproxy/releases">get
|
||||
it from GitHub</a>.
|
||||
</p>
|
||||
|
||||
<p>Side note: It'd be helpful to know how many people use the
|
||||
Play-via-Data-SMS feature in deciding whether to keep these
|
||||
separate variants going. Would you
|
||||
mind <a href="mailto:xwords@eehouse.org">emailing me</a> and
|
||||
letting me know whether you've found it useful?
|
||||
</p>
|
||||
|
||||
<p>Thanks!
|
||||
<br>
|
||||
<br>
|
||||
--Eric
|
||||
</p>
|
||||
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in a new issue