I'm trying to develop an android app with remote access functions. I have been searching similar posts about how remote desktop is made and what is the most efficient method, but i haven't found too mutch information about this.
Now i'm trying to send screenshots and display each one on a ImageView. It works, but the ImageView doesn't get refreshed until the app has ended. I tried to use postInvalidate() and invalidate() on an AsyncTask, but it didn't work.
I'd also like to know if there is a better way (or even different ways) to develop a remote desktop app. I wanna do it by myself, so i don't want to use any app as TeamViewer or similar.
Thanks for the help. Here is my code:
Client
public class MainActivity extends Activity {
static Button boton;
static byte[] imagen;
static ImageView imagenVista;
static Bitmap bmp;
static Socket clientSocket;
static OutputStream os;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
boton = (Button)findViewById(R.id.button1);
boton.setOnClickListener(evento);
imagenVista = (ImageView)findViewById(R.id.imageView1);
}
private OnClickListener evento = new OnClickListener() {
#TargetApi(Build.VERSION_CODES.GINGERBREAD)
#Override
public void onClick(View v) {
if (boton.getText().equals("Start")){
boton.setText("Stop");
try{
if (android.os.Build.VERSION.SDK_INT > 9) {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
while(true){
Socket clientSocket= new Socket();
InetSocketAddress addr=new InetSocketAddress("10.209.0.93", 5555);
clientSocket.connect(addr);
OutputStream os=clientSocket.getOutputStream();
os.write("capture".getBytes());
ObjectInputStream entrada = new ObjectInputStream(clientSocket.getInputStream());
construyendo_img(entrada)
new TareaSegundoPlano().doInBackground(entrada);
entrada.close();
os.flush();
clientSocket.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
else{
boton.setText("Start");
}
}
};
public void construyendo_img(ObjectInputStream entrada)throws IOException, ClassNotFoundException{
byte[] bytes_img = (byte[]) entrada.readObject();
ByteArrayInputStream entrada_img = new ByteArrayInputStream(bytes_img);
bmp = BitmapFactory.decodeByteArray(bytes_img, 0, bytes_img.length);
imagenVista.setImageBitmap(bmp);
}
public class TareaSegundoPlano extends AsyncTask<Void, ObjectInputStream, Void>{
protected void onPreExecute(){}
protected Void doInBackground(ObjectInputStream... params) {
imagenVista.invalidate();
return null;
}
protected void onProgressUpdate(Void... values) {}
protected void onPostExecute(Void result){}
#Override
protected Void doInBackground(Void... arg0) {
// TODO Auto-generated method stub
return null;
}
}
}
Related
When I send a photo to the Microsoft Azure Face API (the api, tutorial), I am receiving
com.microsoft.projectoxford.face.rest.ClientException: Image size is too small.
But when I am debugging the application and when I inspect the following code
faceServiceClient.detect( params[0], false, false, expectedFaceAttributes )
actually it IS working and I CAN get the result, but only the first time. If I press "inspect" one more time I will again receiving the above mentioned error message.
P.S. I tried using different images and the behaviors is the same. I would appreciate any help.
The application:
public class MainActivity extends AppCompatActivity {
Bitmap bmpImage;
TextView txtResult;
ByteArrayInputStream bs;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
txtResult = (TextView) findViewById(R.id.txtResult);
Button btnMicrosoft = (Button) findViewById(R.id.btnMicrosoft);
btnMicrosoft.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
getFaces();
makeMicrosoftCall();
}
});
}
private void getFaces() {
bmpImage = BitmapFactory.decodeResource(this.getResources(), R.drawable.face_1);
}
private void makeMicrosoftCall() {
imgEncoding();
GetEmotionCall emotionCall = new GetEmotionCall();
emotionCall.execute(bs);
}
public void imgEncoding()
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bmpImage.compress(Bitmap.CompressFormat.JPEG, 100, baos);
bs = new ByteArrayInputStream(baos.toByteArray());
}
// asynchronous class which makes the api call in the background
private class GetEmotionCall extends AsyncTask<InputStream, String, Face[]> {
GetEmotionCall() {
}
#Override
protected void onPreExecute() {
super.onPreExecute();
txtResult.setText("Getting results...");
}
// this function is called when the api call is made
#Override
protected Face[] doInBackground(InputStream... params) {
FaceServiceClient faceServiceClient = new FaceServiceRestClient("https://westcentralus.api.cognitive.microsoft.com/face/v1.0", "*******************");
// the only attribute wanted it emotional state
FaceServiceClient.FaceAttributeType[] expectedFaceAttributes = new FaceServiceClient.FaceAttributeType[]{FaceServiceClient.FaceAttributeType.Emotion};
try {
//THE PROBLEMATIC AREA
return faceServiceClient.detect( params[0], false, false, expectedFaceAttributes );
} catch (ClientException e) {
Log.e("ClientException", e.toString());
return null;
} catch (IOException e) {
Log.e("IOException", e.toString());
e.printStackTrace();
return null;
}
}
}
}
I am currently using an AsyncTask to fetch the JSON array when pressing a button. After that i have another button called ParseJson which opens a new activity in which a list is shown with the JSONArray.
What i would like, is to have one button instead of 2, but since the getJSON button (first button above) is starting a backgroundtask which needs to be finnished first, before launching the other activity (ParseJSON button), this doesnt work in one button right now.
I heard something about using a loading dialog, but i am quite new to this and have no idea how to solve it.
This is the code i use, but i also need the the value from the Textview in the background task. I will send the value of the textview to a php file (by POST) which fetches the data from the database.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void getJSON(View view) {
TextView txv = (TextView) findViewById(R.id.orderID);
txv.getText().toString;
//I need this value in the backgroundtask later
new BackgroundTask().execute();
}
class BackgroundTask extends AsyncTask<Void, Void, String>
{
String json_url = "MYJSONURL";
String JSON_STRING;
#Override
protected String doInBackground(Void... params) {
try {
URL url = new URL(json_url);
HttpURLConnection httpURLConnection = (HttpURLConnection)url.openConnection();
InputStream inputStream = httpURLConnection.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
StringBuilder stringBuilder = new StringBuilder();
while ((JSON_STRING = bufferedReader.readLine())!=null)
{
stringBuilder.append(JSON_STRING+"\n");
}
bufferedReader.close();
inputStream.close();
httpURLConnection.disconnect();
return stringBuilder.toString().trim();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
}
#Override
protected void onPostExecute(String result) {
json_string = result;
}
}
public void parseJSON(View view)
{
if(json_string==null)
{
Toast.makeText(getApplicationContext(), "First Get JSON", Toast.LENGTH_LONG).show();
}
else
{
Intent intent = new Intent(this, DisplayListView.class);
intent.putExtra("json_data", json_string);
startActivity(intent);
}
}
Instead of starting the AsyncTask by a button press you code in a way by which it can be started as soon as your main activity is launched. Use onProgressUpdate method of the AsyncTask which will show some progress, once that method is finished your data is loaded. Then you use one button to parse and display the data in the list.
You may refer this to know more about AsyncTask methods
You can have a look at the below code to understand how communication can happen between an activity and AsyncTask. For simplicity I have a count loop running inside AsyncTask which will update the progress on the activity.
Please be warned that this code communicates with the same activity which started the AsyncTask. So, if you would like to perform any such background task, you should be having the AsyncTask attached to your second activity.
public class MainActivity extends Activity {
private ProgressBar mProgress;
private int mProgressStatus = 0;
TextView percentage = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mProgress = (ProgressBar) findViewById(R.id.progress_bar);
percentage = (TextView) findViewById(R.id.percentage);
new CountProgress().execute();
}
class CountProgress extends AsyncTask<Void, Integer, Void> {
#Override
protected void onPreExecute() {
mProgress.setProgress(0);
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... unused) {
for (int i=0; i<101;i++ ) {
if (isCancelled())
break;
publishProgress(i);
SystemClock.sleep(200);
}
return(null);
}
#Override
protected void onProgressUpdate(Integer... progress) {
if (!isCancelled()) {
mProgress.setVisibility(View.VISIBLE);
// updating progress bar value
mProgress.setProgress(progress[0]);
// updating progess percentage text
percentage.setText(progress[0].toString() + "%");
}
}
#Override
protected void onPostExecute(Void unused) {
Toast.makeText(getApplicationContext(), R.string.done, Toast.LENGTH_SHORT).show();
}
}
}
A full working app code can be downloaded from here and you can extend it further for your needs.
I don't know what happen with my source code about Socket in Android, when I use method
.isConnected()
My app always force close. And here my source code
public class MyActivity extends Activity {
private String IP;
private int PORT;
private Socket socket;
private PrintWriter printWriter;
private TextView text;
private EditText fieldIp;
private EditText fieldPort;
private Button connect;
private FrameLayout frameIP;
private String message;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
frameIP = (FrameLayout)findViewById(R.id.frameIP);
connect = (Button)findViewById(R.id.connect);
fieldIp = (EditText)findViewById(R.id.ip);
fieldPort = (EditText)findViewById(R.id.port);
text = (TextView)findViewById(R.id.keterangan);
connect.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
IP = fieldIp.getText().toString();
PORT = Integer.parseInt(fieldPort.getText().toString());
SocketConnect socketConnect = new SocketConnect(IP,PORT);
socketConnect.execute();
}
});
}
private class SocketConnect extends AsyncTask<Void, Void, Boolean> {
String ip;
int port;
public SocketConnect(String a, int b){
this.ip = a;
this.port = b;
}
#Override
protected Boolean doInBackground(Void... params) {
try {
socket = new Socket();
socket.connect(new InetSocketAddress(ip,port));
if(socket.isConnected())
{
text.setText("Connected!");
}
else
{
text.setText("Failed to connect!");
}
} catch (IOException e) {
Log.e("MyActivity",e.getMessage());
}
finally {
startActivity(new Intent(getApplicationContext(),ListViewText.class));
}
return null;
}
}
}
And I use this in AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
I hope you can help me guys :(
Change the doInBackground method as follows...
#Override
protected Boolean doInBackground(Void... params) {
boolean success = true;
try {
socket = new Socket();
socket.connect(new InetSocketAddress(ip, port));
} catch (Exception e) {
success = false;
Log.e("MyActivity", e.getMessage());
}
return success;
}
Then add an onPostExecute method...
#Override
protected void onPostExecute(boolean result) {
if(result) {
text.setText("Connected!");
startActivity(new Intent(MyActivity.this, ListViewText.class));
}
else {
text.setText("Failed to connect!");
}
}
First thing you are calling UI operation outside of UI thread (that is why AsyncTask was created, to handle background job only in doInBackground) So problem about displaying text un TextView is solved...
But more important thing:
Never open Socket in AsyncTask. On Android developer site you can find following:
If you need to keep threads running for long periods of time, it is
highly recommended you use the various APIs provided by the
java.util.concurrent package such as Executor, ThreadPoolExecutor and
FutureTask.)
And that is exactly what you want to do. So use Service, Thread or those mentioned above instead.
I'm using asynctask to make connection between client (runnning on my android device) and server(running on my pc). When i launch the app i have to click on button to connect them, and my server pc program should show me in console device if client is connected but doesn't appear; my android client doesn't connect to my pc server.
Android client:
public class MainActivity extends ActionBarActivity {
Button send;
EditText txt;
TextView testo;
String response = "";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
send = (Button) findViewById(R.id.send);
//txt = (EditText) findViewById(R.id.editText);
testo = (TextView) findViewById(R.id.textView1);
}
class AddStringTask extends AsyncTask<Void, String, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... unused) {
try {
Socket socketClient = new Socket("10.10.0.151",4321); //ipaddress of my pc server
} catch (UnknownHostException e) {
e.printStackTrace();
response = e.toString();
} catch (IOException e) {
e.printStackTrace();
response = e.toString();
}
testo.setText(response);
return (null);
}
#SuppressWarnings("unchecked")
#Override
protected void onProgressUpdate(String... item) {
}
#Override
protected void onPostExecute(Void unused) {
testo.setText(response);
}
}
public void buttonClick(View v){
new AddStringTask().execute();
}
}
Pc server:
public class Server {
public static Socket connection;
public static void main(String[] args) throws IOException {
System.out.println("Starting server on port number: 4321...");
ServerSocket server = new ServerSocket(4321);
while(true){
System.out.println("Waiting for clients...");
connection = server.accept();
System.out.println("Connected to: "+connection.getInetAddress().getHostAddress());
connection.close();
}
}
}
In my AndroidManifest.xml i've just added
<uses-permission android:name="android.permission.INTERNET"/>
If i launch client from pc in my server console i see the device connected but on android doesn't work..why?
Thanks
It's most likely the ip in the android side is wrong. use a private ip eg: 192.168.1.x. theese types of ip require you be on the same network. i think what you're trying to do is access the server from outside of the network and that requires port fkrwarding.
Is it possible to scan several ports at once with AsyncTask? I am totally new to AsyncTask, so I have no clue what I am doing. Even after reading all tutorials on the internet about AsyncTask (eg Vogella etc.) I still can't understand how to make this happen.
Here is the code I have at the moment:
public class MainActivity extends Activity {
EditText et;
Button b;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
et = (EditText) findViewById(R.id.editText1);
b = (Button) findViewById(R.id.button1);
}
public void start(View view){
GetPorts task = new GetPorts();
task.execute(20,53,80,114,140);
}
private class GetPorts extends AsyncTask<Integer, Void, Vector<Integer>> {
Vector<Integer> openPorts = new Vector<Integer>();
#Override
protected Vector<Integer> doInBackground(Integer... ports) {
for(Integer port: ports){
try {
Socket socket = new Socket();
socket.connect(new InetSocketAddress("localhost", port), 500);
socket.close();
openPorts.add(port);
} catch (Exception ex) {
}
}
return openPorts;
}
}
}
the ports 20,53,80 etc are the example porst I'd like to check (there could be up to 65535 ports). I thought checking ports and adding them to Vector and then returning this Vector would be a good idea, but I have no idea how to do that. I wonder if my Vector "openPorts" is going to reset with every new port to scan, and will this AsyncTask be able to scan multiple ports at the same time?
I have created the working solution with Java SE and I'm gonna paste it here to clarify what I am after of.
Java SE code:
public class Scanner {
private final String ip;
private final int sPort, ePort, timeout, poolSize;
private Vector<Integer> openPorts = new Vector<Integer>();
private final ExecutorService es;
private Collection<Future<?>> futures = new LinkedList<Future<?>>();
public Scanner(String ip, int sPort, int ePort, int timeout, int poolSize) {
this.ip = ip;
this.sPort = sPort;
this.ePort = ePort;
this.timeout = timeout;
this.poolSize = poolSize;
es = Executors.newFixedThreadPool(this.poolSize);
}
public Vector<Integer> getPorts() {
Collections.sort(openPorts);
return openPorts;
}
public void runScanner() {
for (int startPort = sPort; startPort <= ePort; startPort++) {
futures.add(es.submit(new Check(ip, startPort, timeout)));
}
es.shutdown();
}
public void stopScanner(){
for (Future<?> future : futures) {
future.cancel(true);
}
}
private class Check implements Runnable {
private String ip;
private int port, timeout;
private Check(String ip, int port, int timeout) {
this.ip = ip;
this.port = port;
this.timeout = timeout;
}
public void run() {
try {
Socket socket = new Socket();
socket.connect(new InetSocketAddress(ip, port), timeout);
socket.close();
openPorts.add(port);
} catch (Exception ex) {
}
}
}
}
Your vector will be reset only when you instanciate a new GetPorts class (as usual).
Your code looks just fine. If your problem is to retrieve the result of the AsyncTask, you have two main ways to achieve it.
You can just call Vector<Integer> v = new GetPorts().execute(20,53,80,114,140).get(); but it's not often a proper way.
Or you can implements callback in the AsyncTask post execute callback.
#Override
protected void onPostExecute(Vector<Integer> result) {
}
Your AsyncTask should be like this:
private class GetPorts extends AsyncTask<Integer, Void, Vector<Integer>> {
public interface MyCallbackInterface {
public void myCallback(Vector<Integer> ports);
}
MyCallbackInterface listener;
Vector<Integer> openPorts = new Vector<Integer>();
public GetPorts(MyCallbackInterface listener) {
this.listener = listener;
}
#Override
protected Vector<Integer> doInBackground(Integer... ports) {
for(Integer port: ports){
try {
Socket socket = new Socket();
socket.connect(new InetSocketAddress("localhost", port), 500);
socket.close();
openPorts.add(port);
} catch (Exception ex) {
}
}
return openPorts;
}
#Override
protected void onPostExecute(Vector<Integer> result) {
listener.myCallback(result);
}
}
Then in the task caller which implements MyCallbackInterface, you can do:
new GetPorts(this).execute(20,53,80,114,140);
And doing what you want in :
#Override
public void myCallback(Vector<Integer> ports) {
}