I am writing an Android Application which has a broadcast receiver secured with permissions. The broadcast receiver on receiving requests from authenticated application scans port 80 of a hardcoded IP address. It returns the result of the socket connection attempt. In my code I have the socket connection called from OnReceive ( ) method. I am able to get to the receiver as i can see the toast messages. However, socket connection is caught by Exception E. Here is my code for the receiver :
package com.example.naveenbreceive;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import android.os.Bundle;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.util.Log;
import android.view.Menu;
import android.widget.Toast;
public class breceiver extends Activity {
BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String Target="107.20.112.24";
int i=80;
int timeout=1000;
Toast.makeText(getApplicationContext(),"Intent Received",Toast.LENGTH_LONG).show();
Log.i("INFO","toast launched");
try {
Socket socket = new Socket();
socket.connect(new InetSocketAddress(Target, i), timeout);
if (socket.isConnected())
{Toast.makeText(getApplicationContext(), "Connected to port 80", Toast.LENGTH_LONG).show();
socket.close();
}
else
{Toast.makeText(getApplicationContext(), "Unable to Connect port 80", Toast.LENGTH_LONG).show();
socket.close();
}
}
catch (UnknownHostException e) {
// TODO Auto-generated catch block
Toast.makeText(getApplicationContext(),"UnknownHost Exception",Toast.LENGTH_LONG).show();
e.printStackTrace();
}
catch (IOException e) {
// TODO Auto-generated catch block
Toast.makeText(getApplicationContext(),"IO Exception",Toast.LENGTH_LONG).show();
e.printStackTrace();
}
catch (Exception e) {
// TODO Auto-generated catch block
Toast.makeText(getApplicationContext(),"Exception",Toast.LENGTH_LONG).show();
e.printStackTrace();
}
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// TODO Auto-generated method stub
IntentFilter filterView = new IntentFilter();
filterView.addAction("com.example.HACKING");
registerReceiver(mReceiver, filterView,"com.example.permission.naveen", null);
Toast.makeText(getApplicationContext(),"Inside Receiver",Toast.LENGTH_LONG).show();
}
The broadcast receiver is on the UI thread. You can't do networking on the UI thread. You need to do it in a Thread or AsyncTask.
Also, BroadcastReceivers are supposed to be very quick and do very little work. Their design is supposed to be a quick notification and then you do the heavy lifting elsewhere, so the next app can get the notification. Networking IO is way too much work for a receiver.
Related
I want to enter an IP address and port of a server using editText in Android studio. When a "connect" button is pressed, the entered information should be saved and be accessible to other activities. I have used the SharedPreferences method for saving the acquired data to be accessible across activities (Is this the best way to do so?). The successful creation of a client socket (handled in the service) is checked in the Connect activity (attached below) by means of (!client.isClosed()).
My problem is that whenever the activity reaches the check in the Connect.java activity, the isclosed is nullified. I assume that the client Socket is thus destroyed when it was created in the Service and called in the Connect.java activity.
Is there a way to create the Socket and keep it alive to be used by various other activities- I require the socket to be kept alive to receive/send messages to a server which will determine to which activity the App should transition. The method of creating and closing sockets in every activity will not work as it will be registered as a new user on the server side- firmware on a module I have no access to.
Any examples/documentation/help would be greatly appreciated.
I am very new to Android App development and Java so please be gentle if my questions are stupid :-)
Thank you very much for any assistance.
This is the service for handling the socket creation.
import android.app.IntentService;
import android.content.Intent;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.StrictMode;
import android.util.Log;
import java.io.IOException;
import java.net.Socket;
public class SocketService extends IntentService
{
public Socket client;
public String ClientIP;
public Integer ClientPORT=0;
public SocketService()
{
super("SocketService");
}
#Override
protected void onHandleIntent(Intent Socketintent)
{
StrictMode.ThreadPolicy policy = new
StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
SharedPreferences savednotes= getSharedPreferences("Socket_NAME",
Context.MODE_MULTI_PROCESS);
ClientIP=savednotes.getString("IP_NAME",null); // Get the IP address
ClientPORT=savednotes.getInt("PORT_NAME",0); // Get the Port number
try
{
Log.d("IP", "Master IP address:" + ClientIP); // Debug to see
variables in Shared preferences
Log.d("PORT", "Port number: " + ClientPORT); // Debug to see
variables in Shared preferences
if ((ClientIP) != null)
{
if ((ClientPORT) != null)
{
client = new Socket(ClientIP, ClientPORT); // Create the Socket
}
}
} catch (IOException e)
{
e.printStackTrace();
try {
client.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
This is the Connect.java activity:
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.StrictMode;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import java.io.PrintWriter;
import java.net.Socket;
public class Connect extends AppCompatActivity
{
public Socket client;
private EditText etIP, etPORT;
private TextView status,IPs;
private Button buttonCON;
public int port=0;
public String IP;
SharedPreferences savednotes;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
StrictMode.ThreadPolicy policy = new
StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
setContentView(R.layout.activity_connect);
etIP = (EditText)findViewById(R.id.editTextIP);
etPORT = (EditText)findViewById(R.id.editText2);
buttonCON= (Button)findViewById(R.id.buttonCON);
status= (TextView)findViewById(R.id.textStatus);
IPs=(TextView)findViewById(R.id.textViewIP);
status.setText("Disconnected");
buttonCON.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
port = Integer.parseInt(etPORT.getText().toString());
IP= etIP.getText().toString();
IPs.setText(IP);
savednotes=
getApplicationContext().getSharedPreferences("Socket_NAME",
Context.MODE_MULTI_PROCESS);
SharedPreferences.Editor editor= savednotes.edit();
editor.putString("IP_NAME",IP);
editor.apply();
editor.putInt("PORT_NAME",port);
editor.apply();
Intent Socketintent= new Intent(Connect.this, SocketService.class);
startService(Socketintent);
int i = 0xFF00EE00;
status.setTextColor(i);
status.setText("Connected");
if (!client.isClosed())
{
Intent relay= new Intent(Connect.this, Relay.class);
startActivity(relay);
finish();
}
}
});
}
}
An IntentService is not a suitable solution for your objective. An IntentService is destroyed as soon as onHandleIntent() returns.
Most likely, you do not need any sort of Service here. A Service is for when you want to be doing work when you have no UI in the foreground, and that does not sound like your case here ("Keeping a Client Socket alive between activities"). An ordinary Java singleton would work, so long as you are very careful not to introduce memory leaks.
The method of creating and closing sockets in every activity will not work as it will be registered as a new user on the server side- firmware on a module I have no access to.
Bear in mind that your process does not live forever. Eventually, you will need to create a new socket.
This question already has answers here:
NetworkOnMainThreadException [duplicate]
(5 answers)
Closed 6 years ago.
I'm trying to test if my Android App is connecting to a Rpi hot spot. I'm following this guide for the client code.
I want to have a toast message pop up depending on the state of socket.isConnected() when I hit a button. However, I think each time I try and implement it, I run into Network on the main thread problems. How could I change the following code to add a simple "if(true), send toast message" using the isConnected method in the onClick?
Thank you for any help!
package mrxhaleenterprise.sockettest;
import java.io.BufferedWriter;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends Activity {
private Socket socket;
private static final int SERVERPORT = 39169;
private static final String SERVER_IP = "172.24.1.1";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new Thread(new ClientThread()).start();
}
public void onClick(View view) {
try {
EditText et = (EditText) findViewById(R.id.EditText01);
String str = et.getText().toString();
PrintWriter out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream())),
true);
out.println(str);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
class ClientThread implements Runnable {
#Override
public void run() {
try {
InetAddress serverAddr = InetAddress.getByName(SERVER_IP);
socket = new Socket(serverAddr, SERVERPORT);
} catch (UnknownHostException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
onClick is called on main Thread.So you are writing to socket(Network Operation) on main thread which is causing problem. Your below code should run on background thread.
PrintWriter out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream())),
true);
out.println(str);
I want to have a toast message pop up depending on the state of socket.isConnected() when I hit a button.
No you don't. Once you've constructed that Socket, it is connected, and that method won't magically start returning false if the connection goes down. You need to maintain your own state of the connection, depending on whether you've encountered an IOException or end of stream on it. More probably you don't want the button at all, you want to pop up an error dialogue when the disconnect happens.
So for my research, I have to send accelometer data to an arduino mega as a constant stream. I have the module connected to the arduino via serial. However, when I ran the code, it only runs once. I tried to place the Bluetooth connect part of the code inside my on accuracy change part of my code, but it keeps freezing the device. Here's my code:
package com.example.arduino_bluetooth2;
//=================================================================================================
//Imports
//=================================================================================================
import java.io.IOException;
import java.io.OutputStream;
import java.util.Set;
import java.util.UUID;
import android.os.Bundle;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.view.Menu;
import android.widget.TextView;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
public class MainActivity extends Activity implements SensorEventListener {
// Setup necessary sensor objects
private Sensor acc;
private SensorManager sm;
private TextView t1;
private double value;
// Bluetooth Object
private BluetoothAdapter bAdapter;
private BluetoothDevice device;
private BluetoothSocket mmServerSocket;
private OutputStream btoutput;
private static final UUID SPP_UUID = UUID
.fromString("00001101-0000-1000-8000-00805F9B34FB");
private static final int DISCOVERY_REQUEST = 1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
accelerometer_initialization();
bluetooth_initialization();
}
// Setsup the accelerometer object
private void accelerometer_initialization() {
sm = (SensorManager) getSystemService(SENSOR_SERVICE);
acc = sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
sm.registerListener(this, acc, SensorManager.SENSOR_DELAY_NORMAL);
}
// Setup bluetooth object
private void bluetooth_initialization() {
bAdapter = BluetoothAdapter.getDefaultAdapter();
startActivityForResult(new Intent(
BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE),
DISCOVERY_REQUEST);
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(mReceiver, filter);
bAdapter.startDiscovery();
}
#Override
public void onSensorChanged(SensorEvent event) {
value = event.values[0];
}
#Override
public void onAccuracyChanged(Sensor arg0, int arg1) {
}
final BroadcastReceiver mReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
if (BluetoothDevice.ACTION_FOUND.equals(intent.getAction())) {
device = intent
.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (new String(device.getName()).equals("BT UART")) {
bAdapter.cancelDiscovery();
try {
BluetoothSocket test = null;
test = device
.createInsecureRfcommSocketToServiceRecord(SPP_UUID);
mmServerSocket = test;
mmServerSocket.connect();
String message = Double.toString(value);
byte[] send = message.getBytes();
btoutput = mmServerSocket.getOutputStream();
btoutput.write(send);
btoutput.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
};
};
}
I am not sure you should creating and connecting the bluetooth socket in the broadcast receiver. I do the bluetooth connection management in the onResume() of the activity.
Also I use a thread to manage getting data from the serial data connection between the arduino and the device, it is spawned off and runs continuously in the background. There is a write method to send data out that i call from the activity
/* Call this from the main activity to send data to the remote device */
public void write(String message) {
System.out.println("...Data to send: " + message + "...");
byte[] msgBuffer = message.getBytes();
try {
mmOutStream.write(msgBuffer);
} catch (IOException e) {
System.out.println("...Error data send: " + e.getMessage() + "...");
}
}
then the run() method of the tread takes care of getting data back
See my answer in this thread for an example
Error with receiving xml strings via bluetooth in Android
Good luck!
Check out this page from arduino: http://arduino.cc/en/Reference/Loop
The problem is that it only goes once because it is not in a loop that continues forever until the device is shut off or told otherwise.
I'm working with android xml rpc to mount a server. For that I'm using and intentService. The only problem is that when the server class is launched, my onHandleIntent which contains the server is never called.
I've made some research and I found someone who had the same problem, he managed solving it by using super class but I'm new in programming and didn't manage to do what he did ==> link
Here is my code:
package tfe.rma.ciss.be;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlrpc.android.MethodCall;
import org.xmlrpc.android.XMLRPCServer;
import android.app.IntentService;
import android.content.Intent;
import android.util.Log;
import android.widget.Toast;
import java.io.IOException;
import java.io.StringReader;
import java.net.MalformedURLException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
public class Server extends IntentService {
public String myData="";
public String streamTitle = "",path="";
public void onCreate() {
Log.d("Server", ">>>onCreate()");
}
public Server() {
super("Server");
}
public void onStart (Intent intent, int startId) {
Log.d("Server", ">>>Started()"); }
#Override
protected void onHandleIntent(Intent intent) {
Log.d("Server", ">>>handlingIntent()");
try {
ServerSocket socket = new ServerSocket(8214);
XMLRPCServer server = new XMLRPCServer();
Log.d("Server", ">>>opening on port" + socket);
while (true) {
Socket client = socket.accept();
MethodCall call = server.readMethodCall(client);
String name = call.getMethodName();
if (name.equals("newImage")) {
ArrayList<Object> params = call.getParams();
// assume "add" method has two Integer params, so no checks done
myData = (String)( params.get(0));
//int i1 = (Integer) params.get(1);
server.respond(client, new Object[] {200});
/*intent = new Intent (this, ParseFunction.class);
startService (intent); */
Toast.makeText(this, myData, Toast.LENGTH_SHORT).show();
Log.d("ParseFunction", ">>>Started()");
Intent i = new Intent( this, B.class );
i.putExtra( "Azo", myData);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity( i );
} else {
server.respond(client, null);
}
}
} catch (IOException e) {
e.printStackTrace();
} catch (XmlPullParserException e) {
e.printStackTrace();
}
}
}
If you got here and nothing worked, check your manifest looks like this:
<service android:name=".subpackage.ServiceClassName" >
</service>
And not like this:
<service android:name=".subpackage.ServiceClassName" />
There's a problem with xml closing tags. The first one works. The second is legal but doesn't work.
In case someone else wants the result here is what I should have done. Adding superclass to onCreate super.onCreate() and change onStart by onStartCommand (plus its superclass super.onStartCommand()), now it works as a charm
package tfe.rma.ciss.be;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlrpc.android.MethodCall;
import org.xmlrpc.android.XMLRPCServer;
import android.app.IntentService;
import android.content.Intent;
import android.util.Log;
import android.widget.Toast;
import java.io.IOException;
import java.io.StringReader;
import java.net.MalformedURLException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
public class Server extends IntentService {
public String myData="";
public String streamTitle = "",path="";
public void onCreate() {
super.onCreate();
Log.d("Server", ">>>onCreate()");
}
public Server() {
super("Server");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, startId, startId);
Log.i("LocalService", "Received start id " + startId + ": " + intent);
return START_STICKY;
}
#Override
protected void onHandleIntent(Intent intent) {
Log.d("Server", ">>>handlingIntent()");
try {
ServerSocket socket = new ServerSocket(8214);
XMLRPCServer server = new XMLRPCServer();
Log.d("Server", ">>>opening on port" + socket);
while (true) {
Socket client = socket.accept();
MethodCall call = server.readMethodCall(client);
String name = call.getMethodName();
if (name.equals("newImage")) {
ArrayList<Object> params = call.getParams();
// assume "add" method has two Integer params, so no checks done
myData = (String)( params.get(0));
//int i1 = (Integer) params.get(1);
server.respond(client, new Object[] {200});
/*intent = new Intent (this, ParseFunction.class);
startService (intent); */
Toast.makeText(this, myData, Toast.LENGTH_SHORT).show();
Log.d("ParseFunction", ">>>Started()");
Intent i = new Intent( this, B.class );
i.putExtra( "Azo", myData);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity( i );
} else {
server.respond(client, null);
}
}
} catch (IOException e) {
e.printStackTrace();
} catch (XmlPullParserException e) {
e.printStackTrace();
}
}
}
Get rid of onStart(). First, it is obsolete. Second, you are not chaining to the superclass, thereby preventing IntentService from doing its work.
I had the same issue, it turned out the service definition was missing in the App manifest.
Adding:
<service
android:name=".MyIntentServiceName"
android:exported="false" />
solved the problem.
Just to sum up: In case you override onStartCommand, do not forget to call super:
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
If not, check your manifest, see answer by Mister Smith.
I was having this problem but only on some devices, more specifically on a Motorola Moto G 1st Gen (4.5" & 4G-less) and the solution was to include the FULL PACKAGE NAME in the Service description in the Manifest.
So changing 'mypackage.MyService' to 'com.android.myapp.mypackage.MyService' solved the onHandleIntent never being called.
Some of you might get to this page because your onHandleIntent() method never gets called, despite you implemented everything just fine.
If it's your first service you try to test, you might not be awared of the importance of permissions. In that case check your permissions.
I hope this helps someone.
I had the same problem. I removed the OnCreate method and it works like a charm now. LMK if it worked for you :)
I'm starting to code with MulticastSocket, trying to make a simple app with a client and a server to send messages.
The code I have for the server:
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.SocketException;
public class Servidor {
private static MulticastSocket ms;
public static void main(String[] args) throws IOException{
InetAddress sessAddr = InetAddress.getByName("224.2.76.24");
try{
sessAddr = InetAddress.getByName("224.2.76.24");
ms = new MulticastSocket(5500);
ms.joinGroup(sessAddr);
while (true)
{
byte[] mensaje = new byte[1024];
mensaje = "aa".getBytes();
DatagramPacket dp = new DatagramPacket(mensaje, mensaje.length,sessAddr,5500);
ms.send(dp);
}
}
catch (SocketException se) {
System.err.println(se);
}
ms.leaveGroup(sessAddr);
}
}
And this on the client:
package com.example;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.UnknownHostException;
import android.app.Activity;
import android.os.Bundle;
import android.widget.EditText;
import android.widget.TextView;
public class ClienteMultiCast extends Activity {
/** Called when the activity is first created. */
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView Mensaje;
Mensaje =(TextView)findViewById(R.id.Mensaje);
InetAddress ia = null;
byte[] buffer = new byte[65535];
MulticastSocket ms = null;
int port = 5500;
try {
ia = InetAddress.getByName("224.2.76.24");
DatagramPacket dp = new DatagramPacket(buffer, buffer.length,ia,port);
ms = new MulticastSocket(port);
ms.joinGroup(ia);
while (true) {
ms.receive(dp);
String s = new String(dp.getData(),0,dp.getLength());
Mensaje.setText(s);
}
} catch (UnknownHostException e) {Mensaje.setText(e.getMessage());} catch (IOException e) {Mensaje.setText(e.getMessage()); }
try {
ms.leaveGroup(ia);
} catch (IOException e) {
Mensaje.setText(e.getMessage());
}
}
}
The problem is that when I start both, nothing happens. The client doesn't get any message.
Any idea what's wrong?
Diego,
By default, the Android WiFi stack filters out multicast packets. Take a look at http://developer.android.com/reference/android/net/wifi/WifiManager.MulticastLock.html.
You need something along the lines of:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/* Turn off multicast filter */
MulticastLock mcastLock = new MulticastLock();
mcastLock.acquire();
/* Process Multicast Packets */
}
It appears that Multicast support in Android is not as solid as some of use might hope. See http://codeisland.org/2012/udp-multicast-on-android/
Ie whether it actually works out or may be device dependent. It is not working on my Nexus5.
https://code.google.com/p/android/issues/detail?id=51195