Reputation: 543
I want to publish or advertise my device name over WiFi, which is variable and can be changed by user.
For example, Take a file transfer application Xender
. We can see the device name set by users on screen when we select receive
option in the app. Here is screen shot.
You can see in the image that name shah.kaushal
is appearing.
I've searched many results on Internet, but can't figure out what the exact thing it is.
I know about host name but I think generally it is not changed by such apps and I think it need some special privileges on android to do so. So I'm sure it is not the host name, Which we can get easily from IP address.
Please note I'm not copying any other apps features. I want this in my music player application to share songs.
To do so, I've used TCP connection between devices. And I can successfully send songs from one device to another. But It requires IP address of the device. Which is not user friendly.
Here is the screenshot of my basic music sharing activity, Which lists the available IP addresses and user have to select one IP from the list.
Here instead of IP addresses, I want to display device names.
My code for sending file is:
@Override
protected Void doInBackground(Void... voids) {
System.out.println("array list");
ArrayList<File> files = new ArrayList<>();
System.out.println("about to create.");
files.add(new File(wholePath));
System.out.println("file created..");
try {
//Receiving IP addresses which are available to send our files(Music)!!
a = getClientList();
//update the UI to display the received IP addresses!!
publishProgress();
//busy waiting for user to select appropriate IP address to send files!
while (destinationAddress.equals("-1")){
}
//User has selected something, It's time to send files there!
socket = new Socket(destinationAddress,5004);
System.out.println("Connecting...");
DataInputStream dis = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
System.out.println(files.size());
//write the number of files to the server
dos.writeInt(files.size());
dos.flush();
//write file size
for(int i = 0;i< files.size();i++){
int file_size = Integer.parseInt(String.valueOf(files.get(i).length()));
dos.writeLong(file_size);
dos.flush();
}
//write file names
for(int i = 0 ; i < files.size();i++){
dos.writeUTF(files.get(i).getName());
dos.flush();
}
//buffer for file writing, to declare inside or outside loop?
int n = 0;
byte[]buf = new byte[4092];
//outer loop, executes one for each file
for(int i =0; i < files.size(); i++){
System.out.println(files.get(i).getName());
//create new fileinputstream for each file
FileInputStream fis = new FileInputStream(files.get(i));
//write file to dos
while((n =fis.read(buf)) != -1){
dos.write(buf,0,n);
dos.flush();
}
}
dos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
xceptionFlag = true;
e.printStackTrace();
}
Log.i("===end of start ====", "==");
try{
if(!socket.isClosed()){
socket.close();
}
}
catch (Exception e){
xceptionFlag = true;
e.printStackTrace();
}
return null;
}
And code for receiving file is:
@Override
protected Void doInBackground(Void... voids) {
try {
//this is done isntead of above line because it was givind error of address is already in use.
ss = new ServerSocket();
ss.setReuseAddress(true);
ss.bind(new InetSocketAddress(5004));
System.out.println("waiting");
Socket socket = ss.accept();
System.out.println("Accepted!");
DataInputStream dis = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
//read the number of files from the client
int number = dis.readInt();
ArrayList<File>files = new ArrayList<File>(number);
System.out.println("Number of Files to be received: " +number);
ArrayList<Long> fileSize = new ArrayList<>(number);
for(int i = 0; i < number ;i++){
long size = dis.readLong();
System.out.println(size);
fileSize.add(size);
}
//read file names, add files to arraylist
for(int i = 0; i< number;i++){
File file = new File(dis.readUTF());
files.add(file);
}
int n = 0;
byte[]buf = new byte[4092];
//outer loop, executes one for each file
for(int i = 0; i < files.size();i++){
System.out.println("Receiving file: " + files.get(i).getName());
//Create new Folder for our app, if it is not there and store received files there in our separate folder.
File folder = new File(Environment.getExternalStorageDirectory() +
File.separator + "File");
boolean success = true;
if (!folder.exists()) {
success = folder.mkdirs();
}
if (success) {
// Do something on success
} else {
// Do something else on failure
}
//create a new fileoutputstream for each new file
FileOutputStream fos = new FileOutputStream("mnt/sdcard/File/" +files.get(i).getName());
//read file
while (fileSize.get(i) > 0 && (n = dis.read(buf, 0, (int)Math.min(buf.length, fileSize.get(i)))) != -1)
{
fos.write(buf,0,n);
long x = fileSize.get(i);
x = x-n;
fileSize.set(i,x);
}
fos.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
xceptionFlag = true;
e.printStackTrace();
}
////////////////////
Log.i("== the end of read ====", "==");
try{
if(!ss.isClosed()){
ss.close();
}
}
catch (Exception e){
xceptionFlag = true;
e.printStackTrace();
}
return null;
}
I've included the code for reference. Thanks.
Upvotes: 9
Views: 321
Reputation: 9784
Just have the name set and stored in SharedPreferences
or wherever as a String, then when you show the screen where you are listing the IP, connect to every one of them and transfer this String and display it instead of the IP. Something like Send a string instead of byte through socket in Java to transfer the String.
When you want to publish the name from a device start this service, and stop it when it shouldn't be publishing the name anymore:
public class NameService extends Service {
private volatile boolean running;
private volatile String myName;
private volatile ServerSocket serverSocket;
public NameService() {
}
@Override
public void onCreate() {
super.onCreate();
try {
serverSocket = new ServerSocket();
serverSocket.bind(new InetSocketAddress(5006));
serverSocket.setReuseAddress(true);
serverSocket.setSoTimeout(2000);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
myName = PreferenceManager.getDefaultSharedPreferences(getApplicationContext())
.getString("NAME_STRING", "TEST.NAME");
if (!running)
{
running = true;
new Thread(new Runnable() {
@Override
public void run() {
while (running)
{
try {
Socket socket = serverSocket.accept();
PrintWriter writer = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream())),
true);
writer.println(myName);
writer.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}).start();
}
return START_NOT_STICKY;
}
@Override
public void onDestroy() {
running = false;
super.onDestroy();
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
}
Then when want to display the list of receivers, connect to each one and do the following:
try {
Socket socket = new Socket();
socket.connect(new InetSocketAddress(ipAddress, 5006), 5000);
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String message = reader.readLine();
reader.close();
socket.close();
Log.i("TAG", message);
} catch (IOException e) {
e.printStackTrace();
}
You can do further calls to startService()
if you want to change the name when it is running.
I recommend you use Service
or IntentService
for your file transfers, AsyncTask
is not appropriate.
Upvotes: 1
Reputation: 1655
Try out this:
For each IP Address, you can resolve hostname using InetAddress
class
InetAddress addr = InetAddress.getByName("IP-ADDRESS");
String host = addr.getHostName();
Log.i("host:",host);
Hope this helps. If not, I can suggest some other approaches.
Upvotes: 0