From 120748416b7fc1640604f9496461ff3c5fc0f3f2 Mon Sep 17 00:00:00 2001
From: Eric House <xwords@eehouse.org>
Date: Wed, 22 May 2013 06:15:07 -0700
Subject: [PATCH] handle GCM messages containing data, changing clientVers so
 server knows we can.  And send to relay in AsyncTask rather than UI thread.

---
 xwords4/android/XWords4/jni/Android.mk        |   2 +-
 .../eehouse/android/xw4/GCMIntentService.java |   9 +
 .../org/eehouse/android/xw4/RelayService.java | 155 +++++++++++++-----
 3 files changed, 120 insertions(+), 46 deletions(-)

diff --git a/xwords4/android/XWords4/jni/Android.mk b/xwords4/android/XWords4/jni/Android.mk
index 67a4961aa..2c72a0f92 100644
--- a/xwords4/android/XWords4/jni/Android.mk
+++ b/xwords4/android/XWords4/jni/Android.mk
@@ -36,7 +36,7 @@ local_DEFINES += \
 	-DHASH_STREAM \
 	-DXWFEATURE_BASE64 \
 	-DXWFEATURE_DEVID \
-	-DINITIAL_CLIENT_VERS=2 \
+	-DINITIAL_CLIENT_VERS=3 \
 	-DRELAY_ROOM_DEFAULT=\"\" \
 	-D__LITTLE_ENDIAN \
 
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 532e70329..23285a1fa 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GCMIntentService.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GCMIntentService.java
@@ -62,6 +62,15 @@ public class GCMIntentService extends GCMBaseIntentService {
         if ( null != value && Boolean.parseBoolean( value ) ) {
             RelayReceiver.RestartTimer( context, true );
         }
+
+        value = intent.getStringExtra( "msg64" );
+        if ( null != value ) {
+            String connname = intent.getStringExtra( "connname" );
+            if ( null != connname ) {
+                RelayService.processMsg( context, connname, value );
+            }
+        }
+
         value = intent.getStringExtra( "checkUpdates" );
         if ( null != value && Boolean.parseBoolean( value ) ) {
             UpdateCheckReceiver.checkVersions( context, true );
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/RelayService.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/RelayService.java
index bc4d2d179..0c2afed9f 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/RelayService.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/RelayService.java
@@ -23,6 +23,7 @@ package org.eehouse.android.xw4;
 import android.app.Service;
 import android.content.Context;
 import android.content.Intent;
+import android.os.AsyncTask;
 import android.os.IBinder;
 import java.io.ByteArrayOutputStream;
 import java.io.DataOutputStream;
@@ -32,11 +33,34 @@ import java.util.HashMap;
 import java.util.Iterator;
 
 import org.eehouse.android.xw4.jni.GameSummary;
+import org.eehouse.android.xw4.jni.XwJNI;
 
 public class RelayService extends Service {
     private static final int MAX_SEND = 1024;
     private static final int MAX_BUF = MAX_SEND - 2;
 
+    private static final String CMD_STR = "CMD";
+    private static final int PROCESS_MSG = 1;
+    private static final String MSG = "MSG";
+    private static final String RELAY_ID = "RELAY_ID";
+
+    public static void processMsg( Context context, String relayId, 
+                                   String msg64 )
+    {
+        byte[] msg = XwJNI.base64Decode( msg64 );
+        Intent intent = getIntentTo( context, PROCESS_MSG )
+            .putExtra( MSG, msg )
+            .putExtra( RELAY_ID, relayId );
+        context.startService( intent );
+    }
+
+    private static Intent getIntentTo( Context context, int cmd )
+    {
+        Intent intent = new Intent( context, RelayService.class );
+        intent.putExtra( CMD_STR, cmd );
+        return intent;
+    }
+
     @Override
     public void onCreate()
     {
@@ -57,6 +81,26 @@ public class RelayService extends Service {
         return null;
     }
 
+    @Override
+    public int onStartCommand( Intent intent, int flags, int startId )
+    {
+        int cmd = intent.getIntExtra( CMD_STR, -1 );
+        switch( cmd ) {
+        case PROCESS_MSG:
+            String[] relayIDs = new String[1];
+            relayIDs[0] = intent.getStringExtra( RELAY_ID );
+            long[] rowIDs = DBUtils.getRowIDsFor( this, relayIDs[0] );
+            if ( 0 < rowIDs.length ) {
+                byte[][][] msgs = new byte[1][1][1];
+                msgs[0][0] = intent.getByteArrayExtra( MSG );
+                process( msgs, rowIDs, relayIDs );
+            }
+            break;
+        }
+        stopSelf( startId );
+        return Service.START_NOT_STICKY;
+    }
+
     private void setupNotification( String[] relayIDs )
     {
         for ( String relayID : relayIDs ) {
@@ -80,67 +124,80 @@ public class RelayService extends Service {
         long[][] rowIDss = new long[1][];
         String[] relayIDs = DBUtils.getRelayIDs( this, rowIDss );
         if ( null != relayIDs && 0 < relayIDs.length ) {
-            long[] rowIDs = rowIDss[0];
             byte[][][] msgs = NetUtils.queryRelay( this, relayIDs );
-
-            if ( null != msgs ) {
-                RelayMsgSink sink = new RelayMsgSink();
-                int nameCount = relayIDs.length;
-                ArrayList<String> idsWMsgs =
-                    new ArrayList<String>( nameCount );
-                for ( int ii = 0; ii < nameCount; ++ii ) {
-                    byte[][] forOne = msgs[ii];
-                    // if game has messages, open it and feed 'em
-                    // to it.
-                    if ( null == forOne ) {
-                        // Nothing for this relayID
-                    } else if ( BoardActivity.feedMessages( rowIDs[ii], forOne )
-                                || GameUtils.feedMessages( this, rowIDs[ii],
-                                                           forOne, null,
-                                                           sink ) ) {
-                        idsWMsgs.add( relayIDs[ii] );
-                    } else {
-                        DbgUtils.logf( "dropping message for %s (rowid %d)",
-                                       relayIDs[ii], rowIDs[ii] );
-                    }
-                }
-                if ( 0 < idsWMsgs.size() ) {
-                    String[] tmp = new String[idsWMsgs.size()];
-                    idsWMsgs.toArray( tmp );
-                    setupNotification( tmp );
-                }
-                sink.send( this );
-            }
+            process( msgs, rowIDss[0], relayIDs );
         }
     }
 
-    private static void sendToRelay( Context context,
-                                     HashMap<String,ArrayList<byte[]>> msgHash )
+    private void process( byte[][][] msgs, long[] rowIDs, String[] relayIDs )
     {
-        // format: total msg lenth: 2
-        //         number-of-relayIDs: 2
-        //         for-each-relayid: relayid + '\n': varies
-        //                           message count: 1
-        //                           for-each-message: length: 2
-        //                                             message: varies
+        if ( null != msgs ) {
+            RelayMsgSink sink = new RelayMsgSink();
+            int nameCount = relayIDs.length;
+            ArrayList<String> idsWMsgs = new ArrayList<String>( nameCount );
 
-        if ( null != msgHash ) {
+            for ( int ii = 0; ii < nameCount; ++ii ) {
+                byte[][] forOne = msgs[ii];
+
+                // if game has messages, open it and feed 'em to it.
+                if ( null == forOne ) {
+                    // Nothing for this relayID
+                } else if ( BoardActivity.feedMessages( rowIDs[ii], forOne )
+                            || GameUtils.feedMessages( this, rowIDs[ii],
+                                                       forOne, null,
+                                                       sink ) ) {
+                    idsWMsgs.add( relayIDs[ii] );
+                } else {
+                    DbgUtils.logf( "message for %s (rowid %d) not consumed",
+                                   relayIDs[ii], rowIDs[ii] );
+                }
+            }
+            if ( 0 < idsWMsgs.size() ) {
+                String[] tmp = new String[idsWMsgs.size()];
+                idsWMsgs.toArray( tmp );
+                setupNotification( tmp );
+            }
+            sink.send( this );
+        }
+    }
+
+    private static class AsyncSender extends AsyncTask<Void, Void, Void> {
+        private Context m_context;
+        private HashMap<String,ArrayList<byte[]>> m_msgHash;
+
+        public AsyncSender( Context context, 
+                            HashMap<String,ArrayList<byte[]>> msgHash )
+        {
+            m_context = context;
+            m_msgHash = msgHash;
+        }
+
+        @Override
+        protected Void doInBackground( Void... ignored )
+        {
+            // format: total msg lenth: 2
+            //         number-of-relayIDs: 2
+            //         for-each-relayid: relayid + '\n': varies
+            //                           message count: 1
+            //                           for-each-message: length: 2
+            //                                             message: varies
+
+            // Build up a buffer containing everything but the total
+            // message length and number of relayIDs in the message.
             try {
-                // Build up a buffer containing everything but the total
-                // message length and number of relayIDs in the message.
                 ByteArrayOutputStream store = 
                     new ByteArrayOutputStream( MAX_BUF ); // mem
                 DataOutputStream outBuf = new DataOutputStream( store );
                 int msgLen = 4;          // relayID count + protocol stuff
                 int nRelayIDs = 0;
         
-                Iterator<String> iter = msgHash.keySet().iterator();
+                Iterator<String> iter = m_msgHash.keySet().iterator();
                 while ( iter.hasNext() ) {
                     String relayID = iter.next();
                     int thisLen = 1 + relayID.length(); // string and '\n'
                     thisLen += 2;                        // message count
 
-                    ArrayList<byte[]> msgs = msgHash.get( relayID );
+                    ArrayList<byte[]> msgs = m_msgHash.get( relayID );
                     for ( byte[] msg : msgs ) {
                         thisLen += 2 + msg.length;
                     }
@@ -161,10 +218,9 @@ public class RelayService extends Service {
                     }
                     msgLen += thisLen;
                 }
-
                 // Now open a real socket, write size and proto, and
                 // copy in the formatted buffer
-                Socket socket = NetUtils.makeProxySocket( context, 8000 );
+                Socket socket = NetUtils.makeProxySocket( m_context, 8000 );
                 if ( null != socket ) {
                     DataOutputStream outStream = 
                         new DataOutputStream( socket.getOutputStream() );
@@ -179,6 +235,15 @@ public class RelayService extends Service {
             } catch ( java.io.IOException ioe ) {
                 DbgUtils.loge( ioe );
             }
+            return null;
+        } // doInBackground
+    }
+
+    private static void sendToRelay( Context context,
+                                     HashMap<String,ArrayList<byte[]>> msgHash )
+    {
+        if ( null != msgHash ) {
+            new AsyncSender( context, msgHash ).execute();
         } else {
             DbgUtils.logf( "sendToRelay: null msgs" );
         }