# HG changeset patch # User Medo # Date 1343918171 -7200 # Node ID 38acbfdb484fdec8279e38f517ce96c4013cb868 # Parent fec6fa1e460e628b0438cf1fe6451ce2f5e12e73 Hedgeroid: Started to implement RoomActivity diff -r fec6fa1e460e -r 38acbfdb484f project_files/Android-build/SDL-android-project/AndroidManifest.xml --- a/project_files/Android-build/SDL-android-project/AndroidManifest.xml Thu Aug 02 16:35:12 2012 +0200 +++ b/project_files/Android-build/SDL-android-project/AndroidManifest.xml Thu Aug 02 16:36:11 2012 +0200 @@ -72,5 +72,11 @@ android:screenOrientation="landscape" android:windowSoftInputMode="adjustPan" > + + \ No newline at end of file diff -r fec6fa1e460e -r 38acbfdb484f project_files/Android-build/SDL-android-project/res/layout/activity_netroom.xml --- a/project_files/Android-build/SDL-android-project/res/layout/activity_netroom.xml Thu Aug 02 16:35:12 2012 +0200 +++ b/project_files/Android-build/SDL-android-project/res/layout/activity_netroom.xml Thu Aug 02 16:36:11 2012 +0200 @@ -30,10 +30,10 @@ android:layout_marginRight="10dp" android:background="@drawable/box" > - + tools:layout="@layout/fragment_map" /> --> - + tools:layout="@layout/fragment_settings" /> --> - + tools:layout="@layout/fragment_teamlist" /> --> @@ -74,12 +74,12 @@ android:layout_below="@id/upperFrame" android:background="@drawable/box" > - + tools:layout="@layout/lobby_players_fragment" /> --> Level 1 Hedgewars Server Lobby + Room + Type here to chat @@ -118,7 +120,7 @@ An unexpected error has occurred: %1$s The server you tried to connect to is using an incompatible protocol. Unable to authenticate for your username. - The connection to the server was lost: %1$s + The connection to the server was lost. Please wait @@ -127,4 +129,10 @@ The server has requested a password to connect as "%1$s". Password remember password + Room name + Create new room + + Disconnected: %1$s + The room was closed because the owner left. + You were kicked from the room. diff -r fec6fa1e460e -r 38acbfdb484f project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/LobbyActivity.java --- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/LobbyActivity.java Thu Aug 02 16:35:12 2012 +0200 +++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/LobbyActivity.java Thu Aug 02 16:36:11 2012 +0200 @@ -1,8 +1,13 @@ package org.hedgewars.hedgeroid.netplay; import org.hedgewars.hedgeroid.R; +import org.hedgewars.hedgeroid.StartGameActivity; +import org.hedgewars.hedgeroid.netplay.Netplay.State; +import org.hedgewars.hedgeroid.netplay.NetplayStateFragment.NetplayStateListener; +import org.hedgewars.hedgeroid.netplay.TextInputDialog.TextInputDialogListener; import android.content.Context; +import android.content.Intent; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.support.v4.app.FragmentActivity; @@ -15,9 +20,10 @@ import android.widget.LinearLayout; import android.widget.TabHost; import android.widget.TextView; -import android.widget.Toast; -public class LobbyActivity extends FragmentActivity { +public class LobbyActivity extends FragmentActivity implements TextInputDialogListener, NetplayStateListener { + private static final int DIALOG_CREATE_ROOM = 0; + private TabHost tabHost; private Netplay netplay; @@ -79,7 +85,8 @@ public boolean onOptionsItemSelected(MenuItem item) { switch(item.getItemId()) { case R.id.room_create: - Toast.makeText(this, R.string.not_implemented_yet, Toast.LENGTH_SHORT).show(); + TextInputDialog dialog = new TextInputDialog(DIALOG_CREATE_ROOM, R.string.dialog_create_room_title, 0, R.string.dialog_create_room_hint); + dialog.show(getSupportFragmentManager(), "create_room_dialog"); return true; case R.id.disconnect: netplay.disconnect(); @@ -102,4 +109,31 @@ icicle.putString("currentTab", tabHost.getCurrentTabTag()); } } + + public void onTextInputDialogSubmitted(int dialogId, String text) { + if(text != null && text.length()>0) { + netplay.sendCreateRoom(text); + } + } + + public void onTextInputDialogCancelled(int dialogId) { + } + + public void onNetplayStateChanged(State newState) { + switch(newState) { + case CONNECTING: + case NOT_CONNECTED: + finish(); + break; + case ROOM: + case INGAME: + startActivity(new Intent(getApplicationContext(), RoomActivity.class)); + break; + case LOBBY: + // Do nothing + break; + default: + throw new IllegalStateException("Unknown connection state: "+newState); + } + } } diff -r fec6fa1e460e -r 38acbfdb484f project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/Netplay.java --- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/Netplay.java Thu Aug 02 16:35:12 2012 +0200 +++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/Netplay.java Thu Aug 02 16:36:11 2012 +0200 @@ -5,6 +5,7 @@ import org.hedgewars.hedgeroid.R; import org.hedgewars.hedgeroid.Utils; +import org.hedgewars.hedgeroid.netplay.JnaFrontlib.BoolCallback; import org.hedgewars.hedgeroid.netplay.JnaFrontlib.IntStrCallback; import org.hedgewars.hedgeroid.netplay.JnaFrontlib.MetaschemePtr; import org.hedgewars.hedgeroid.netplay.JnaFrontlib.NetconnPtr; @@ -40,11 +41,15 @@ public static final String EXTRA_PLAYERNAME = "playerName"; public static final String EXTRA_MESSAGE = "message"; public static final String EXTRA_HAS_ERROR = "hasError"; + public static final String EXTRA_REASON = "reason"; private static final String ACTIONPREFIX = "org.hedgewars.hedgeroid.netconn."; public static final String ACTION_DISCONNECTED = ACTIONPREFIX+"DISCONNECTED"; public static final String ACTION_CONNECTED = ACTIONPREFIX+"CONNECTED"; public static final String ACTION_PASSWORD_REQUESTED = ACTIONPREFIX+"PASSWORD_REQUESTED"; + public static final String ACTION_ENTERED_ROOM_FROM_LOBBY = ACTIONPREFIX+"ENTERED_ROOM"; + public static final String ACTION_LEFT_ROOM = ACTIONPREFIX+"LEFT_ROOM"; + public static final String ACTION_STATE_CHANGED = ACTIONPREFIX+"STATE_CHANGED"; public static final String DEFAULT_SERVER = "netserver.hedgewars.org"; public static final int DEFAULT_PORT = 46631; @@ -54,13 +59,14 @@ private final FromNetHandler fromNetHandler = new FromNetHandler(); private State state; - private int foregroundUsers = 0; + private int foregroundUsers = 0; // Reference counter of clients requesting foreground tick speed (fast ticks) + private boolean chief; // Do we control the current room? // null if there is no running connection (==state is NOT_CONNECTED) private ThreadedNetConnection connection; - public final PlayerList playerList = new PlayerList(); - public final RoomList roomList = new RoomList(); + public final Playerlist playerList = new Playerlist(); + public final Roomlist roomList = new Roomlist(); public final MessageLog lobbyChatlog; public final MessageLog roomChatlog; @@ -96,7 +102,7 @@ } clearState(); - state = State.CONNECTING; + changeState(State.CONNECTING); connection = ThreadedNetConnection.startConnection(appContext, fromNetHandler, name, host, port); connection.setFastTickRate(foregroundUsers > 0); } @@ -106,7 +112,12 @@ public void sendQuit(String message) { sendToNet(ThreadedNetConnection.ToNetHandler.MSG_SEND_QUIT, message); } public void sendRoomlistRequest() { sendToNet(ThreadedNetConnection.ToNetHandler.MSG_SEND_ROOMLIST_REQUEST); } public void sendPlayerInfoQuery(String name) { sendToNet(ThreadedNetConnection.ToNetHandler.MSG_SEND_PLAYER_INFO_REQUEST, name); } - public void sendChat(final String s) { sendToNet(ThreadedNetConnection.ToNetHandler.MSG_SEND_CHAT, s); } + public void sendChat(String s) { sendToNet(ThreadedNetConnection.ToNetHandler.MSG_SEND_CHAT, s); } + public void sendFollowPlayer(String nick) { sendToNet(ThreadedNetConnection.ToNetHandler.MSG_SEND_FOLLOW_PLAYER, nick); } + public void sendJoinRoom(String name) { sendToNet(ThreadedNetConnection.ToNetHandler.MSG_SEND_JOIN_ROOM, name); } + public void sendCreateRoom(String name) { sendToNet(ThreadedNetConnection.ToNetHandler.MSG_SEND_CREATE_ROOM, name); } + public void sendLeaveRoom(String message) { sendToNet(ThreadedNetConnection.ToNetHandler.MSG_SEND_LEAVE_ROOM, message); } + public void disconnect() { sendToNet(ThreadedNetConnection.ToNetHandler.MSG_DISCONNECT, "User Quit"); } private static Netplay instance; @@ -133,6 +144,17 @@ return state; } + private void changeState(State newState) { + if(newState != state) { + state = newState; + broadcastManager.sendBroadcastSync(new Intent(ACTION_STATE_CHANGED)); + } + } + + public boolean isChief() { + return chief; + } + /** * Indicate that you want network messages to be checked regularly (several times per second). * As long as nobody requests fast ticks, the network is only checked once every few seconds @@ -191,15 +213,19 @@ final class FromNetHandler extends Handler { public static final int MSG_LOBBY_JOIN = 0; public static final int MSG_LOBBY_LEAVE = 1; - public static final int MSG_CHAT = 2; - public static final int MSG_MESSAGE = 3; - public static final int MSG_ROOM_ADD = 4; - public static final int MSG_ROOM_UPDATE = 5; - public static final int MSG_ROOM_DELETE = 6; - public static final int MSG_ROOMLIST = 7; - public static final int MSG_CONNECTED = 8; - public static final int MSG_DISCONNECTED = 9; - public static final int MSG_PASSWORD_REQUEST = 10; + public static final int MSG_ROOM_JOIN = 2; + public static final int MSG_ROOM_LEAVE = 3; + public static final int MSG_CHAT = 4; + public static final int MSG_MESSAGE = 5; + public static final int MSG_ROOM_ADD = 6; + public static final int MSG_ROOM_UPDATE = 7; + public static final int MSG_ROOM_DELETE = 8; + public static final int MSG_ROOMLIST = 9; + public static final int MSG_CONNECTED = 10; + public static final int MSG_DISCONNECTED = 11; + public static final int MSG_PASSWORD_REQUEST = 12; + public static final int MSG_ENTER_ROOM_FROM_LOBBY = 13; + public static final int MSG_LEAVE_ROOM = 14; public FromNetHandler() { super(Looper.getMainLooper()); @@ -221,6 +247,18 @@ lobbyChatlog.appendPlayerLeave(args.first, args.second); break; } + case MSG_ROOM_JOIN: { + String name = (String)msg.obj; + // TODO roomPlayerList.addPlayerWithNewId(name); + roomChatlog.appendPlayerJoin(name); + break; + } + case MSG_ROOM_LEAVE: { + Pair args = (Pair)msg.obj; + // TODO roomPlayerList.removePlayer(args.first); + roomChatlog.appendPlayerLeave(args.first, args.second); + break; + } case MSG_CHAT: { Pair args = (Pair)msg.obj; getCurrentLog().appendChat(args.first, args.second); @@ -248,13 +286,13 @@ break; } case MSG_CONNECTED: { - state = State.LOBBY; + changeState(State.LOBBY); broadcastManager.sendBroadcast(new Intent(ACTION_CONNECTED)); break; } case MSG_DISCONNECTED: { Pair args = (Pair)msg.obj; - state = State.NOT_CONNECTED; + changeState(State.NOT_CONNECTED); connection = null; Intent intent = new Intent(ACTION_DISCONNECTED); intent.putExtra(EXTRA_HAS_ERROR, args.first); @@ -268,6 +306,22 @@ broadcastManager.sendBroadcast(intent); break; } + case MSG_ENTER_ROOM_FROM_LOBBY: { + roomChatlog.clear(); + changeState(State.ROOM); + chief = (Boolean)msg.obj; + Intent intent = new Intent(ACTION_ENTERED_ROOM_FROM_LOBBY); + broadcastManager.sendBroadcastSync(intent); + break; + } + case MSG_LEAVE_ROOM: { + changeState(State.LOBBY); + Intent intent = new Intent(ACTION_LEFT_ROOM); + intent.putExtra(EXTRA_MESSAGE, (String)msg.obj); + intent.putExtra(EXTRA_REASON, msg.arg1); + broadcastManager.sendBroadcastSync(intent); + break; + } default: { Log.e("FromNetHandler", "Unknown message type: "+msg.what); break; @@ -332,6 +386,8 @@ } FLIB.flib_netconn_onLobbyJoin(conn, lobbyJoinCb, null); FLIB.flib_netconn_onLobbyLeave(conn, lobbyLeaveCb, null); + FLIB.flib_netconn_onRoomJoin(conn, roomJoinCb, null); + FLIB.flib_netconn_onRoomLeave(conn, roomLeaveCb, null); FLIB.flib_netconn_onChat(conn, chatCb, null); FLIB.flib_netconn_onMessage(conn, messageCb, null); FLIB.flib_netconn_onRoomAdd(conn, roomAddCb, null); @@ -341,6 +397,9 @@ FLIB.flib_netconn_onRoomlist(conn, roomlistCb, null); FLIB.flib_netconn_onDisconnected(conn, disconnectCb, null); FLIB.flib_netconn_onPasswordRequest(conn, passwordRequestCb, null); + FLIB.flib_netconn_onEnterRoom(conn, enterRoomCb, null); + FLIB.flib_netconn_onLeaveRoom(conn, leaveRoomCb, null); + FLIB.flib_metascheme_release(meta); tickHandler.start(); } @@ -375,6 +434,16 @@ } }; + private final StrCallback roomJoinCb = new StrCallback() { + public void callback(Pointer context, String name) { + sendFromNet(FromNetHandler.MSG_ROOM_JOIN, name); + } + }; + private final StrStrCallback roomLeaveCb = new StrStrCallback() { + public void callback(Pointer context, String name, String message) { + sendFromNet(FromNetHandler.MSG_ROOM_LEAVE, Pair.create(name, message)); + } + }; private final StrStrCallback chatCb = new StrStrCallback() { public void callback(Pointer context, String name, String msg) { sendFromNet(FromNetHandler.MSG_CHAT, Pair.create(name, msg)); @@ -425,6 +494,18 @@ } }; + private final BoolCallback enterRoomCb = new BoolCallback() { + public void callback(Pointer context, boolean isChief) { + sendFromNet(FromNetHandler.MSG_ENTER_ROOM_FROM_LOBBY, Boolean.TRUE); + } + }; + + private final IntStrCallback leaveRoomCb = new IntStrCallback() { + public void callback(Pointer context, int reason, String message) { + sendFromNet(FromNetHandler.MSG_LEAVE_ROOM, reason, message); + } + }; + private void shutdown(boolean error, String message) { if(conn != null) { FLIB.flib_netconn_destroy(conn); @@ -448,7 +529,7 @@ case JnaFrontlib.NETCONN_DISCONNECT_AUTH_FAILED: return res.getString(R.string.error_auth_failed); case JnaFrontlib.NETCONN_DISCONNECT_CONNLOST: - return res.getString(R.string.error_connection_lost, message); + return res.getString(R.string.error_connection_lost); case JnaFrontlib.NETCONN_DISCONNECT_INTERNAL_ERROR: return res.getString(R.string.error_unexpected, message); case JnaFrontlib.NETCONN_DISCONNECT_SERVER_TOO_OLD: @@ -476,7 +557,12 @@ public static final int MSG_SEND_ROOMLIST_REQUEST = 3; public static final int MSG_SEND_PLAYER_INFO_REQUEST = 4; public static final int MSG_SEND_CHAT = 5; - public static final int MSG_DISCONNECT = 6; + public static final int MSG_SEND_FOLLOW_PLAYER = 6; + public static final int MSG_SEND_JOIN_ROOM = 7; + public static final int MSG_SEND_CREATE_ROOM = 8; + public static final int MSG_SEND_LEAVE_ROOM = 9; + + public static final int MSG_DISCONNECT = 10; public ToNetHandler(Looper looper) { super(looper); @@ -511,6 +597,24 @@ } break; } + case MSG_SEND_FOLLOW_PLAYER: { + FLIB.flib_netconn_send_playerFollow(conn, (String)msg.obj); + break; + } + case MSG_SEND_JOIN_ROOM: { + FLIB.flib_netconn_send_joinRoom(conn, (String)msg.obj); + break; + } + case MSG_SEND_CREATE_ROOM: { + FLIB.flib_netconn_send_createRoom(conn, (String)msg.obj); + break; + } + case MSG_SEND_LEAVE_ROOM: { + if(FLIB.flib_netconn_send_leaveRoom(conn, (String)msg.obj) == 0) { + sendFromNet(FromNetHandler.MSG_LEAVE_ROOM, -1, ""); + } + break; + } case MSG_DISCONNECT: { FLIB.flib_netconn_send_quit(conn, (String)msg.obj); shutdown(false, "User quit"); diff -r fec6fa1e460e -r 38acbfdb484f project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/NetplayStateFragment.java --- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/NetplayStateFragment.java Thu Aug 02 16:35:12 2012 +0200 +++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/NetplayStateFragment.java Thu Aug 02 16:36:11 2012 +0200 @@ -1,7 +1,9 @@ package org.hedgewars.hedgeroid.netplay; +import org.hedgewars.hedgeroid.R; import org.hedgewars.hedgeroid.netplay.Netplay.State; +import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -13,30 +15,45 @@ /** * Fragment for use by an activity that depends on the state of the network - * connection. + * connection. The activity must implement the NetplayStateListener interface. * * This fragment manages a few aspects of the netplay connection: Requesting * the network system loop to run at high frequency while the activity is in - * the foreground, and reacting to changes in the networking state by switching - * to the appropriate activity or finishing the activity if the network connection - * is closed. + * the foreground, and reacting to changes in the networking state by calling + * a callback method on the activity. */ public class NetplayStateFragment extends Fragment { private Netplay netplay; private Context appContext; private LocalBroadcastManager broadcastManager; + private NetplayStateListener listener; + private State knownState; - private final BroadcastReceiver disconnectReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if(intent.getBooleanExtra(Netplay.EXTRA_HAS_ERROR, true)) { - String message = intent.getStringExtra(Netplay.EXTRA_MESSAGE); - Toast.makeText(appContext, "Disconnected: "+message, Toast.LENGTH_LONG).show(); - } - getActivity().finish(); + interface NetplayStateListener { + /** + * This is called while the activity is running, and every time during resume, if + * a change in the networking state is detected. It is also called once + * with the initial state (which could be called a change from the "unknown" state). + */ + void onNetplayStateChanged(State newState); + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + try { + listener = (NetplayStateListener) activity; + } catch(ClassCastException e) { + throw new ClassCastException("Activity " + activity + " must implement NetplayStateListener to use NetplayStateFragment."); } - }; - + } + + @Override + public void onDetach() { + super.onDetach(); + listener = null; + } + @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); @@ -49,10 +66,14 @@ public void onResume() { super.onResume(); broadcastManager.registerReceiver(disconnectReceiver, new IntentFilter(Netplay.ACTION_DISCONNECTED)); + broadcastManager.registerReceiver(leaveRoomReceiver, new IntentFilter(Netplay.ACTION_LEFT_ROOM)); + broadcastManager.registerReceiver(stateChangeReceiver, new IntentFilter(Netplay.ACTION_STATE_CHANGED)); netplay.requestFastTicks(); - if(netplay.getState() == State.NOT_CONNECTED) { - getActivity().finish(); + State newState = netplay.getState(); + if(knownState != newState) { + listener.onNetplayStateChanged(newState); + knownState = newState; } } @@ -60,6 +81,40 @@ public void onPause() { super.onPause(); broadcastManager.unregisterReceiver(disconnectReceiver); + broadcastManager.unregisterReceiver(leaveRoomReceiver); + broadcastManager.unregisterReceiver(stateChangeReceiver); netplay.unrequestFastTicks(); } + + private final BroadcastReceiver disconnectReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if(intent.getBooleanExtra(Netplay.EXTRA_HAS_ERROR, true)) { + String message = intent.getStringExtra(Netplay.EXTRA_MESSAGE); + String toastText = getString(R.string.toast_disconnected, message); + Toast.makeText(appContext, toastText, Toast.LENGTH_LONG).show(); + } + } + }; + + private final BroadcastReceiver leaveRoomReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int reason = intent.getIntExtra(Netplay.EXTRA_REASON, -1); + if(reason == JnaFrontlib.NETCONN_ROOMLEAVE_ABANDONED) { + Toast.makeText(appContext, R.string.toast_room_abandoned, Toast.LENGTH_LONG).show(); + } else if(reason == JnaFrontlib.NETCONN_ROOMLEAVE_KICKED) { + Toast.makeText(appContext, R.string.toast_kicked, Toast.LENGTH_LONG).show(); + } + } + }; + + private final BroadcastReceiver stateChangeReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + State newState = netplay.getState(); + listener.onNetplayStateChanged(newState); + knownState = newState; + } + }; } diff -r fec6fa1e460e -r 38acbfdb484f project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/Player.java --- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/Player.java Thu Aug 02 16:35:12 2012 +0200 +++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/Player.java Thu Aug 02 16:36:11 2012 +0200 @@ -6,4 +6,4 @@ public Player(String name) { this.name = name; } -} \ No newline at end of file +} diff -r fec6fa1e460e -r 38acbfdb484f project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/PlayerList.java --- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/PlayerList.java Thu Aug 02 16:35:12 2012 +0200 +++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/PlayerList.java Thu Aug 02 16:36:11 2012 +0200 @@ -7,7 +7,7 @@ import android.database.DataSetObservable; import android.util.Pair; -public class PlayerList extends DataSetObservable { +public class Playerlist extends DataSetObservable { private long nextId = 1; private Map> players = new TreeMap>(); diff -r fec6fa1e460e -r 38acbfdb484f project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/PlayerListAdapter.java --- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/PlayerListAdapter.java Thu Aug 02 16:35:12 2012 +0200 +++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/PlayerListAdapter.java Thu Aug 02 16:36:11 2012 +0200 @@ -16,15 +16,15 @@ import android.widget.BaseAdapter; import android.widget.TextView; -public class PlayerListAdapter extends BaseAdapter { +public class PlayerlistAdapter extends BaseAdapter { private List> players = new ArrayList>(); private Context context; - private PlayerList playerList; + private Playerlist playerlist; private DataSetObserver observer = new DataSetObserver() { @Override public void onChanged() { - reloadFromList(playerList); + reloadFromList(playerlist); } @Override @@ -33,7 +33,7 @@ } }; - public PlayerListAdapter(Context context) { + public PlayerlistAdapter(Context context) { this.context = context; } @@ -53,24 +53,24 @@ return true; } - public void setList(PlayerList playerList) { - if(this.playerList != null) { - this.playerList.unregisterObserver(observer); + public void setList(Playerlist playerlist) { + if(this.playerlist != null) { + this.playerlist.unregisterObserver(observer); } - this.playerList = playerList; - this.playerList.registerObserver(observer); - reloadFromList(playerList); + this.playerlist = playerlist; + this.playerlist.registerObserver(observer); + reloadFromList(playerlist); } public void invalidate() { - if(playerList != null) { - playerList.unregisterObserver(observer); + if(playerlist != null) { + playerlist.unregisterObserver(observer); } - playerList = null; + playerlist = null; notifyDataSetInvalidated(); } - private void reloadFromList(PlayerList list) { + private void reloadFromList(Playerlist list) { players = new ArrayList>(list.getMap().values()); Collections.sort(players, AlphabeticalOrderComparator.INSTANCE); notifyDataSetChanged(); diff -r fec6fa1e460e -r 38acbfdb484f project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/PlayerlistFragment.java --- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/PlayerlistFragment.java Thu Aug 02 16:35:12 2012 +0200 +++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/PlayerlistFragment.java Thu Aug 02 16:36:11 2012 +0200 @@ -12,17 +12,16 @@ import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView.AdapterContextMenuInfo; -import android.widget.Toast; public class PlayerlistFragment extends ListFragment { private Netplay netconn; - private PlayerListAdapter playerListAdapter; + private PlayerlistAdapter playerListAdapter; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); netconn = Netplay.getAppInstance(getActivity().getApplicationContext()); - playerListAdapter = new PlayerListAdapter(getActivity()); + playerListAdapter = new PlayerlistAdapter(getActivity()); playerListAdapter.setList(Netplay.getAppInstance(getActivity().getApplicationContext()).playerList); setListAdapter(playerListAdapter); } @@ -53,13 +52,13 @@ @Override public boolean onContextItemSelected(MenuItem item) { AdapterContextMenuInfo info = (AdapterContextMenuInfo)item.getMenuInfo(); + Player player = playerListAdapter.getItem(info.position); switch(item.getItemId()) { case R.id.player_info: - Player p = playerListAdapter.getItem(info.position); - netconn.sendPlayerInfoQuery(p.name); + netconn.sendPlayerInfoQuery(player.name); return true; case R.id.player_follow: - Toast.makeText(getActivity(), R.string.not_implemented_yet, Toast.LENGTH_SHORT).show(); + netconn.sendFollowPlayer(player.name); return true; default: return super.onContextItemSelected(item); diff -r fec6fa1e460e -r 38acbfdb484f project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/RoomActivity.java --- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/RoomActivity.java Thu Aug 02 16:35:12 2012 +0200 +++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/RoomActivity.java Thu Aug 02 16:36:11 2012 +0200 @@ -2,29 +2,38 @@ import org.hedgewars.hedgeroid.R; import org.hedgewars.hedgeroid.netplay.JnaFrontlib.NetconnPtr; +import org.hedgewars.hedgeroid.netplay.Netplay.State; +import org.hedgewars.hedgeroid.netplay.NetplayStateFragment.NetplayStateListener; +import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; +import android.support.v4.app.FragmentTransaction; import android.support.v4.content.LocalBroadcastManager; import android.widget.LinearLayout; import android.widget.TabHost; +import android.widget.Toast; -public class RoomActivity extends FragmentActivity { +public class RoomActivity extends FragmentActivity implements NetplayStateListener { private TabHost tabHost; - private Netplay netconn; + private Netplay netplay; @Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); - netconn = Netplay.getAppInstance(getApplicationContext()); + netplay = Netplay.getAppInstance(getApplicationContext()); + + setContentView(R.layout.activity_netroom); + ChatFragment chatFragment = (ChatFragment)getSupportFragmentManager().findFragmentById(R.id.chatFragment); + chatFragment.setInRoom(true); - setContentView(R.layout.activity_lobby); - Fragment chatFragment = getSupportFragmentManager().findFragmentById(R.id.chatFragment); - chatFragment.getArguments().putBoolean(ChatFragment.ARGUMENT_INROOM, true); + FragmentTransaction trans = getSupportFragmentManager().beginTransaction(); + trans.add(new NetplayStateFragment(), "netplayFragment"); + trans.commit(); - tabHost = (TabHost)findViewById(android.R.id.tabhost); + /*tabHost = (TabHost)findViewById(android.R.id.tabhost); if(tabHost != null) { tabHost.setup(); tabHost.getTabWidget().setOrientation(LinearLayout.VERTICAL); @@ -35,9 +44,14 @@ if (icicle != null) { tabHost.setCurrentTabByTag(icicle.getString("currentTab")); } - } + }*/ } + @Override + public void onBackPressed() { + netplay.sendLeaveRoom(null); + } + @Override protected void onSaveInstanceState(Bundle icicle) { super.onSaveInstanceState(icicle); @@ -45,4 +59,23 @@ icicle.putString("currentTab", tabHost.getCurrentTabTag()); } } + + public void onNetplayStateChanged(State newState) { + switch(newState) { + case NOT_CONNECTED: + case CONNECTING: + case LOBBY: + finish(); + break; + case ROOM: + // Do nothing + break; + case INGAME: + //startActivity(new Intent(getApplicationContext(), RoomActivity.class)); + Toast.makeText(getApplicationContext(), R.string.not_implemented_yet, Toast.LENGTH_SHORT).show(); + break; + default: + throw new IllegalStateException("Unknown connection state: "+newState); + } + } } diff -r fec6fa1e460e -r 38acbfdb484f project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/RoomList.java --- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/RoomList.java Thu Aug 02 16:35:12 2012 +0200 +++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/RoomList.java Thu Aug 02 16:36:11 2012 +0200 @@ -8,7 +8,7 @@ import android.util.Log; import android.util.Pair; -public class RoomList extends DataSetObservable { +public class Roomlist extends DataSetObservable { private long nextId = 1; private Map> rooms = new TreeMap>(); diff -r fec6fa1e460e -r 38acbfdb484f project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/RoomListAdapter.java --- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/RoomListAdapter.java Thu Aug 02 16:35:12 2012 +0200 +++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/RoomListAdapter.java Thu Aug 02 16:36:11 2012 +0200 @@ -17,15 +17,15 @@ import android.widget.BaseAdapter; import android.widget.TextView; -public class RoomListAdapter extends BaseAdapter { +public class RoomlistAdapter extends BaseAdapter { private List> rooms = new ArrayList>(); private Context context; - private RoomList roomList; + private Roomlist roomlist; private DataSetObserver observer = new DataSetObserver() { @Override public void onChanged() { - reloadFromList(roomList); + reloadFromList(roomlist); } @Override @@ -34,7 +34,7 @@ } }; - public RoomListAdapter(Context context) { + public RoomlistAdapter(Context context) { this.context = context; } @@ -54,25 +54,25 @@ return true; } - public void setList(RoomList roomList) { - if(this.roomList != null) { - this.roomList.unregisterObserver(observer); + public void setList(Roomlist roomlist) { + if(this.roomlist != null) { + this.roomlist.unregisterObserver(observer); } - this.roomList = roomList; - this.roomList.registerObserver(observer); - reloadFromList(roomList); + this.roomlist = roomlist; + this.roomlist.registerObserver(observer); + reloadFromList(roomlist); } public void invalidate() { - if(roomList != null) { - roomList.unregisterObserver(observer); + if(roomlist != null) { + roomlist.unregisterObserver(observer); } - roomList = null; + roomlist = null; notifyDataSetInvalidated(); } - private void reloadFromList(RoomList list) { - rooms = new ArrayList>(roomList.getMap().values()); + private void reloadFromList(Roomlist list) { + rooms = new ArrayList>(roomlist.getMap().values()); Collections.sort(rooms, RoomAgeComparator.INSTANCE); notifyDataSetChanged(); } diff -r fec6fa1e460e -r 38acbfdb484f project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/RoomlistFragment.java --- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/RoomlistFragment.java Thu Aug 02 16:35:12 2012 +0200 +++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/RoomlistFragment.java Thu Aug 02 16:36:11 2012 +0200 @@ -10,17 +10,16 @@ import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; -import android.widget.Toast; public class RoomlistFragment extends ListFragment implements OnItemClickListener { private static final int AUTO_REFRESH_INTERVAL_MS = 15000; - private Netplay netconn; - private RoomListAdapter adapter; + private Netplay netplay; + private RoomlistAdapter adapter; private CountDownTimer autoRefreshTimer = new CountDownTimer(Long.MAX_VALUE, AUTO_REFRESH_INTERVAL_MS) { @Override public void onTick(long millisUntilFinished) { - netconn.sendRoomlistRequest(); + netplay.sendRoomlistRequest(); } @Override @@ -30,9 +29,9 @@ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - netconn = Netplay.getAppInstance(getActivity().getApplicationContext()); - adapter = new RoomListAdapter(getActivity()); - adapter.setList(netconn.roomList); + netplay = Netplay.getAppInstance(getActivity().getApplicationContext()); + adapter = new RoomlistAdapter(getActivity()); + adapter.setList(netplay.roomList); setListAdapter(adapter); } @@ -67,6 +66,6 @@ } public void onItemClick(AdapterView parent, View view, int position, long id) { - Toast.makeText(getActivity(), R.string.not_implemented_yet, Toast.LENGTH_SHORT).show(); + netplay.sendJoinRoom(adapter.getItem(position).name); } } diff -r fec6fa1e460e -r 38acbfdb484f project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/TextInputDialog.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/TextInputDialog.java Thu Aug 02 16:36:11 2012 +0200 @@ -0,0 +1,128 @@ +package org.hedgewars.hedgeroid.netplay; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.DialogInterface; +import android.os.Bundle; +import android.support.v4.app.DialogFragment; +import android.view.KeyEvent; +import android.view.inputmethod.EditorInfo; +import android.widget.EditText; +import android.widget.TextView; +import android.widget.TextView.OnEditorActionListener; + +/** + * A generic text input dialog with configurable text. The Activity must implement the callback + * interface TextInputDialogListener, which will be called by the dialog if it is submitted or cancelled. + */ +public class TextInputDialog extends DialogFragment { + private static final String BUNDLE_DIALOG_ID = "dialogId"; + private static final String BUNDLE_TITLE_TEXT = "title"; + private static final String BUNDLE_MESSAGE_TEXT = "message"; + private static final String BUNDLE_HINT_TEXT = "hint"; + + private int dialogId, titleText, messageText, hintText; + private TextInputDialogListener listener; + + public interface TextInputDialogListener { + void onTextInputDialogSubmitted(int dialogId, String text); + void onTextInputDialogCancelled(int dialogId); + } + + /** + * The dialogId is only used for passing back to the callback on the activity, the + * other parameters are text resource IDs. Pass 0 for any of them to not use this + * text. + */ + public TextInputDialog(int dialogId, int titleText, int messageText, int hintText) { + this.dialogId = dialogId; + this.titleText = titleText; + this.messageText = messageText; + this.hintText = hintText; + } + + public TextInputDialog() { + // Only for reflection-based instantiation by the framework + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + try { + listener = (TextInputDialogListener) activity; + } catch(ClassCastException e) { + throw new ClassCastException("Activity " + activity + " must implement TextInputDialogListener to use TextInputDialog."); + } + } + + @Override + public void onDetach() { + super.onDetach(); + listener = null; + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + if(savedInstanceState != null) { + dialogId = savedInstanceState.getInt(BUNDLE_DIALOG_ID, dialogId); + titleText = savedInstanceState.getInt(BUNDLE_TITLE_TEXT, titleText); + messageText = savedInstanceState.getInt(BUNDLE_MESSAGE_TEXT, messageText); + hintText = savedInstanceState.getInt(BUNDLE_HINT_TEXT, hintText); + } + + final EditText editText = new EditText(getActivity()); + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + + if(titleText != 0) { + builder.setTitle(titleText); + } + if(messageText != 0) { + builder.setTitle(messageText); + } + if(hintText != 0) { + editText.setHint(hintText); + } + + editText.setId(android.R.id.text1); + editText.setImeOptions(EditorInfo.IME_ACTION_DONE); + editText.setSingleLine(); + + builder.setView(editText); + builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + dialog.cancel(); + } + }); + + editText.setOnEditorActionListener(new OnEditorActionListener() { + public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { + listener.onTextInputDialogSubmitted(dialogId, v.getText().toString()); + return true; + } + }); + + builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + listener.onTextInputDialogSubmitted(dialogId, editText.getText().toString()); + } + }); + + return builder.create(); + } + + @Override + public void onSaveInstanceState(Bundle icicle) { + super.onSaveInstanceState(icicle); + icicle.putInt(BUNDLE_DIALOG_ID, dialogId); + icicle.putInt(BUNDLE_TITLE_TEXT, titleText); + icicle.putInt(BUNDLE_MESSAGE_TEXT, messageText); + icicle.putInt(BUNDLE_HINT_TEXT, hintText); + } + + @Override + public void onCancel(DialogInterface dialog) { + super.onCancel(dialog); + listener.onTextInputDialogCancelled(dialogId); + } +}