/* * CCNx Android Chat * * Copyright (C) 2010 Palo Alto Research Center, Inc. * * This work is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License version 2 as published by the * Free Software Foundation. * This work is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ package org.ccnx.android.apps.chat; /** * This module is purely UI for chat. It has an EditText to enter your * message and a TextView to display received messages. The TextView * uses a ScrollView so we can keep scrolling the screen to the bottom * so the most recent message is always at the bottom. * * This UI is very basic and has these limitations: * - No screen orientation change support * - No pause/sleep support * - Does not check the system setting to see if we should not use the network * * CCN pieces are in the ChatWorker. * * We disable the EditText until we get a ready() call from * ChatWorker, indicating that the network is ready for our input. * */ import org.ccnx.ccn.config.UserConfiguration; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.util.Log; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.View.OnKeyListener; import android.widget.EditText; import android.widget.ScrollView; import android.widget.TextView; public class ChatScreen extends Activity implements OnKeyListener, ChatCallback { protected final static String TAG="ChatScreen"; // =========================================================================== // Process control Methods /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.ccnchat_chat); EditText etPost = (EditText) findViewById(R.id.etPost); etPost.setEnabled(false); etPost.setOnKeyListener(this); tv = (TextView) findViewById(R.id.tvOutput); //tv.setMovementMethod(new ScrollingMovementMethod()); tv.setText(""); sv = (ScrollView) findViewById(R.id.svOutput); ScreenOutput("Starting the CCN listen thread\n"); Intent i = this.getIntent(); String namespace = i.getStringExtra(CcnxChatMain.PREF_NAMESPACE); String username = i.getStringExtra(CcnxChatMain.PREF_HANDLE); String remotehost = i.getStringExtra(CcnxChatMain.PREF_REMOTEHOST); String remoteport = i.getStringExtra(CcnxChatMain.PREF_REMOTEPORT); _worker = new ChatWorker(this, this); _worker.start(username, namespace, remotehost, remoteport); // Do these CCNx operations after we created ChatWorker ScreenOutput("User name = " + UserConfiguration.userName() + "\n"); ScreenOutput("ccnDir = " + UserConfiguration.userConfigurationDirectory() + "\n"); ScreenOutput("Waiting for CCN Services to become ready\n"); } @Override public void onStart() { super.onStart(); } @Override public void onResume() { super.onResume(); } @Override public void onPause() { super.onPause(); } @Override public void onDestroy() { Log.i(TAG, "onDestroy()"); _worker.stop(); super.onDestroy(); } // =========================================================================== // UI Methods private final static int EXIT_MENU = 1; private final static int SHUTDOWN_MENU = 2; @Override public boolean onCreateOptionsMenu(Menu menu) { boolean result = super.onCreateOptionsMenu(menu); menu.add(0, EXIT_MENU, 1, "Exit"); menu.add(0, SHUTDOWN_MENU, 1, "Exit & Shutdown"); return result; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case EXIT_MENU: finish(); return true; case SHUTDOWN_MENU: _worker.shutdown(); finish(); return true; } return super.onOptionsItemSelected(item); } @Override public boolean onKey(View v, int keyCode, KeyEvent event) { // send text when enter pressed Log.d(TAG, "KeyEvent = " + keyCode); Log.d(TAG, "Event = " + event.toString()); if( keyCode == KeyEvent.KEYCODE_ENTER && event.getAction() == KeyEvent.ACTION_UP ) { EditText etPost = null; etPost = (EditText) findViewById(R.id.etPost); UiToCcn(etPost.getText().toString()); etPost.setText(""); return true; } return false; } // ==================================================================== // Internal implementation protected ChatWorker _worker; protected TextView tv = null; protected ScrollView sv = null; /** * In the UI thread, post a message to the screen */ protected void ScreenOutput(String s) { tv.append(s); tv.invalidate(); // Now scroll to the bottom sv.post(new Runnable() { public void run() { sv.fullScroll(ScrollView.FOCUS_DOWN); } }); } /** * this will be called when we receive a chat line. * It is executed in the UI thread. */ private Handler _handler = new Handler() { @Override public void handleMessage(Message msg) { String text = (String) msg.obj; ScreenOutput(text); msg.obj = null; msg = null; } }; /** * Send a message to the network */ protected void UiToCcn(String s) { _worker.send(s); } /** * From ChatCallback, when we get a message from CCN */ public void recv(String message) { Message msg = Message.obtain(); msg.obj = message; _handler.sendMessage(msg); } /** * Called by ChatWorker based on CCNx service state */ @Override public void ccnxServices(boolean ok) { if ( ok ) { recv("CCN Services now ready -- let's chat!\n"); // activate the edit text by sending a Runnable to // the UI handler. _handler.post( new Runnable() { @Override public void run() { EditText etPost = (EditText) findViewById(R.id.etPost); etPost.setEnabled(true); } } ); } else { recv("CCN Service error, cannot chat!\n"); } } }