diff --git a/xwords4/android/app/build.gradle b/xwords4/android/app/build.gradle index b797f6d68..f16f912dd 100644 --- a/xwords4/android/app/build.gradle +++ b/xwords4/android/app/build.gradle @@ -333,6 +333,8 @@ dependencies { implementation 'com.github.eehouse:nbsproxy:v0.2.2' implementation "org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.+" + + implementation 'com.google.zxing:core:3.3.+' } task mkImages(type: Exec) { diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BoardDelegate.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BoardDelegate.java index c4623735f..bc8f6d239 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BoardDelegate.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BoardDelegate.java @@ -821,7 +821,8 @@ public class BoardDelegate extends DelegateBase private void showInviteChoicesThen( Object[] params ) { SentInvitesInfo info = (SentInvitesInfo)params[0]; - showInviteChoicesThen( Action.LAUNCH_INVITE_ACTION, info ); + NetLaunchInfo nli = nliForMe(); + showInviteChoicesThen( Action.LAUNCH_INVITE_ACTION, info, nli ); } @Override diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/DelegateBase.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/DelegateBase.java index f96c0f89e..055ca4225 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/DelegateBase.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/DelegateBase.java @@ -595,9 +595,10 @@ public class DelegateBase implements DlgClickNotify, } protected void showInviteChoicesThen( Action action, - DBUtils.SentInvitesInfo info ) + DBUtils.SentInvitesInfo info, + NetLaunchInfo nli) { - m_dlgDelegate.showInviteChoicesThen( action, info ); + m_dlgDelegate.showInviteChoicesThen( action, info, nli ); } public Builder makeOkOnlyBuilder( int msgID ) diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/DlgDelegate.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/DlgDelegate.java index c317ac9aa..8ca1888dc 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/DlgDelegate.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/DlgDelegate.java @@ -394,11 +394,12 @@ public class DlgDelegate { } public void showInviteChoicesThen( final Action action, - SentInvitesInfo info ) + SentInvitesInfo info, + NetLaunchInfo nli ) { DlgState state = new DlgState( DlgID.INVITE_CHOICES_THEN ) .setAction( action ) - .setParams( info ); + .setParams( info, nli ); m_dlgt.show( state ); } diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/InviteChoicesAlert.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/InviteChoicesAlert.java index e4c86b7bc..e88dd76b8 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/InviteChoicesAlert.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/InviteChoicesAlert.java @@ -55,12 +55,16 @@ public class InviteChoicesAlert extends DlgDelegateAlert { ArrayList means = new ArrayList<>(); InviteMeans lastMeans = null; + NetLaunchInfo nli = null; Object[] params = state.getParams(); - if ( null != params - && params[0] instanceof SentInvitesInfo ) { - lastMeans = ((SentInvitesInfo)params[0]).getLastMeans(); + if ( null != params ) { + if ( 0 < params.length && params[0] instanceof SentInvitesInfo ) { + lastMeans = ((SentInvitesInfo)params[0]).getLastMeans(); + } + if ( 1 < params.length && params[1] instanceof NetLaunchInfo ) { + nli = (NetLaunchInfo)params[1]; + } } - means.add( InviteMeans.EMAIL ); means.add( InviteMeans.SMS_USER ); @@ -129,7 +133,9 @@ public class InviteChoicesAlert extends DlgDelegateAlert String[] players = XwJNI.kplr_getPlayers(); inviteView.setChoices( means, lastSelMeans, players ) - .setCallbacks( this ); + .setNli( nli ) + .setCallbacks( this ) + ; if ( false && BuildConfig.DEBUG ) { OnClickListener ocl = new OnClickListener() { diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/InviteView.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/InviteView.java index d52ae1083..4c7d405fe 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/InviteView.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/InviteView.java @@ -20,8 +20,11 @@ package org.eehouse.android.xw4; import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Color; import android.util.AttributeSet; import android.view.View; +import android.widget.ImageView; import android.widget.RadioButton; import android.widget.RadioGroup; import android.widget.ScrollView; @@ -30,6 +33,11 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import com.google.zxing.BarcodeFormat; +import com.google.zxing.MultiFormatWriter; +import com.google.zxing.WriterException; +import com.google.zxing.common.BitMatrix; + import org.eehouse.android.xw4.DlgDelegate.DlgClickNotify.InviteMeans; import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnType; import org.eehouse.android.xw4.loc.LocUtils; @@ -38,6 +46,7 @@ public class InviteView extends ScrollView implements RadioGroup.OnCheckedChangeListener { private static final String TAG = InviteView.class.getSimpleName(); + private static final int QRCODE_SIZE = 512; public interface ItemClicked { public void meansClicked( InviteMeans means ); @@ -79,7 +88,9 @@ public class InviteView extends ScrollView RadioButton button = (RadioButton)LocUtils .inflate( context, R.layout.invite_radio ); button.setText( LocUtils.getString( context, means.getUserDescID() ) ); - mGroupHow.addView( button ); + // -2: place before QR code and its explanatory text + int where = mGroupHow.getChildCount() - 2; + mGroupHow.addView( button, where ); mHowMeans.put( button, means ); } @@ -100,6 +111,14 @@ public class InviteView extends ScrollView return this; } + public InviteView setNli( NetLaunchInfo nli ) + { + if ( null != nli ) { + startQRCodeThread( nli ); + } + return this; + } + public InviteView setCallbacks( ItemClicked procs ) { mProcs = procs; return this; @@ -117,7 +136,6 @@ public class InviteView extends ScrollView result = mHowMeans.get(checked); } } - Log.d( TAG, "getChoice() => %s", result ); return result; } @@ -163,4 +181,37 @@ public class InviteView extends ScrollView findViewById( R.id.who_empty ) .setVisibility( showEmpty ? View.VISIBLE : View.INVISIBLE ); } + + private void startQRCodeThread( NetLaunchInfo nli ) + { + final String url = nli.makeLaunchUri( getContext() ).toString(); + new Thread( new Runnable() { + @Override + public void run() { + try { + MultiFormatWriter multiFormatWriter = new MultiFormatWriter(); + BitMatrix bitMatrix = multiFormatWriter.encode( url, BarcodeFormat.QR_CODE, + QRCODE_SIZE, QRCODE_SIZE ); + final Bitmap bitmap = Bitmap.createBitmap( QRCODE_SIZE, QRCODE_SIZE, + Bitmap.Config.ARGB_8888 ); + for ( int ii = 0; ii < QRCODE_SIZE; ++ii ) { + for ( int jj = 0; jj < QRCODE_SIZE; ++jj ) { + bitmap.setPixel( ii, jj, bitMatrix.get(ii, jj) + ? Color.BLACK : Color.WHITE ); + } + } + + post( new Runnable() { + @Override + public void run() { + ImageView iv = (ImageView)findViewById( R.id.qr_view ); + iv.setImageBitmap( bitmap ); + } + } ); + } catch ( WriterException we ) { + Log.ex( TAG, we ); + } + } + } ).start(); + } } diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/NetLaunchInfo.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/NetLaunchInfo.java index 9eab7e334..7b7f82b80 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/NetLaunchInfo.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/NetLaunchInfo.java @@ -588,7 +588,7 @@ public class NetLaunchInfo implements Serializable { String host = LocUtils.getString( context, R.string.invite_host ); host = NetUtils.forceHost( host ); Uri.Builder ub = new Uri.Builder() - .scheme( "http" ) + .scheme( "http" ) // PENDING: should be https soon .path( String.format( "//%s%s", host, LocUtils.getString(context, R.string.invite_prefix) ) ); appendInt( ub, LANG_KEY, lang ); diff --git a/xwords4/android/app/src/main/res/layout/invite_view.xml b/xwords4/android/app/src/main/res/layout/invite_view.xml index 6d1f654c0..0222a3b3f 100644 --- a/xwords4/android/app/src/main/res/layout/invite_view.xml +++ b/xwords4/android/app/src/main/res/layout/invite_view.xml @@ -52,7 +52,21 @@ + > + + + + + Who? empty expl + + Or just have your opponent scan this QRCode + How?