Android edittext loses and repeats texts received via TCP socket - android

I have a problem with a edittext in Android Studio.
Normally, log.d reports the messages received via TCP socket and
those appears in the textedit mySocketrx. When there is a fast
message burst log.d is still working fine but textedit loses and repeats
messages.
protected void onCreate(Bundle savedInstanceState) {
final EditText mySocketrx = (EditText) findViewById(R.id.Socketrx);
new Thread(new Runnable() { // Client TCP socket thread
public void run() {
try {
s = new Socket("192.168.1.161",6000);
p = new PrintStream(s.getOutputStream());
b = new BufferedReader ( new InputStreamReader( s.getInputStream() ) );
} catch(Exception ex) { }
while (true) {
try {
status = b.readLine();
Log.d("DEBUG", status);
runOnUiThread(new Runnable() {
public void run() {
mySocketrx.append(status + "\n");
}
} );
} catch(Exception ex) { }
}
}
}).start();
}

Instead of append() use the setText() method.

Related

Timing threads on Android

I try to build an app, that vibrates with a certain pattern depending on the value of a variable that comes constantly with a stream from a video game.
I managed to display telemetry data on the TextView continiously. What I want is the phone to vibrate for a certain lenght in ms or pattern, depending on the value of gforce in Thread2. What I would like to achieve is, the following sequence. Read the stream, display ias, gforce and vertical on the TextView, check gforce value, if value>=2, vibrate(choose length or pattern by gforce value), pause 500ms, repeat.
I know about the lack of connection security in my code, but that is something for later.
I do have the problem of thread management here, that I cant solve. The stream comes from a Java server socket and has an output of around one line per ms.
This the code I try to make that work with.
public class MainActivity extends AppCompatActivity {
Thread Thread1 = null;
EditText etIP, etPort;
TextView tvMessages;
String SERVER_IP;
int SERVER_PORT;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
etIP = findViewById(R.id.etIP);
etPort = findViewById(R.id.etPort);
etIP.setText("192.168.178.61");
etPort.setText("31091");
tvMessages = findViewById(R.id.tvMessages);
Button btnConnect = findViewById(R.id.btnConnect);
btnConnect.setOnClickListener(new View.OnClickListener() {
#RequiresApi(api = Build.VERSION_CODES.O)
#Override
public void onClick(View v) {
tvMessages.setText("");
SERVER_IP = etIP.getText().toString().trim();
SERVER_PORT = Integer.parseInt(etPort.getText().toString().trim());
Thread1 = new Thread(new Thread1());
Thread1.start();
}
});
}
PrintStream output;
BufferedReader input;
Socket socket;
String message;
class Thread1 implements Runnable {
#Override
public void run() {
try {
socket = new Socket(SERVER_IP, SERVER_PORT);
socket.setTcpNoDelay(true);
output = new PrintStream(socket.getOutputStream(), true);
input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
runOnUiThread(new Runnable() {
#Override
public void run() {
tvMessages.setText("Connected\n");
}
});
new Thread(new Thread2()).start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
class Thread2 implements Runnable {
private double ias;
private double gforce;
private double vertical;
#Override
public void run() {
while (!(socket.isClosed())) {
try {
message = input.readLine();
if (message != null && message.contains("IAS")) {
ias = Double.parseDouble(message.substring(5, (message.indexOf(" ", 5))));
gforce = Double.parseDouble(message.substring(message.indexOf("Gy:") + 4, message.indexOf("Gz:") - 1));
vertical = Double.parseDouble(message.substring(message.indexOf("vertical:") + 10, message.indexOf("Gx:") - 1));
}
if (message != null && !(message.equals("exit"))) {
runOnUiThread(new Runnable() {
#Override
public void run() {
System.out.println(message);
tvMessages.setText("IAS: " + ias + "\n" +
"G: " + gforce + "\n" +
"Vertical: " + vertical + "\n");
}
});
//do trigger Vibration handler and make the phone vibrate in a pattern relative to gforce
new VibrationHandler((int)gforce).start();
//at this point sleep for n ms
} else {
Thread1 = new Thread(new Thread1());
Thread1.start();
return;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
class VibrationHandler extends Thread{
int pattern;
public VibrationHandler(int pattern){
this.pattern=pattern;
}
public void run(){
Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
// Vibrate for 500 milliseconds
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
v.vibrate(VibrationEffect.createOneShot(pattern*50, VibrationEffect.DEFAULT_AMPLITUDE));
} else {
//deprecated in API 26
v.vibrate(pattern*50);
}
}
}
}
Thank you a lot for your help.

How can I connect two Android device by socket without server

I am trying to develop an android application that can exchange data on peer to peer connection with other devices without server. So please suggest how can I do this. Thank you in advance.
This is a complete code for chat by SocketProgramming without server.
In my Application, first you are a client and you search for a server. When you do not find any server, you become a server and wait for a client.
public class MainActivity extends ActionBarActivity {
private Handler handler = new Handler();
private TextView text;
private EditText input;
private Button send;
private Socket socket;
private DataOutputStream outputStream;
private BufferedReader inputStream;
private String DeviceName = "Device";
private boolean searchNetwork() {
log("Connecting");
String range = "192.168.56.";
for (int i = 1; i <= 255; i++) {
String ip = range + i;
try {
socket = new Socket();
socket.connect(new InetSocketAddress(ip, 9000), 50);
outputStream = new DataOutputStream(socket.getOutputStream());
inputStream = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
DeviceName += "1";
Log.i("Server", DeviceName);
log("Connected");
return true;
} catch (Exception e) {
}
}
return false;
}
private void runNewChatServer() {
ServerSocket serverSocket;
try {
serverSocket = new ServerSocket(9000);
log("Waiting for client...");
socket = serverSocket.accept();
DeviceName += "2";
log("a new client Connected");
} catch (IOException e) {
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text = (TextView) findViewById(R.id.text);
input = (EditText) findViewById(R.id.input);
send = (Button) findViewById(R.id.send);
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
try {
if (!searchNetwork()) {
runNewChatServer();
}
outputStream = new DataOutputStream(
socket.getOutputStream());
inputStream = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
while (true) {
String Message = inputStream.readLine();
if (Message != null) {
log(Message);
}
}
} catch (IOException e) {
log("Error: IO Exception");
e.printStackTrace();
}
}
});
send.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
if (outputStream == null) {
return;
}
try {
String Message = input.getText().toString() + "\n";
outputStream.write(Message.getBytes());
log2(input.getText().toString());
} catch (IOException e) {
e.printStackTrace();
}
input.setText("");
}
});
thread.start();
}
private void log(final String message) {
handler.post(new Runnable() {
String DeviceName2="";
#Override
public void run() {
if (DeviceName.equals("Device1")) {
DeviceName2 = "Device2";
}else if(DeviceName.equals("Device2")) {
DeviceName2 = "Device1";
}else{
DeviceName2 = "UnknowDevice";
}
text.setText(text.getText() + "\n" + DeviceName2 + " :"
+ message);
}
});
}
private void log2(final String message) {
handler.post(new Runnable() {
#Override
public void run() {
text.setText(text.getText() + "\n" + "you" + " :"
+ message);
}
});
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.exit(0);
return true;
}
return super.onKeyDown(keyCode, event);
}
}
Your design has a big problem : ...
If there is no central server some android devices should act as client and others as server but this will not work in some situations:
When the mobile telephony provider assigns private and non-public IP
When the device is connected to a Wi-Fi network but no NAT rule is defined on the router.
In both cases the problem is that the listening port of the device that must act as server is unreachable.
Java provides ServerSocket and Socket to communicate b/w devices. One of the device you can make as server and other device you can make as client and communicate b/w 'em without introducing server hosted on some machine.
The Other and better option is Using Wi-Fi Peer-to-Peer. WifiP2pManager help you to achieve your purpose.Here is an example.
If you're looking for such P2P over a local network, there are two parts to it:
Discovering peers
Communicating with peers
Among Android APIs, you can either use Network Service Discovery APIs for this or Wifi P2P Service Discovery APIs.
There's a wrapper library which which uses these internally and has comparatively better documentation - Salut, which can also be used.
I also created a library for P2P - Near, which uses sockets directly. The problem I was facing with Android APIs was that discovery wasn't happening with certainty every time and the underlying issue was unknown.
If you're looking for P2P across the internet, socket IO is a prevalent solution. Even Near should be able to facilitate the transfers if you provide the IP addresses and they're not behind NAT firewalls.

How to break while loop android server?

This is part of server's code. I got problem, that i can't break this endless loop. It's separate class, which handle client connections. How it's possible to make unlimited quantity of clients connected, but finish connection on button click if it's possible?
public class Handler implements Runnable {
public void run(){
....
//sockets
try{
....
//socket
while (true) {
client = server.accept();
count++;
Log.d("My Log", "Connected");
Log.d("My Log", "log" + count);
executor.execute(new Handler(client));
}
}
}
Instead of using
while(true)
use something like
while(myConditional)
{
client = server.accept();
count++;
Log.d("My Log", "Connected");
Log.d("My Log", "log" + count);
executor.execute(new Handler(client));
}
where myConditional is a boolean value that you can set in the UI thread, something like
button.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
myConditional = false;
}
});

Android ImageView not showing received images from socket connection

I am trying to show two consecutive images in an Android app, which are received through a socket (from a C program using sendfile). The sender code seems to work ok, and I am having issues with the Android code side.
Part of the code in the Android app is the following:
public class DisplayNewActivity extends Activity {
...
#Override
public void onCreate(Bundle savedInstanceState) {
....
mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
Drawable d2;
d2 = (Drawable)msg.obj;
imageSock.setImageDrawable(d2); // to set the arrived image in the imageshow object
}
};
...
cThread = new Thread(new ClientThread());
rThread = new Thread(new RcvThread());
cThread.start();
}
public class ClientThread implements Runnable {
public void run() {
// thread used for socket connection.
...
rThread.start(); // once the connection has been established
...
}
}
#SuppressLint("HandlerLeak")
public class RcvThread implements Runnable {
public void run() {
while (connected) {
try {
InputStream inputStream = socket.getInputStream();
Drawable d = Drawable.createFromStream(inputStream, null);
Message msg = new Message();
msg.obj = d;
mHandler.sendMessage(msg);
} catch (Exception e) {
Log.e("SocketConnectionv02Activity", "C: ErrorRCVD", e);
}
}
}
}
}
The problem I am facing is that after the first image received by the Android app is shown correctly, then the next one received (which is correctly received) is not shown and leaves the imageview object showing a white space.
Any suggestion/idea to solve this issue?.
Thanks in advance for any help you could provide.
EDIT:
public class DisplayNewActivity extends Activity {
...
#Override
public void onCreate(Bundle savedInstanceState) {
....
mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
Bitmap d2;
d2 = (Bitmap)msg.obj;
imageSock.setImageBitmap(d2); // to set the arrived image in the imageshow object
}
};
...
cThread = new Thread(new ClientThread());
rThread = new Thread(new RcvThread());
cThread.start();
}
public class ClientThread implements Runnable {
public void run() {
// thread used for socket connection.
...
rThread.start(); // once the connection has been established
...
}
}
#SuppressLint("HandlerLeak")
public class RcvThread implements Runnable {
public void run() {
while (connected) {
try {
DataInputStream in = new DataInputStream(socket.getInputStream());
Bitmap d = BitmapFactory.decodeStream(in);
Message msg = new Message();
msg.obj = d;
mHandler.sendMessage(msg);
} catch (Exception e) {
Log.e("SocketConnectionv02Activity", "C: ErrorRCVD", e);
}
}
}
}
}
It sounds like the issue you are having is in decoding the data into a proper image after receiving it.
I might recommend not using Drawable.createFromStream() and instead using BitmapFactory.decodeStream() or manually downloading the data into a byte[] first and using BitmapFactory.decodeByteArray(). Sometimes the latter is useful if the former can't sufficiently keep up with the decoder as the data is received.
The method you are currently using actually ends up calling BitmapFactory.descodeResourceStream(), which is used to read image data out of the local res/ package and not so much from a remote socket.

how to link process output to textview and automatically update in realtime?

I'm not the best programmer, actually, I'm pretty bad :(
I need help with something thats driving my crazy. basically I have a tcpdump process, I want to extract the output and put it into a textview which is updated every few milliseconds, I've tried everything and just cant get it to work.
I don't get any errors and it seems to work in the background, but only displays chunks of text only after I go to the homescreen and return back into the app. however, it doesnt constantly update the textview, and sometimes hangs and crashes.
I've created a simple handler which can update the textview with plain text without problems, but then i faced major problems getting it to read the process.
Begin button
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.capture);
this.LiveTraffic = (TextView) findViewById(R.id.LiveTraffic);
this.CaptureText = (TextView) findViewById(R.id.CaptureText);
((TextView) findViewById(R.id.ipv4)).setText(getLocalIpv4Address());
((TextView) findViewById(R.id.ipv6)).setText(getLocalIpv6Address());
//Begin button
final Button startButton = (Button) findViewById(R.id.start);
startButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Toast.makeText(getApplicationContext(), "Now Capturing Packets", Toast.LENGTH_LONG).show();
try {
process = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(process.getOutputStream());
os.writeBytes("/data/local/tcpdump -q\n");
os.flush();
os.writeBytes("exit\n");
os.flush();
os.close();
inputStream = new DataInputStream(process.getInputStream());
Thread.sleep(1000);
Process process2 = Runtime.getRuntime().exec("ps tcpdump");
DataInputStream in = new DataInputStream(process2.getInputStream());
String temp = in.readLine();
temp = in.readLine();
temp = temp.replaceAll("^root *([0-9]*).*", "$1");
pid = Integer.parseInt(temp);
Log.e("MyTemp", "" + pid);
process2.destroy();
CaptureActivity.this.thisActivity.CaptureText.setText("Active");
} catch (Exception e) {
}
ListenThread thread = new ListenThread(new BufferedReader(new InputStreamReader(inputStream)));
thread.start();
}
});
}
ListenThread class
public class ListenThread extends Thread {
public ListenThread(BufferedReader reader) {
this.reader = reader;
}
private BufferedReader reader = null;
#Override
public void run() {
reader = new BufferedReader(new InputStreamReader(inputStream));
while (true) {
try {
CaptureActivity.this.thisActivity.CaptureText.setText("exec");
int a = 1;
String received = reader.readLine();
while (a == 1) {
CaptureActivity.this.thisActivity.LiveTraffic.append(received);
CaptureActivity.this.thisActivity.LiveTraffic.append("\n");
received = reader.readLine();
CaptureActivity.this.thisActivity.CaptureText.setText("in loop");
}
CaptureActivity.this.thisActivity.CaptureText.setText("out loop");
} catch (Exception e) {
Log.e("FSE", "", e);
}
}
}
}
I am not an android expert but I notice that:
you are running I/O operations in the UI thread - that will freeze your GUI until the I/O operation finishes ==> run them in a separate thread.
you update the UI from outside the UI thread in ListenThread, which can lead to unexpected results
You can read more about it in this tutorial (make sure you read the 2 examples as the first one is broken (on purpose)).
EDIT
In conclusion you should have something like this in your first piece of code:
startButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Toast.makeText(getApplicationContext(), "Now Capturing Packets", Toast.LENGTH_LONG).show();
new Thread(new Runnable() {
public void run() {
try {
process = Runtime.getRuntime().exec("su");
...
CaptureActivity.this.runOnUiThread(new Runnable() {
public void run() {
CaptureActivity.this.thisActivity.CaptureText.setText("Active");
}
});
} catch (Exception e) {
}
ListenThread thread = new ListenThread(new BufferedReader(new InputStreamReader(inputStream)));
thread.start();
}
}).start();
}
});
and in the second:
while (true) {
try {
CaptureActivity.this.runOnUiThread(new Runnable() {
public void run() {
CaptureActivity.this.thisActivity.CaptureText.setText("exec");
}
});
int a = 1;
String received = reader.readLine();
while (a == 1) {
CaptureActivity.this.runOnUiThread(new Runnable() {
public void run() {
CaptureActivity.this.thisActivity.LiveTraffic.append(received);
CaptureActivity.this.thisActivity.LiveTraffic.append("\n");
CaptureActivity.this.thisActivity.CaptureText.setText("in loop");
}
});
received = reader.readLine();
}
CaptureActivity.this.runOnUiThread(new Runnable() {
public void run() {
CaptureActivity.this.thisActivity.CaptureText.setText("out loop");
}
});
} catch (Exception e) {
Log.e("FSE", "", e);
}
}
That should solve the specific UI interaction issue. But there are other logic problems in your code which go beyond this question (for example the fact that you never test if you have reached the end of the file you are reading, the fact that while(a==1) is an infinite loop because you never change the value of a etc.).

Categories

Resources