diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/MQTTUtils.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/MQTTUtils.java index 9227c660b..15b37243a 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/MQTTUtils.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/MQTTUtils.java @@ -21,6 +21,7 @@ package org.eehouse.android.xw4; import android.content.Context; +import android.content.Intent; import android.os.Build; import org.eclipse.paho.client.mqttv3.IMqttActionListener; @@ -60,7 +61,7 @@ public class MQTTUtils extends Thread implements IMqttActionListener, MqttCallba private MqttAsyncClient mClient; private String mDevID; - private String mTopic; + private String[] mTopics = { null, null }; private Context mContext; private MsgThread mMsgThread; private LinkedBlockingQueue mOutboundQueue = new LinkedBlockingQueue<>(); @@ -166,7 +167,7 @@ public class MQTTUtils extends Thread implements IMqttActionListener, MqttCallba me.printStackTrace(); break; } catch ( InterruptedException ie ) { - ie.printStackTrace(); + // ie.printStackTrace(); break; } } @@ -225,10 +226,8 @@ public class MQTTUtils extends Thread implements IMqttActionListener, MqttCallba { Log.d( TAG, "%H.()", this ); mContext = context; - String[] topic = {null}; - mDevID = XwJNI.dvc_getMQTTDevID( topic ); + mDevID = XwJNI.dvc_getMQTTDevID( mTopics ); Assert.assertTrueNR( 16 == mDevID.length() ); - mTopic = topic[0]; mMsgThread = new MsgThread(); String host = XWPrefs.getPrefsString( context, R.string.key_mqtt_host ); @@ -522,8 +521,7 @@ public class MQTTUtils extends Thread implements IMqttActionListener, MqttCallba public void messageArrived( String topic, MqttMessage message ) throws Exception { Log.d( TAG, "%H.messageArrived(topic=%s)", this, topic ); - Assert.assertTrueNR( topic.equals(mTopic) ); - mMsgThread.add( message.getPayload() ); + mMsgThread.add( topic, message.getPayload() ); ConnStatusHandler .updateStatusIn( mContext, CommsConnType.COMMS_CONN_MQTT, true ); @@ -541,10 +539,13 @@ public class MQTTUtils extends Thread implements IMqttActionListener, MqttCallba private void subscribe() { + Assert.assertTrueNR( null != mTopics && 2 == mTopics.length ); final int qos = XWPrefs.getPrefsInt( mContext, R.string.key_mqtt_qos, 2 ); + int qoss[] = { qos, qos }; + setState( State.SUBSCRIBING ); try { - mClient.subscribe( mTopic, qos, null, this ); + mClient.subscribe( mTopics, qoss, null, this ); // Log.d( TAG, "subscribed to %s", mTopic ); } catch ( MqttException ex ) { ex.printStackTrace(); @@ -581,10 +582,10 @@ public class MQTTUtils extends Thread implements IMqttActionListener, MqttCallba } private class MsgThread extends Thread { - private LinkedBlockingQueue mQueue = new LinkedBlockingQueue<>(); + private LinkedBlockingQueue mQueue = new LinkedBlockingQueue<>(); - void add( byte[] msg ) { - mQueue.add( msg ); + void add( String topic, byte[] msg ) { + mQueue.add( new MessagePair( topic, msg ) ); } @Override @@ -594,17 +595,39 @@ public class MQTTUtils extends Thread implements IMqttActionListener, MqttCallba Log.d( TAG, "%H.MsgThread.run() starting", MQTTUtils.this ); for ( ; ; ) { try { - byte[] packet = mQueue.take(); - XwJNI.dvc_parseMQTTPacket( packet ); + MessagePair pair = mQueue.take(); + String topic = pair.mTopic; + if ( topic.equals( mTopics[0] ) ) { + XwJNI.dvc_parseMQTTPacket( pair.mPacket ); + } else if ( topic.equals( mTopics[1] ) ) { + postNotification( pair ); + } } catch ( InterruptedException ie ) { // Assert.failDbg(); break; + } catch ( JSONException je ) { + Log.e( TAG, "run() ex: %s", je ); } } long now = Utils.getCurSeconds(); Log.d( TAG, "%H.MsgThread.run() exiting after %d seconds", MQTTUtils.this, now - startTime ); } + + private void postNotification( MessagePair pair ) throws JSONException + { + JSONObject obj = new JSONObject( new String(pair.mPacket) ); + String msg = obj.optString( "msg" ); + if ( null != msg ) { + String title = obj.optString( "title" ); + if ( null == title ) { + title = LocUtils.getString( mContext, R.string.remote_msg_title ); + } + Intent alertIntent = GamesListDelegate.makeAlertIntent( mContext, msg ); + int code = msg.hashCode() ^ title.hashCode(); + Utils.postNotification( mContext, alertIntent, title, msg, code ); + } + } } public static void handleMessage( Context context, CommsAddrRec from, diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/UpdateCheckReceiver.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/UpdateCheckReceiver.java index 6b85b5ebc..54653a44c 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/UpdateCheckReceiver.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/UpdateCheckReceiver.java @@ -150,8 +150,7 @@ public class UpdateCheckReceiver extends BroadcastReceiver { params.put( k_APP, appParams ); params.put( k_DEVID, XWPrefs.getDevID( context ) ); - String[] topic = {null}; - String devID = XwJNI.dvc_getMQTTDevID( topic ); + String devID = XwJNI.dvc_getMQTTDevID( null ); params.put( k_MQTTDEVID, devID ); } catch ( org.json.JSONException jse ) { Log.ex( TAG, jse ); diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/jni/XwJNI.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/jni/XwJNI.java index b68ad87e7..eb843f64d 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/jni/XwJNI.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/jni/XwJNI.java @@ -136,9 +136,10 @@ public class XwJNI { cleanGlobals(); } - public static String dvc_getMQTTDevID( String[] topic ) + public static String dvc_getMQTTDevID( String[] topics ) { - return dvc_getMQTTDevID( getJNI().m_ptrGlobals, topic ); + Assert.assertTrueNR( null == topics || 2 == topics.length ); + return dvc_getMQTTDevID( getJNI().m_ptrGlobals, topics ); } public static void dvc_resetMQTTDevID() diff --git a/xwords4/android/jni/xwjni.c b/xwords4/android/jni/xwjni.c index dd2f80c7f..71a564b8b 100644 --- a/xwords4/android/jni/xwjni.c +++ b/xwords4/android/jni/xwjni.c @@ -629,7 +629,7 @@ streamFromJStream( MPFORMAL JNIEnv* env, VTableMgr* vtMgr, jbyteArray jstream ) JNIEXPORT jstring JNICALL Java_org_eehouse_android_xw4_jni_XwJNI_dvc_1getMQTTDevID -( JNIEnv* env, jclass C, jlong jniGlobalPtr, jobjectArray jTopicOut ) +( JNIEnv* env, jclass C, jlong jniGlobalPtr, jobjectArray jTopicsOut ) { jstring result; DVC_HEADER(jniGlobalPtr); @@ -638,12 +638,18 @@ Java_org_eehouse_android_xw4_jni_XwJNI_dvc_1getMQTTDevID XP_UCHAR buf[64]; - if ( !!jTopicOut ) { + if ( !!jTopicsOut ) { formatMQTTTopic( &devID, buf, VSIZE(buf) ); jstring jtopic = (*env)->NewStringUTF( env, buf ); - XP_ASSERT( 1 == (*env)->GetArrayLength( env, jTopicOut ) ); /* fired */ - (*env)->SetObjectArrayElement( env, jTopicOut, 0, jtopic ); + (*env)->SetObjectArrayElement( env, jTopicsOut, 0, jtopic ); deleteLocalRef( env, jtopic ); + + if ( 1 < (*env)->GetArrayLength( env, jTopicsOut ) ) { + formatMQTTCtrlTopic( &devID, buf, VSIZE(buf) ); + jstring jtopic = (*env)->NewStringUTF( env, buf ); + (*env)->SetObjectArrayElement( env, jTopicsOut, 1, jtopic ); + deleteLocalRef( env, jtopic ); + } } formatMQTTDevID( &devID, buf, VSIZE(buf) ); diff --git a/xwords4/common/comtypes.h b/xwords4/common/comtypes.h index e4ce74ce9..d2c35f93b 100644 --- a/xwords4/common/comtypes.h +++ b/xwords4/common/comtypes.h @@ -285,6 +285,7 @@ typedef uint64_t MQTTDevID; # define MQTTDevID_FMT "%016llX" #endif # define MQTTTopic_FMT "xw4/device/" MQTTDevID_FMT +# define MQTTCtrlTopic_FMT "xw4/msg/" MQTTDevID_FMT /* Used by scoring code and engine as fast representation of moves. */ typedef struct _MoveInfoTile { diff --git a/xwords4/common/strutils.c b/xwords4/common/strutils.c index f424747a6..8f25cb264 100644 --- a/xwords4/common/strutils.c +++ b/xwords4/common/strutils.c @@ -621,6 +621,13 @@ formatMQTTTopic( const MQTTDevID* devid, XP_UCHAR* buf, XP_U16 bufLen ) return buf; } +const XP_UCHAR* +formatMQTTCtrlTopic( const MQTTDevID* devid, XP_UCHAR* buf, XP_U16 bufLen ) +{ + XP_SNPRINTF( buf, bufLen, MQTTCtrlTopic_FMT, *devid ); + return buf; +} + XP_Bool strToMQTTCDevID( const XP_UCHAR* str, MQTTDevID* result ) { diff --git a/xwords4/common/strutils.h b/xwords4/common/strutils.h index 1ce35e482..53ed4d676 100644 --- a/xwords4/common/strutils.h +++ b/xwords4/common/strutils.h @@ -115,6 +115,7 @@ XP_Bool smsToBin( XP_U8* out, XP_U16* outlen, const XP_UCHAR* in, XP_U16 inlen ) #endif const XP_UCHAR* formatMQTTTopic( const MQTTDevID* devid, XP_UCHAR* buf, XP_U16 bufLen ); +const XP_UCHAR* formatMQTTCtrlTopic( const MQTTDevID* devid, XP_UCHAR* buf, XP_U16 bufLen ); const XP_UCHAR* formatMQTTDevID( const MQTTDevID* devid, XP_UCHAR* buf, XP_U16 bufLen ); XP_Bool strToMQTTCDevID( const XP_UCHAR* str, MQTTDevID* result );