Stack Exchange
Delphi Android Java class that inherits from an interface
I'm trying to implement the latest version of Google Play Services (15.01) in Delphi. I have merged the relevant libraries into a single jar file, and extracted a bridge file with java2op. Everything was running pretty smooth, until i ran into this showstopper:
I have this class:
JRoomConfigClass = interface(JObjectClass)
['{88F39239-F51D-4BA0-8131-24EBF070A584}']
{class} function builder(P1: JRoomUpdateListener): JRoomConfig_Builder; 
cdecl; overload;
{class} function builder(P1: JRoomUpdateCallback): JRoomConfig_Builder; 
cdecl; overload;
{class} function createAutoMatchCriteria(P1: Integer; P2: Integer; P3: 
Int64): JBundle; cdecl;
end;

[JavaSignature('com/google/android/gms/games/multiplayer/realtime/
RoomConfig')]
JRoomConfig = interface(JObject)
['{EF764B81-BF25-490C-8562-D9DC6BB337AD}']
function getAutoMatchCriteria: JBundle; cdecl;
function getInvitationId: JString; cdecl;
function getInvitedPlayerIds: TJavaObjectArray<JString>; cdecl;
function getMessageReceivedListener: JRealTimeMessageReceivedListener; cdecl;
function getOnMessageReceivedListener: JOnRealTimeMessageReceivedListener; 
cdecl;
function getRoomStatusUpdateCallback: JRoomStatusUpdateCallback; cdecl;
function getRoomStatusUpdateListener: JRoomStatusUpdateListener; cdecl;
function getRoomUpdateCallback: JRoomUpdateCallback; cdecl;
function getRoomUpdateListener: JRoomUpdateListener; cdecl;
function getVariant: Integer; cdecl;
function zzch: Jrealtime_zzh; cdecl;
end;
TJRoomConfig = class(TJavaGenericImport<JRoomConfigClass, JRoomConfig>) end;

i call method "builder":
rtmConfigBuilder := TJRoomConfig.JavaClass.builder(RoomUpdateCallback);

But RoomUpdateCallback is defined like this:
JRoomUpdateCallbackClass = interface(JRoomUpdateListenerClass)
['{B7973699-780A-4D76-9585-D113DD245CC5}']
{class} function init: JRoomUpdateCallback; cdecl;
end;
[JavaSignature('com/google/android/gms/games/multiplayer/realtime/
RoomUpdateCallback')]

JRoomUpdateCallback = interface(JRoomUpdateListener)
['{0CA35AB2-8AA9-4604-909B-68DE93112867}']
procedure onJoinedRoom(P1: Integer; P2: JRoom); cdecl;
procedure onLeftRoom(P1: Integer; P2: JString); cdecl;
procedure onRoomConnected(P1: Integer; P2: JRoom); cdecl;
procedure onRoomCreated(P1: Integer; P2: JRoom); cdecl;
end;
TJRoomUpdateCallback = class(TJavaGenericImport<JRoomUpdateCallbackClass, 
JRoomUpdateCallback>) end;

So, it's not an interface, which means, that i can't use the usual listener approach:
TRoomUpdateListener = class(TJavaLocal, JRoomUpdateCallback)
  procedure onJoinedRoom(P1: Integer; P2: JRoom); cdecl;
  procedure onLeftRoom(P1: Integer; P2: JString); cdecl;
  procedure onRoomConnected(P1: Integer; P2: JRoom); cdecl;
  procedure onRoomCreated(P1: Integer; P2: JRoom); cdecl;
 end;

But JRoomUpdateCallback is a descendant of JRoomUpdateListener which is an interface:
JRoomUpdateListenerClass = interface(IJavaClass)
['{62795DB4-DDD0-48F2-AABA-644CC96D5E6E}']
end;

[JavaSignature('com/google/android/gms/games/multiplayer/realtime/
RoomUpdateListener')]
JRoomUpdateListener = interface(IJavaInstance)
['{236212AF-A72A-4DEC-BB73-E0B42E80F7A1}']
procedure onJoinedRoom(P1: Integer; P2: JRoom); cdecl;
procedure onLeftRoom(P1: Integer; P2: JString); cdecl;
procedure onRoomConnected(P1: Integer; P2: JRoom); cdecl;
procedure onRoomCreated(P1: Integer; P2: JRoom); cdecl;
end;
TJRoomUpdateListener = class(TJavaGenericImport<JRoomUpdateListenerClass, 
JRoomUpdateListener>) end;

How do i implement this? Is it at all possible?

I found similar questions in the Android section of SO like (https://stackoverflow.com/questions/26511788) and you aren't even close. The Android dev's are setting up a game instance first...

That's not it. The question is how to somehow catch the events from the java class. As far as i know you cannot descent from a java class, but i was hoping there was some way, because the java class implements the interface.

The import you have there does not seem to make sense. Where did you obtain the .jar from?

The jar was merged from the individual jars in version 15.01, downloaded from maven repository.

It looks to me like you wish to define a Delphi class implementing an Android listener interface. The listener interface is JRoomUpdateCallback, which inherits from JRoomUpdateListener, which inherits from IJavaInstance, the base Android/Java interface representation. So far, you appear to be describing a perfect scenario where your listener class can be built and yet you say there is some obstacle stopping you. I'm not sure what this obstacle is, and apologies if I'm missing something stated clearly, but what doesn't work? It looks like it should work just fine.

There's no way around it. I had to code some java. this is what i put in my java library, if somebody can benefit from it.
package cometsoft.com.roomconfiglib;

import 
com.google.android.gms.games.multiplayer.realtime.OnRealTimeMessageReceivedListener;
import com.google.android.gms.games.multiplayer.realtime.RealTimeMessage;
import com.google.android.gms.games.multiplayer.realtime.Room;
import com.google.android.gms.games.multiplayer.realtime.RoomConfig;
import com.google.android.gms.games.multiplayer.realtime.RoomStatusUpdateCallback;
import com.google.android.gms.games.multiplayer.realtime.RoomUpdateCallback;

import android.os.Bundle;
import android.support.annotation.NonNull;

import java.util.ArrayList;
import java.util.List;

interface RoomConfigListener {
    public abstract void onRoomConnecting(@android.support.annotation.Nullable 
com.google.android.gms.games.multiplayer.realtime.Room room);

public abstract void onRoomAutoMatching(@android.support.annotation.Nullable 
com.google.android.gms.games.multiplayer.realtime.Room room);

public abstract void onPeerInvitedToRoom(@android.support.annotation.Nullable 
com.google.android.gms.games.multiplayer.realtime.Room room, 
   @android.support.annotation.NonNull java.util.List<java.lang.String> list);

public abstract void onPeerDeclined(@android.support.annotation.Nullable 
com.google.android.gms.games.multiplayer.realtime.Room room, 
@android.support.annotation.NonNull java.util.List<java.lang.String> list);

public abstract void onPeerJoined(@android.support.annotation.Nullable 
   com.google.android.gms.games.multiplayer.realtime.Room room, 
   @android.support.annotation.NonNull java.util.List<java.lang.String> list);

public abstract void onPeerLeft(@android.support.annotation.Nullable 
   com.google.android.gms.games.multiplayer.realtime.Room room, 
   @android.support.annotation.NonNull java.util.List<java.lang.String> list);

public abstract void onConnectedToRoom(@android.support.annotation.Nullable 
   com.google.android.gms.games.multiplayer.realtime.Room room);

public abstract void onDisconnectedFromRoom(@android.support.annotation.Nullable 
   com.google.android.gms.games.multiplayer.realtime.Room room);

public abstract void onPeersConnected(@android.support.annotation.Nullable 
   com.google.android.gms.games.multiplayer.realtime.Room room, 
   @android.support.annotation.NonNull java.util.List<java.lang.String> list);

public abstract void onPeersDisconnected(@android.support.annotation.Nullable 
   com.google.android.gms.games.multiplayer.realtime.Room room, 
   @android.support.annotation.NonNull java.util.List<java.lang.String> list);

public abstract void onP2PConnected(@android.support.annotation.NonNull 
   java.lang.String s);

public abstract void onP2PDisconnected(@android.support.annotation.NonNull 
   java.lang.String s);

public abstract void onRoomCreated(int i, @android.support.annotation.Nullable 
   com.google.android.gms.games.multiplayer.realtime.Room room);

public abstract void onJoinedRoom(int i, @android.support.annotation.Nullable 
   com.google.android.gms.games.multiplayer.realtime.Room room);

public abstract void onLeftRoom(int i, @android.support.annotation.NonNull 
   java.lang.String s);

public abstract void onRoomConnected(int i, @android.support.annotation.Nullable 
   com.google.android.gms.games.multiplayer.realtime.Room room);

void onRealTimeMessageReceived(@android.support.annotation.NonNull 
   com.google.android.gms.games.multiplayer.realtime.RealTimeMessage 
   realTimeMessage);

}

public class RoomConfigBuilder {

    private RoomConfigListener mRoomConfigListener;
    private Bundle mautoMatchCriteria;

    private RoomUpdateCallback mRoomUpdateCallback = new RoomUpdateCallback() {

        @Override
        public void onRoomCreated(int statusCode, Room room) {
            mRoomConfigListener.onRoomCreated(statusCode, room);
        }

        @Override
        public void onRoomConnected(int statusCode, Room room) {
            mRoomConfigListener.onRoomConnected(statusCode, room);
        }

        @Override
        public void onJoinedRoom(int statusCode, Room room) {
            mRoomConfigListener.onJoinedRoom(statusCode, room);
        }

        @Override
        public void onLeftRoom(int statusCode, @NonNull String roomId) {
            mRoomConfigListener.onLeftRoom(statusCode, roomId);
        }

    };

    private RoomStatusUpdateCallback mRoomStatusUpdateCallback = new 
       RoomStatusUpdateCallback() {

        @Override
        public void onConnectedToRoom(Room room) {
            mRoomConfigListener.onConnectedToRoom(room);
        }

        @Override
        public void onDisconnectedFromRoom(Room room) {
            mRoomConfigListener.onDisconnectedFromRoom(room);
        }

        @Override
        public void onPeerDeclined(Room room, @NonNull List<String> arg1) {
            mRoomConfigListener.onPeerDeclined(room, arg1);
        }

        @Override
        public void onPeerInvitedToRoom(Room room, @NonNull List<String> arg1) {
            mRoomConfigListener.onPeerInvitedToRoom(room, arg1);
        }

        @Override
        public void onP2PDisconnected(@NonNull String participant) {
            mRoomConfigListener.onP2PDisconnected(participant);
        }

        @Override
        public void onP2PConnected(@NonNull String participant) {
            mRoomConfigListener.onP2PConnected(participant);
        }

        @Override
        public void onPeerJoined(Room room, @NonNull List<String> arg1) {
            mRoomConfigListener.onPeerJoined(room, arg1);
        }

        @Override
        public void onPeerLeft(Room room, @NonNull List<String> peersWhoLeft) {
            mRoomConfigListener.onPeerLeft(room, peersWhoLeft);
        }

        @Override
        public void onRoomAutoMatching(Room room) {
            mRoomConfigListener.onRoomAutoMatching(room);
        }

        @Override
        public void onRoomConnecting(Room room) {
            mRoomConfigListener.onRoomConnecting(room);
        }

        @Override
        public void onPeersConnected(Room room, @NonNull List<String> peers) {
            mRoomConfigListener.onPeersConnected(room, peers);
        }

        @Override
        public void onPeersDisconnected(Room room, @NonNull List<String> peers) {
            mRoomConfigListener.onPeersDisconnected(room, peers);
        }
    };

    private OnRealTimeMessageReceivedListener mOnRealTimeMessageReceivedListener = 
       new OnRealTimeMessageReceivedListener() {
        @Override
        public void onRealTimeMessageReceived(@NonNull RealTimeMessage 
           realTimeMessage) {
            mRoomConfigListener.onRealTimeMessageReceived(realTimeMessage);
        }
    };

    public RoomConfig BuildRoomConfig(RoomConfigListener listener, Bundle 
           autoMatchCriteria, ArrayList<String> invitees, String invitationId) {
        mRoomConfigListener = listener;
        mautoMatchCriteria = autoMatchCriteria;
        RoomConfig.Builder mRoomConfigBuilder;

        mRoomConfigBuilder = 
           RoomConfig.builder(mRoomUpdateCallback)
           .setRoomStatusUpdateCallback(mRoomStatusUpdateCallback)
           .setOnMessageReceivedListener(mOnRealTimeMessageReceivedListener);

        if (invitees != null){
           mRoomConfigBuilder.addPlayersToInvite(invitees);
        }

        if (autoMatchCriteria != null){
            mRoomConfigBuilder.setAutoMatchCriteria(mautoMatchCriteria);
        }

        if (invitationId != null){
            mRoomConfigBuilder.setInvitationIdToAccept(invitationId);
        }

        return mRoomConfigBuilder.build();
    }
}


And that should translate to Delphi quite easily now?
