1

I have been trying to send an image using a particular network, the image is being sent successfully when I don't mention any network. I have tried it with both Async task and IntentService. Also if I don't mention any network and the state of the app is running, when I try to turn off the wifi and then I turn it on again the image is not being sent.

Thank you in advance

Service class

public class ImageService extends IntentService {

    public ImageService() {
        super("HelloIntentService");
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    protected void onHandleIntent(@Nullable final Intent intent) {

        new Thread(new Runnable() {
            @Override
            public void run () {
                byte[] bytesss=intent.getByteArrayExtra("byte");
                try {
                Socket socket = new Socket("ip_address", 8888);
                OutputStream out = socket.getOutputStream();
                DataOutputStream dataOutputStream = new DataOutputStream(out);
                dataOutputStream.write(bytesss);
                dataOutputStream.close();
                out.close();
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            }

        }).start();

    }


    @Override
    public void onDestroy() {
        super.onDestroy();
    }
}

MainActivity.java

    private WifiManager wifiManager;

    String networkSSID="network";
    String networkPassword="pass123";
     int netId;

   wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE); 
    networkConfiguration();


}
    private void networkConfiguration(){

        WifiConfiguration configuration=new WifiConfiguration();
        configuration.SSID="\""+networkSSID+"\""; 
        configuration.preSharedKey="\""+networkPassword+"\"";  

        wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE); 

        netId=wifiManager.addNetwork(configuration); 
        wifiManager.disconnect();
        wifiManager.enableNetwork(netId,true);
        wifiManager.reconnect();
    }

    private BroadcastReceiver wifiStateReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
                final String action=intent.getAction();

              if (action.equals(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION)){
                if (intent.getBooleanExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED,false)){

                    Toast.makeText(context, "wifi connected", Toast.LENGTH_SHORT).show();
                    sendingImage();

                }else{

                    Toast.makeText(context, "Please Check Your Internet Connection", Toast.LENGTH_SHORT).show();

                }
            }

        }
    };

  @Override
    protected void onStart() { 
        super.onStart();
        networkConfiguration();
        IntentFilter intentFilter = new IntentFilter(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
        registerReceiver(wifiStateReceiver, intentFilter);
}

   @Override
    protected void onPause() {
        super.onPause();
        unregisterReceiver(wifiStateReceiver);
        stopService(new Intent(this, SendImageClientService.class));
    }


    private void sendingImage() {

        drawable = (BitmapDrawable) imageView.getDrawable();
        bitmap = drawable.getBitmap();
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream);
        byte[] array = byteArrayOutputStream.toByteArray();

        Intent serviceIntent=new Intent(this,ImageService.class);
        serviceIntent.putExtra("byte",array);
       this.startService(serviceIntent);


    }
  • Are there any logs of errors or something else when it isn't working? If there are, can you include them in your question? – JensV Apr 10 '20 at 08:04
  • There are no errors, even the toast of "Please Check Your Wifi Connection" doesn't appear, which means the connection is establishing successfully – Noman Ansari Apr 10 '20 at 08:08
  • Add some logging or a toast when you attempt to send the image. Perhaps the problem is that you never get the `WIFI_STATE_ENABLED` event. Better yet, log every event you receive from the receiver – JensV Apr 10 '20 at 08:11
  • I have already tried it and wifi state is enabled. – Noman Ansari Apr 10 '20 at 08:17
  • Are you sure the intent service is being started? Android has some restrictions for starting services especially when the app is in background and such. Since you are sure that the event is received, `sendingImage()` must've been called and it seems the only place this would stop working is if the service wasn't started correctly. You can also check the general logcat messages for errors which might not show if you filter by your application. But it's usually hard to find in between all the other messages. – JensV Apr 10 '20 at 08:20
  • E/HwCHRWifiFile: getFileResult throw exceptionjava.io.FileNotFoundException: /proc/wifi/wifi_tim_stat (No such file or directory) java.net.SocketException: Software caused connection abort java.io.FileNotFoundException: /sys/kernel/hungtask/vm_heart (Permission denied) These are some errors in logcat – Noman Ansari Apr 10 '20 at 08:27
  • You are actually only listening for if wifi is enabled/disabled, not actually if it's connected or not. This means you receive the event too early when you are not yet connected to the wifi. See the above question for how to detect when you are connected. The first answer might actually be better for your use-case – JensV Apr 10 '20 at 08:31
  • I tried as you suggested but still it doesn't succeed, I have same errors in logcat and this exception : RemoteException caught trying to send a callback msg for NetworkRequest [ LISTEN id=9495, [ Capabilities: INTERNET&NOT_RESTRICTED&TRUSTED&FOREGROUND] – Noman Ansari Apr 10 '20 at 08:52
  • Can you update your question with the new method? – JensV Apr 10 '20 at 08:55
  • I have updated the code – Noman Ansari Apr 10 '20 at 09:00
  • Sorry, the linked answer you chose is a bit misleading since the `SUPPLICANT_CONNECTION_CHANGE_ACTION` is no longer supported. You should really use WorkManager for this. As shown in this answer: https://stackoverflow.com/a/52330503/2232127 . The Android API changes a lot over time which is just part of android development... I can write up an answer with Workmanager if you'd like. (Also you should no longer use a Service with this solution) – JensV Apr 10 '20 at 09:09

1 Answers1

0

This should give you an idea how to implement this with WorkManager. It's assumed that this inherits from Context (Activity, Service, etc. ). The UploadWorker can also be a completely separate class.

I have not tested this, but in theory it should work.

You will need WorkManager as a dependency. So in your build.gradle of your app you need to add it:

dependencies {
    ...

    def work_version = "2.3.4" // current version at time of answer
    // (Java only)
    implementation "androidx.work:work-runtime:$work_version"

}

And here's the java code:

public void entry() {

    // Create temporary file
    // Use some kind of numbering system if you need multiple at once
    // Should use some method of cleaning up files if they never get uploaded
    File outputFile = new File(getNoBackupFilesDir(), "upload_image.jpg");


    // Save ImageView to file
    BitmapDrawable drawable = (BitmapDrawable) imageView.getDrawable();
    Bitmap bitmap = drawable.getBitmap();
    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    try (FileOutputStream fileOutputStream = new FileOutputStream(outputFile)) {
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fileOutputStream);
    } catch (IOException e) {
        e.printStackTrace();
        return;
    }

    Data inputData = new Data.Builder()
            .putString("imagePath", outputFile.getAbsolutePath())
            .build();

    OneTimeWorkRequest uploadWork = new OneTimeWorkRequest.Builder(UploadWorker.class)
            .setConstraints(new Constraints.Builder()
                    .setRequiredNetworkType(NetworkType.UNMETERED)
                    .build())
            .setInputData(inputData)
            .build();

    WorkManager.getInstance(this).enqueue(uploadWork);

}


public static class UploadWorker extends Worker {

    public UploadWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
        super(context, workerParams);
    }

    @NonNull
    @Override
    public Result doWork() {
        String imagePath = getInputData().getString("imagePath");
        File imageFile = new File(imagePath);

        try {
            Socket socket = new Socket("ip_address", 8888);
            OutputStream out = socket.getOutputStream();
            DataOutputStream dataOutputStream = new DataOutputStream(out);
            FileInputStream fis = new FileInputStream(imageFile);
            BufferedInputStream bis = new BufferedInputStream(fis);

            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = bis.read(buffer, 0, buffer.length)) != -1) {
                dataOutputStream.write(buffer, 0, bytesRead);
            }

            bis.close();
            dataOutputStream.close();
            out.close();
            socket.close();

            imageFile.delete();
        } catch (IOException e) {
            e.printStackTrace();
            return Result.failure();
        }

        return Result.success();
    }
}

Update: Added a solution with a temporary file and direct data buffering to support uploading large files.

JensV
  • 3,997
  • 2
  • 19
  • 43
  • should I remove everything related to broadcastReceiver? and only add networkConfiguration() and entry() method in my code? I tried your code but now there is one more error IllegalStateException: Data cannot occupy more than 10240 bytes when serialized – Noman Ansari Apr 10 '20 at 09:45
  • @NomanAnsari the broadcast receiver is not needed anymore. Since you have so much data, it is perhaps more reasonable to create a temporary file and pass the filename instead of the raw bytes. Since the Work could start running after the App was restarted, the data would need to stay in memory. By using a file you circumvent that. – JensV Apr 10 '20 at 10:47
  • @NomanAnsari the `entry()` function is basically your `sendingImage()` method. You can name it whatever you want – JensV Apr 10 '20 at 10:48
  • okay I am working on it, by creating temporary file. But I want to know does this UploadWorker checks for wifi connectivity and as I want to connect to specific wifi that is why I have networkConfiguration() method – Noman Ansari Apr 10 '20 at 10:57
  • @NomanAnsari I've edited the answer to include a solution with a temporary file. Not tested though – JensV Apr 10 '20 at 11:01
  • when I remove this networkConfiguration() method every where in the code. The app works perfect, So I really think it has something to do with this method (without Worker class) – Noman Ansari Apr 10 '20 at 11:03
  • Which version of android are you using? `addNetwork()` won't work from API 29 (Q) and further. – JensV Apr 10 '20 at 11:12
  • I'm not completely sure of your use-case but the code in this question should help: https://stackoverflow.com/q/57929863/2232127 But this is turning into a separate question. If my solution with file uploading on network change helped, you can upvote and accept my answer. For any further help, post a new question – JensV Apr 10 '20 at 11:14