diff --git a/xwords4/android/XWords4/build.xml b/xwords4/android/XWords4/build.xml index b1d8ad988..d1536010c 100644 --- a/xwords4/android/XWords4/build.xml +++ b/xwords4/android/XWords4/build.xml @@ -61,6 +61,7 @@ diff --git a/xwords4/android/XWords4/res/values/strings.xml b/xwords4/android/XWords4/res/values/strings.xml index 1ce1ffc86..9db8836f9 100644 --- a/xwords4/android/XWords4/res/values/strings.xml +++ b/xwords4/android/XWords4/res/values/strings.xml @@ -2127,6 +2127,10 @@ play Crosswords using the wordlist %2$s (for play in %3$s), but it is not installed. Would you like to download the wordlist or decline the invitation? + You have been invited to + play Crosswords using the wordlist %2$s (for play in %3$s), but it + is not installed. Would you like to download the wordlist or + decline the invitation? Decline Downloading %s... diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java index 9f9f5089a..e45f64e3e 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java @@ -816,9 +816,8 @@ public class BoardActivity extends XWActivity if ( DlgDelegate.DISMISS_BUTTON != which ) { GameUtils.launchInviteActivity( BoardActivity.this, DlgDelegate.EMAIL_BTN == which, - m_room, null, - m_gi.dictLang, - m_gi.nPlayers ); + m_room, null, m_gi.dictLang, + m_gi.dictName, m_gi.nPlayers ); } } else if ( AlertDialog.BUTTON_POSITIVE == which ) { JNICmd cmd = JNICmd.CMD_NONE; diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java index 426e5dd23..f0a09b78c 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java @@ -547,7 +547,7 @@ public class DBUtils { DBHelper.ROOMNAME, nli.room, DBHelper.INVITEID, nli.inviteID, DBHelper.DICTLANG, nli.lang, - DBHelper.NUM_PLAYERS, nli.nPlayers ); + DBHelper.NUM_PLAYERS, nli.nPlayersT ); Cursor cursor = db.query( DBHelper.TABLE_NAME_SUM, columns, selection, null, null, null, null ); if ( 1 == cursor.getCount() && cursor.moveToFirst() ) { @@ -563,7 +563,7 @@ public class DBUtils { { long rowid = ROWID_NOTFOUND; NetLaunchInfo nli = new NetLaunchInfo( data ); - if ( null != nli ) { + if ( null != nli && nli.isValid() ) { rowid = getRowIDForOpen( context, nli ); } return rowid; diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DispatchNotify.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DispatchNotify.java index a82d1addc..57d674d62 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DispatchNotify.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DispatchNotify.java @@ -64,11 +64,30 @@ public class DispatchNotify extends Activity { if ( !tryHandle( gameID ) ) { mustLaunch = true; } - } else if ( null != data ) { - long rowid = DBUtils.getRowIDForOpen( this, data ); + } else if ( null != data ) { // relay invite redirected URL case + NetLaunchInfo nli = new NetLaunchInfo( data ); + long rowid = DBUtils.getRowIDForOpen( this, nli ); if ( DBUtils.ROWID_NOTFOUND == rowid ) { - if ( !tryHandle( data ) ) { - mustLaunch = true; + boolean haveDict; + if ( null == nli.dict ) { // can only test for language support + haveDict = + 0 < DictLangCache.getHaveLang( this, nli.lang ).length; + } else { + haveDict = DictLangCache.haveDict( this, nli.lang, nli.dict ); + } + if ( haveDict ) { + if ( !tryHandle( data ) ) { + mustLaunch = true; + } + } else { + Intent intent = MultiService.makeMissingDictIntent( this, + nli ); + intent.putExtra( MultiService.OWNER, + MultiService.OWNER_RELAY ); + // do we have gameID? + MultiService. + postMissingDictNotification( this, intent, + nli.inviteID.hashCode() ); } } else { DbgUtils.logf( "DispatchNotify: dropping duplicate invite" ); diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GCMIntentService.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GCMIntentService.java index 2ab40f4bc..1fc22e503 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GCMIntentService.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GCMIntentService.java @@ -74,7 +74,7 @@ public class GCMIntentService extends GCMBaseIntentService { public static void init( Application app ) { int sdkVersion = Integer.valueOf( android.os.Build.VERSION.SDK ); - if ( 8 <= sdkVersion ) { + if ( 8 <= sdkVersion && 0 < GCMConsts.SENDER_ID.length() ) { try { GCMRegistrar.checkDevice( app ); // GCMRegistrar.checkManifest( app ); diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java index e5977edc7..ed9e46bb5 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java @@ -24,15 +24,8 @@ import android.app.Activity; import android.content.Context; import android.content.Intent; import android.net.Uri; -import android.os.Environment; import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.InputStream; -import java.nio.channels.FileChannel; -import java.util.ArrayList; import java.util.Arrays; -import android.content.res.AssetManager; import java.util.concurrent.locks.Lock; import java.util.HashMap; import java.util.HashSet; @@ -432,7 +425,7 @@ public class GameUtils { } private static long makeNewMultiGame( Context context, CommsAddrRec addr, - int[] lang, String dict, + int[] lang, String[] dict, int nPlayersT, int nPlayersH, String inviteID, int gameID, boolean isHost ) @@ -440,8 +433,9 @@ public class GameUtils { long rowid = -1; CurGameInfo gi = new CurGameInfo( context, true ); - gi.setLang( lang[0], dict ); + gi.setLang( lang[0], dict[0] ); lang[0] = gi.dictLang; + dict[0] = gi.dictName; gi.setNPlayers( nPlayersT, nPlayersH ); gi.juggle(); if ( 0 != gameID ) { @@ -466,7 +460,8 @@ public class GameUtils { public static long makeNewNetGame( Context context, String room, String inviteID, int[] lang, - int nPlayersT, int nPlayersH ) + String[] dict, int nPlayersT, + int nPlayersH ) { long rowid = -1; String relayName = XWPrefs.getDefaultRelayHost( context ); @@ -474,21 +469,24 @@ public class GameUtils { CommsAddrRec addr = new CommsAddrRec( relayName, relayPort ); addr.ip_relay_invite = room; - return makeNewMultiGame( context, addr, lang, null, nPlayersT, + return makeNewMultiGame( context, addr, lang, dict, nPlayersT, nPlayersH, inviteID, 0, false ); } public static long makeNewNetGame( Context context, String room, - String inviteID, int lang, int nPlayers ) + String inviteID, int lang, String dict, + int nPlayers ) { int[] langarr = { lang }; - return makeNewNetGame( context, room, inviteID, langarr, nPlayers, 1 ); + String[] dictArr = { dict }; + return makeNewNetGame( context, room, inviteID, langarr, dictArr, + nPlayers, 1 ); } public static long makeNewNetGame( Context context, NetLaunchInfo info ) { return makeNewNetGame( context, info.room, info.inviteID, info.lang, - info.nPlayers ); + info.dict, info.nPlayersT ); } public static long makeNewBTGame( Context context, int gameID, @@ -512,11 +510,12 @@ public class GameUtils { { long rowid = -1; int[] langa = { lang }; + String[] dicta = { dict }; boolean isHost = null == addr; if ( isHost ) { addr = new CommsAddrRec(CommsAddrRec.CommsConnType.COMMS_CONN_SMS); } - return makeNewMultiGame( context, addr, langa, dict, nPlayersT, + return makeNewMultiGame( context, addr, langa, dicta, nPlayersT, nPlayersH, null, gameID, isHost ); } @@ -539,13 +538,14 @@ public class GameUtils { public static void launchInviteActivity( Context context, boolean choseEmail, String room, String inviteID, - int lang, int nPlayers ) + int lang, String dict, + int nPlayers ) { if ( null == inviteID ) { inviteID = makeRandomID(); } Uri gameUri = NetLaunchInfo.makeLaunchUri( context, room, inviteID, - lang, nPlayers ); + lang, dict, nPlayers ); if ( null != gameUri ) { int fmtId = choseEmail? R.string.invite_htmf : R.string.invite_txtf; diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java index ff2ef90b5..04be68eaa 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java @@ -88,7 +88,7 @@ public class GamesList extends XWExpandableListActivity private GameListAdapter m_adapter; private String m_missingDict; - private String[] m_missingDictNames; + private String m_missingDictName; private long m_missingDictRowId; private String[] m_sameLangDicts; private int m_missingDictLang; @@ -115,10 +115,15 @@ public class GamesList extends XWExpandableListActivity lstnr = new DialogInterface.OnClickListener() { public void onClick( DialogInterface dlg, int item ) { // just do one - NetUtils.downloadDictInBack( GamesList.this, - m_missingDictLang, - m_missingDictNames[0], - GamesList.this ); + if ( null == m_missingDictName ) { + DictsActivity.launchAndDownload( GamesList.this, + m_missingDictLang ); + } else { + NetUtils.downloadDictInBack( GamesList.this, + m_missingDictLang, + m_missingDictName, + GamesList.this ); + } } }; String message; @@ -130,7 +135,7 @@ public class GamesList extends XWExpandableListActivity gameName, langName ); } else { message = getString( R.string.no_dict_substf, - gameName, m_missingDictNames[0], + gameName, m_missingDictName, langName ); } @@ -163,8 +168,10 @@ public class GamesList extends XWExpandableListActivity dict = DictLangCache.stripCount( dict ); GameUtils.replaceDicts( GamesList.this, m_missingDictRowId, - m_missingDictNames[0], + m_missingDictName, dict ); + GameUtils.launchGame( GamesList.this, + m_missingDictRowId ); } }; dialog = new AlertDialog.Builder( this ) @@ -404,7 +411,7 @@ public class GamesList extends XWExpandableListActivity super.onSaveInstanceState( outState ); outState.putLong( SAVE_ROWID, m_rowid ); outState.putLong( SAVE_GROUPID, m_groupid ); - outState.putStringArray( SAVE_DICTNAMES, m_missingDictNames ); + outState.putString( SAVE_DICTNAMES, m_missingDictName ); if ( null != m_netLaunchInfo ) { m_netLaunchInfo.putSelf( outState ); } @@ -416,7 +423,7 @@ public class GamesList extends XWExpandableListActivity m_rowid = bundle.getLong( SAVE_ROWID ); m_groupid = bundle.getLong( SAVE_GROUPID ); m_netLaunchInfo = new NetLaunchInfo( bundle ); - m_missingDictNames = bundle.getStringArray( SAVE_DICTNAMES ); + m_missingDictName = bundle.getString( SAVE_DICTNAMES ); } } @@ -834,13 +841,21 @@ public class GamesList extends XWExpandableListActivity missingNames, missingLang ); if ( !hasDicts ) { - m_missingDictNames = missingNames[0]; m_missingDictLang = missingLang[0]; + if ( 0 < missingNames[0].length ) { + m_missingDictName = missingNames[0][0]; + } else { + m_missingDictName = null; + } m_missingDictRowId = rowid; if ( 0 == DictLangCache.getLangCount( this, m_missingDictLang ) ) { showDialog( WARN_NODICT ); - } else { + } else if ( null != m_missingDictName ) { showDialog( WARN_NODICT_SUBST ); + } else { + String dict = DictLangCache.getHaveLang( this, m_missingDictLang)[0]; + GameUtils.replaceDicts( this, m_missingDictRowId, null, dict ); + GameUtils.launchGame( this, m_missingDictRowId ); } } return hasDicts; @@ -911,13 +926,18 @@ public class GamesList extends XWExpandableListActivity private void startNewNetGame( Intent intent ) { - Uri data = intent.getData(); - if ( null != data ) { - NetLaunchInfo info = new NetLaunchInfo( data ); - if ( info.isValid() ) { - startNewNetGame( info ); + NetLaunchInfo info = null; + if ( MultiService.isMissingDictIntent( intent ) ) { + info = new NetLaunchInfo( intent ); + } else { + Uri data = intent.getData(); + if ( null != data ) { + info = new NetLaunchInfo( data ); } } + if ( null != info && info.isValid() ) { + startNewNetGame( info ); + } } // startNewNetGame private void startHasGameID( int gameID ) @@ -972,4 +992,9 @@ public class GamesList extends XWExpandableListActivity return dialog; } + public static void onGameDictDownload( Context context, Intent intent ) + { + intent.setClass( context, GamesList.class ); + context.startActivity( intent ); + } } diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/MultiService.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/MultiService.java index 8c06598b0..4e4d21686 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/MultiService.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/MultiService.java @@ -31,6 +31,8 @@ public class MultiService { public static final String LANG = "LANG"; public static final String DICT = "DICT"; public static final String GAMEID = "GAMEID"; + public static final String INVITEID = "INVITEID"; // relay only + public static final String ROOM = "ROOM"; public static final String GAMENAME = "GAMENAME"; public static final String NPLAYERST = "NPLAYERST"; public static final String NPLAYERSH = "NPLAYERSH"; @@ -38,6 +40,7 @@ public class MultiService { public static final String OWNER = "OWNER"; public static final int OWNER_SMS = 1; + public static final int OWNER_RELAY = 2; private BTEventListener m_li; @@ -84,11 +87,39 @@ public class MultiService { } } + public static void fillInviteIntent( Intent intent, String gameName, + int lang, String dict, + int nPlayersT, int nPlayersH ) + { + intent.putExtra( GAMENAME, gameName ); + intent.putExtra( LANG, lang ); + intent.putExtra( DICT, dict ); + intent.putExtra( NPLAYERST, nPlayersT ); // both of these used + intent.putExtra( NPLAYERSH, nPlayersH ); + } + + public static Intent makeMissingDictIntent( Context context, String gameName, + int lang, String dict, + int nPlayersT, int nPlayersH ) + { + Intent intent = new Intent( context, DictsActivity.class ); + fillInviteIntent( intent, gameName, lang, dict, nPlayersT, nPlayersH ); + return intent; + } + + public static Intent makeMissingDictIntent( Context context, NetLaunchInfo nli ) + { + Intent intent = makeMissingDictIntent( context, null, nli.lang, nli.dict, + nli.nPlayersT, 1 ); + intent.putExtra( ROOM, nli.room ); + return intent; + } + public static boolean isMissingDictIntent( Intent intent ) { return intent.hasExtra( LANG ) - && intent.hasExtra( DICT ) - && intent.hasExtra( GAMEID ) + // && intent.hasExtra( DICT ) + && (intent.hasExtra( GAMEID ) || intent.hasExtra( ROOM )) && intent.hasExtra( GAMENAME ) && intent.hasExtra( NPLAYERST ) && intent.hasExtra( NPLAYERSH ); @@ -102,8 +133,10 @@ public class MultiService { String langStr = DictLangCache.getLangName( context, lang ); String dict = intent.getStringExtra( DICT ); String inviter = intent.getStringExtra( INVITER ); - String msg = context.getString( R.string.invite_dict_missing_bodyf, - inviter, dict, langStr ); + int msgID = (null == inviter) ? R.string.invite_dict_missing_body_nonamef + : R.string.invite_dict_missing_bodyf; + String msg = context.getString( msgID, inviter, dict, langStr ); + return new AlertDialog.Builder( context ) .setTitle( R.string.invite_dict_missing_title ) .setMessage( msg) @@ -112,6 +145,13 @@ public class MultiService { .create(); } + public static void postMissingDictNotification( Context content, + Intent intent, int id ) + { + Utils.postNotification( content, intent, R.string.missing_dict_title, + R.string.missing_dict_detail, id ); + } + // resend the intent, but only if the dict it names is here. (If // it's not, we may need to try again later, e.g. because our cue // was a focus gain.) @@ -123,11 +163,15 @@ public class MultiService { String dict = intent.getStringExtra( DICT ); downloaded = DictLangCache.haveDict( context, lang, dict ); if ( downloaded ) { - int owner = intent.getIntExtra( OWNER, -1 ); - if ( owner == OWNER_SMS ) { + switch ( intent.getIntExtra( OWNER, -1 ) ) { + case OWNER_SMS: SMSService.onGameDictDownload( context, intent ); - } else { - DbgUtils.logf( "unexpected OWNER: %d", owner ); + break; + case OWNER_RELAY: + GamesList.onGameDictDownload( context, intent ); + break; + default: + DbgUtils.logf( "unexpected OWNER" ); } } } diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/NetLaunchInfo.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/NetLaunchInfo.java index d73370d79..53a9c61ab 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/NetLaunchInfo.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/NetLaunchInfo.java @@ -21,8 +21,9 @@ package org.eehouse.android.xw4; import android.content.Context; -import android.net.Uri; +import android.content.Intent; import android.net.Uri.Builder; +import android.net.Uri; import android.os.Bundle; import java.net.URLEncoder; @@ -30,11 +31,13 @@ import java.net.URLEncoder; public class NetLaunchInfo { public String room; public String inviteID; + public String dict; public int lang; - public int nPlayers; + public int nPlayersT; private static final String LANG = "netlaunchinfo_lang"; private static final String ROOM = "netlaunchinfo_room"; + private static final String DICT = "netlaunchinfo_dict"; private static final String INVITEID = "netlaunchinfo_inviteid"; private static final String NPLAYERS = "netlaunchinfo_nplayers"; private static final String VALID = "netlaunchinfo_valid"; @@ -46,7 +49,8 @@ public class NetLaunchInfo { bundle.putInt( LANG, lang ); bundle.putString( ROOM, room ); bundle.putString( INVITEID, inviteID ); - bundle.putInt( NPLAYERS, nPlayers ); + bundle.putString( DICT, dict ); + bundle.putInt( NPLAYERS, nPlayersT ); bundle.putBoolean( VALID, m_valid ); } @@ -54,8 +58,9 @@ public class NetLaunchInfo { { lang = bundle.getInt( LANG ); room = bundle.getString( ROOM ); + dict = bundle.getString( DICT ); inviteID = bundle.getString( INVITEID ); - nPlayers = bundle.getInt( NPLAYERS ); + nPlayersT = bundle.getInt( NPLAYERS ); m_valid = bundle.getBoolean( VALID ); } @@ -66,10 +71,11 @@ public class NetLaunchInfo { try { room = data.getQueryParameter( "room" ); inviteID = data.getQueryParameter( "id" ); + dict = data.getQueryParameter( "wl" ); String langStr = data.getQueryParameter( "lang" ); lang = Integer.decode( langStr ); String np = data.getQueryParameter( "np" ); - nPlayers = Integer.decode( np ); + nPlayersT = Integer.decode( np ); m_valid = true; } catch ( Exception e ) { DbgUtils.logf( "unable to parse \"%s\"", data.toString() ); @@ -77,8 +83,21 @@ public class NetLaunchInfo { } } + public NetLaunchInfo( Intent intent ) + { + room = intent.getStringExtra( MultiService.ROOM ); + inviteID = intent.getStringExtra( MultiService.INVITEID ); + lang = intent.getIntExtra( MultiService.LANG, -1 ); + dict = intent.getStringExtra( MultiService.DICT ); + nPlayersT = intent.getIntExtra( MultiService.NPLAYERST, -1 ); + m_valid = null != room + && -1 != lang + && -1 != nPlayersT; + } + public static Uri makeLaunchUri( Context context, String room, - String inviteID, int lang, int nPlayers ) + String inviteID, int lang, + String dict, int nPlayersT ) { Builder ub = new Builder(); ub.scheme( "http" ); @@ -86,9 +105,12 @@ public class NetLaunchInfo { XWPrefs.getDefaultRedirHost( context ) ) ); ub.appendQueryParameter( "lang", String.format("%d", lang ) ); - ub.appendQueryParameter( "np", String.format( "%d", nPlayers ) ); + ub.appendQueryParameter( "np", String.format( "%d", nPlayersT ) ); ub.appendQueryParameter( "room", room ); ub.appendQueryParameter( "id", inviteID ); + if ( null != dict ) { + ub.appendQueryParameter( "wl", dict ); + } return ub.build(); } diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/NewGameActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/NewGameActivity.java index 3cfee37c9..039aaa23d 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/NewGameActivity.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/NewGameActivity.java @@ -318,13 +318,14 @@ public class NewGameActivity extends XWActivity { String inviteID = null; long rowid; int[] lang = {0}; + String[] dict = {null}; final int nPlayers = 2; // hard-coded for no-configure case if ( networked ) { room = GameUtils.makeRandomID(); inviteID = GameUtils.makeRandomID(); rowid = GameUtils.makeNewNetGame( this, room, inviteID, lang, - nPlayers, 1 ); + dict, nPlayers, 1 ); } else { rowid = GameUtils.saveNew( this, new CurGameInfo( this ) ); } @@ -333,7 +334,8 @@ public class NewGameActivity extends XWActivity { GameUtils.launchGame( this, rowid, networked ); if ( networked ) { GameUtils.launchInviteActivity( this, choseEmail, room, - inviteID, lang[0], nPlayers ); + inviteID, lang[0], dict[0], + nPlayers ); } } else { GameUtils.doConfig( this, rowid, GameConfig.class ); diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/SMSService.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/SMSService.java index 6121e7196..18cbd8c88 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/SMSService.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/SMSService.java @@ -424,17 +424,15 @@ public class SMSService extends Service { makeForInvite( phone, gameID, gameName, lang, dict, nPlayersT, nPlayersH ); } else { - Intent intent = new Intent( this, DictsActivity.class ); - fillInviteIntent( intent, phone, gameID, gameName, lang, dict, - nPlayersT, nPlayersH ); + Intent intent = MultiService + .makeMissingDictIntent( this, gameName, lang, dict, + nPlayersT, nPlayersH ); + intent.putExtra( PHONE, phone ); intent.putExtra( MultiService.OWNER, MultiService.OWNER_SMS ); intent.putExtra( MultiService.INVITER, Utils.phoneToContact( this, phone, true ) ); - Utils.postNotification( this, intent, - R.string.missing_dict_title, - R.string.missing_dict_detail, - gameID ); + MultiService.postMissingDictNotification( this, intent, gameID ); } break; case DATA: @@ -591,11 +589,8 @@ public class SMSService extends Service { { intent.putExtra( PHONE, phone ); intent.putExtra( MultiService.GAMEID, gameID ); - intent.putExtra( MultiService.GAMENAME, gameName ); - intent.putExtra( MultiService.LANG, lang ); - intent.putExtra( MultiService.DICT, dict ); - intent.putExtra( MultiService.NPLAYERST, nPlayersT ); - intent.putExtra( MultiService.NPLAYERSH, nPlayersH ); + MultiService.fillInviteIntent( intent, gameName, lang, dict, + nPlayersT, nPlayersH ); } private void feedMessage( int gameID, byte[] msg, CommsAddrRec addr ) diff --git a/xwords4/android/scripts/gen_gcmid.sh b/xwords4/android/scripts/gen_gcmid.sh index 9ca58833a..bf719f2ab 100755 --- a/xwords4/android/scripts/gen_gcmid.sh +++ b/xwords4/android/scripts/gen_gcmid.sh @@ -1,8 +1,11 @@ #!/bin/sh +set -e -u + +GCM_SENDER_ID=${GCM_SENDER_ID:-""} + if [ -z "$GCM_SENDER_ID" ]; then - echo "GCM_SENDER_ID not in env" - exit 1 + echo "GCM_SENDER_ID empty; GCM use will be disabled" >&2 fi cat < "; + } +} + +$g_androidStrings = array( "android", ); $scheme = "newxwgame"; $host = "10.0.2.2"; @@ -10,33 +34,46 @@ $lang = $_REQUEST["lang"]; $room = $_REQUEST["room"]; $np = $_REQUEST["np"]; $id = $_REQUEST["id"]; +$wl = $_REQUEST["wl"]; -$content = "0; url=$scheme://$host?room=$room&lang=$lang&np=$np"; +$agent = $_SERVER['HTTP_USER_AGENT']; +$onAndroid = false; +for ( $ii = 0; $ii < count($g_androidStrings) && !$onAndroid; ++$ii ) { + $needle = $g_androidStrings[$ii]; + $onAndroid = 0 != stripos( $agent, $needle ); +} +$onFire = 0 != stripos( $agent, 'silk' ); + +$localurl = "$scheme://$host?room=$room&lang=$lang&np=$np"; if ( $id != "" ) { - $content .= "&id=$id"; + $localurl .= "&id=$id"; +} +if ( $wl != "" ) { + $localurl .= "&wl=$wl"; } +if ( $onAndroid || $onFire ) { print << -Crosswords SMS redirect - +Crosswords Invite redirect
- + -

redirecting to Crosswords....

- -

This page is meant to be viewed (briefly) on your Android device after which Crosswords should launch. - If this fails it's probably because you don't have a new enough version of Crosswords installed. +

Tap this link to launch Crosswords with + your new game. +

+

If this fails it's probably because you don't have a new enough + version of Crosswords installed.

+
@@ -44,4 +81,77 @@ print << + + +Crosswords Invite redirect + + + +

It appears you're running on a Kindle Fire, whose non-standard (from +an Android perspective) OS doesn't support the custom schemes on which +Crosswords invitations depend. If you want to accept this invitation +you'll need to do it the manual way: + +

    +
  1. Open Crosswords, and navigate to the main Games List screen
  2. +
  3. Choose "Add game", either from the menu or the button at the bottom.
  4. +
  5. Under "New Networked game", choose "Configure first".
  6. +
  7. $langText
  8. +
  9. As the room name, enter "$room".
  10. +
  11. Make sure the total number of players shown is $np and that only one of them is not an "Off-device player".
  12. +
  13. Now tap the "Play game" button at the bottom (above the keyboard). Your new game should open and connect.
  14. +

+

I'm sorry this is so complicated. I'm trying to find a +workaround for this limitation in the Kindle Fire's operating system +but for now this is all I can offer.

+ +

(Just in case Amazon's fixed the +problem, here is the link that should open +your new game.)

+ + +EOF; +} else { +$subject = "Android device not identified"; + +$body = htmlentities("My browser is running on an android device but" +. " says its user agent is: \"$agent\". Please fix your script to recognize" +. " this as an Android browser."); + +print << + + +Crosswords Invite redirect + + +
+ +
+

This page is meant to be viewed on a browser on your Android + device. Please open the email that sent you here on that device and + revisit this link to complete the invitation process. +

+ +

(If you are viewing this on an Android device, you've + found a bug! Please email me (and be + sure to leave the user agent string in the email body.) +

+ + + + +EOF; +} + ?>