Tag

fileuploading

Browsing

In the previous blog, I have learned, File uploading to the server from an activity. Now In this article, Iโ€™m going to explain how to upload file to the server using Android Service.

In earlier, Normally We use IntentService to perform background task, it is an advanced form of background service in android. That creates a separate thread to perform background operation. But Android Oreo imposed some limitation of background execution. I have written a separate article on it you can read here. So IntentService does not work in Oreo devices and onward while app is in background. In Oreo Android introduced JobIntentService for performing background. It is the modern way of using the background service to perform background task(that run in both cases while app is foreground or background). I have written also a separate article on Working with JobIntentService also. Now we will use JobIntentService for file uploading.

Step for implementation

  1. Create a new class and extends JobIntentService.
  2. Now override the onHandleWork() methods.
  3. Setup Retrofit instance and Expose API file upload API
  4. Place file upload logic in onHandleWork()
  5. Create a local BroadCastReceiver() that update the result of service in activity
  6. Now expose enqueueWork() to start this service
  7. Open MainActivity and starts the JobIntentService
  8. We have to pass file path with Intent so write a below code for getting file from camera and intent.
  9. Open AndroidManifest and add followings code
Upload Files to Server using Service (Demo App)

Let’s implements above one by one.

1. Create a new class and extends JobIntentService

Create a new project with Basic Template. open app/build.gradle add the dependency

    implementation 'com.squareup.retrofit2:retrofit:2.4.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
    // reactive
    implementation 'io.reactivex.rxjava2:rxjava:2.1.10'
    implementation 'io.reactivex.rxjava2:rxandroid:2.0.2'
    implementation 'com.squareup.retrofit2:adapter-rxjava2:2.4.0'
    /**
     * dependency to request the runtime permissions.
     */
    implementation 'com.karumi:dexter:5.0.0'
    implementation 'com.github.bumptech.glide:glide:4.8.0'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0'

After that create a new class in named is FileUploadService and extends JobIntentService. Then override the onHandleWork() methods.

package com.wave.fileuploadservice;

import android.content.Intent;
import android.support.annotation.NonNull;
import android.support.v4.app.JobIntentService;


/**
 * Created on : Mar 13, 2019
 * Author     : AndroidWave
 */
public class FileUploadService extends JobIntentService {
    @Override
    protected void onHandleWork(@NonNull Intent intent) {

    }
}
2. Setup Retrofit instance and Expose API file upload API

Create a interface named RestApiService and expose file upload API

package com.wave.fileuploadservice.service;

import io.reactivex.Single;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.http.Multipart;
import retrofit2.http.POST;
import retrofit2.http.Part;

/**
 * Created on : Feb 25, 2019
 */
public interface RestApiService {

  @Multipart
  @POST("fileUpload.php")
  Single<ResponseBody> onFileUpload(@Part("email") RequestBody mEmail,
      @Part MultipartBody.Part file);
}

Now create instances of Retrofit like this

package com.wave.fileuploadservice.service;

import java.util.concurrent.TimeUnit;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;

import static com.wave.fileuploadservice.BuildConfig.BASE_URL;

/**
 * Created on : Feb 25, 2019
 * Author     : AndroidWave
 */
public class RetrofitInstance {

  private static Retrofit retrofit = null;

  public static RestApiService getApiService() {

    OkHttpClient client = new OkHttpClient.Builder()
        .readTimeout(2, TimeUnit.MINUTES)
        .writeTimeout(2, TimeUnit.MINUTES).addInterceptor(chain -> {
          Request original = chain.request();
          Request.Builder requestBuilder = requestBuilder = original.newBuilder()
              .method(original.method(), original.body());
          Request request = requestBuilder.build();
          return chain.proceed(request);
        }).build();

    if (retrofit == null) {
      retrofit = new Retrofit
          .Builder()
          .baseUrl(BASE_URL)
          .client(client)
          .addConverterFactory(GsonConverterFactory.create())
          .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
          .build();
    }
    return retrofit.create(RestApiService.class);
  }
}
3. Create a utility class named is CountingRequestBody
package com.wave.fileuploadservice.service;

import android.support.annotation.NonNull;
import java.io.IOException;
import okhttp3.MediaType;
import okhttp3.RequestBody;
import okio.Buffer;
import okio.BufferedSink;
import okio.ForwardingSink;
import okio.Okio;
import okio.Sink;

/**
 * Created on : Dec 30, 2018
 */
public class CountingRequestBody extends RequestBody {

  private final RequestBody delegate;
  private final Listener listener;

  public CountingRequestBody(RequestBody delegate, Listener listener) {
    this.delegate = delegate;
    this.listener = listener;
  }

  @Override
  public MediaType contentType() {
    return delegate.contentType();
  }

  @Override
  public long contentLength() {
    try {
      return delegate.contentLength();
    } catch (IOException e) {
      e.printStackTrace();
    }
    return -1;
  }

  @Override
  public void writeTo(@NonNull BufferedSink sink) throws IOException {
    CountingSink countingSink = new CountingSink(sink);
    BufferedSink bufferedSink = Okio.buffer(countingSink);

    delegate.writeTo(bufferedSink);

    bufferedSink.flush();
  }

  final class CountingSink extends ForwardingSink {

    private long bytesWritten = 0;

    CountingSink(Sink delegate) {
      super(delegate);
    }

    @Override
    public void write(@NonNull Buffer source, long byteCount) throws IOException {
      super.write(source, byteCount);
      bytesWritten += byteCount;
      listener.onRequestProgress(bytesWritten, contentLength());
    }
  }

  public interface Listener {
    void onRequestProgress(long bytesWritten, long contentLength);
  }
}
4.. Open the FileUploadService and do following operation

Furthermore, open the FileUploadService again and call the API likes below

  • Place file upload logic in onHandleWork()
  • Create a local BroadCastReceiver() that updates the result in activity
  • Now expose enqueueWork() to start this service

The complete FileUploadService is looks like this

package com.wave.fileuploadservice;

import android.content.Context;
import android.content.Intent;
import android.support.annotation.NonNull;
import android.support.v4.app.JobIntentService;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import com.wave.fileuploadservice.service.CountingRequestBody;
import com.wave.fileuploadservice.service.RestApiService;
import com.wave.fileuploadservice.service.RetrofitInstance;
import com.wave.fileuploadservice.utils.MIMEType;
import io.reactivex.BackpressureStrategy;
import io.reactivex.Flowable;
import io.reactivex.FlowableEmitter;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import java.io.File;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;

public class FileUploadService extends JobIntentService {
  private static final String TAG = "FileUploadService";
  Disposable mDisposable;
  /**
   * Unique job ID for this service.
   */
  private static final int JOB_ID = 102;

  public static void enqueueWork(Context context, Intent intent) {
    enqueueWork(context, FileUploadService.class, JOB_ID, intent);
  }

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

  @Override
  protected void onHandleWork(@NonNull Intent intent) {
    /**
     * Download/Upload of file
     * The system or framework is already holding a wake lock for us at this point
     */

    // get file file here
    String mFilePath = intent.getStringExtra("mFilePath");
    if (mFilePath == null) {
      Log.e(TAG, "onHandleWork: Invalid file URI");
      return;
    }
    RestApiService apiService = RetrofitInstance.getApiService();
    Flowable<Double> fileObservable = Flowable.create(emitter -> {
      apiService.onFileUpload(createRequestBodyFromText("info@androidwave.com"),
          createMultipartBody(mFilePath, emitter)).blockingGet();
      emitter.onComplete();
    }, BackpressureStrategy.LATEST);

    mDisposable = fileObservable.subscribeOn(Schedulers.computation())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(progress -> onProgress(progress), throwable -> onErrors(throwable),
            () -> onSuccess());
  }

  private void onErrors(Throwable throwable) {
    sendBroadcastMeaasge("Error in file upload " + throwable.getMessage());
    Log.e(TAG, "onErrors: ", throwable);
  }

  private void onProgress(Double progress) {
    sendBroadcastMeaasge("Uploading in progress... " + (int) (100 * progress));
    Log.i(TAG, "onProgress: " + progress);
  }

  private void onSuccess() {
    sendBroadcastMeaasge("File uploading successful ");
    Log.i(TAG, "onSuccess: File Uploaded");
  }

  public void sendBroadcastMeaasge(String message) {
    Intent localIntent = new Intent("my.own.broadcast");
    localIntent.putExtra("result", message);
    LocalBroadcastManager.getInstance(this).sendBroadcast(localIntent);
  }

  private RequestBody createRequestBodyFromFile(File file, String mimeType) {
    return RequestBody.create(MediaType.parse(mimeType), file);
  }

  private RequestBody createRequestBodyFromText(String mText) {
    return RequestBody.create(MediaType.parse("text/plain"), mText);
  }

  /**
   * return multi part body in format of FlowableEmitter
   */
  private MultipartBody.Part createMultipartBody(String filePath, FlowableEmitter<Double> emitter) {
    File file = new File(filePath);
    return MultipartBody.Part.createFormData("myFile", file.getName(),
        createCountingRequestBody(file, MIMEType.IMAGE.value, emitter));
  }

  private RequestBody createCountingRequestBody(File file, String mimeType,
      FlowableEmitter<Double> emitter) {
    RequestBody requestBody = createRequestBodyFromFile(file, mimeType);
    return new CountingRequestBody(requestBody, (bytesWritten, contentLength) -> {
      double progress = (1.0 * bytesWritten) / contentLength;
      emitter.onNext(progress);
    });
  }
}
4.1 Declare service inside the Manifest
  • For Pre-Oreo devices => We have to set uses permission โ€“ WAKE_LOCK permission
  • For Oreo device => you have to declare android.permission.BIND_JOB_SERVICE
  <!--for JobIntentService-->
  <uses-permission android:name="android.permission.WAKE_LOCK" />

  <service
      android:name=".FileUploadService"
      android:permission="android.permission.BIND_JOB_SERVICE" />
5. Open activity_main.xml and add below code
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">


  <ImageView
      android:id="@+id/ivDisplayImage"
      android:layout_width="wrap_content"
      android:layout_height="200dp"
      android:layout_marginStart="8dp"
      android:layout_marginTop="56dp"
      android:layout_marginEnd="8dp"
      android:layout_marginBottom="16dp"
      app:layout_constraintBottom_toTopOf="@+id/tvSelectedFilePath"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintHorizontal_bias="0.5"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toTopOf="parent"
      app:layout_constraintVertical_chainStyle="packed"
      app:srcCompat="@drawable/photo" />

  <Button
      android:id="@+id/buttonUpload"
      android:layout_width="200dp"
      android:layout_height="wrap_content"
      android:layout_marginStart="8dp"
      android:layout_marginTop="8dp"
      android:layout_marginEnd="8dp"
      android:background="@color/colorAccent"
      android:text="UPLOAD"
      android:textColor="#fff"
      android:textSize="18sp"
      app:layout_constraintBottom_toBottomOf="parent"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintHorizontal_bias="0.5"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toBottomOf="@+id/tvSelectedFilePath" />

  <TextView
      android:id="@+id/tvSelectedFilePath"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_marginStart="8dp"
      android:layout_marginTop="32dp"
      android:layout_marginEnd="8dp"
      android:layout_marginBottom="16dp"
      android:gravity="center"
      android:hint="Selected file"
      android:textSize="18sp"
      android:textColor="#161616"
      app:layout_constraintBottom_toTopOf="@+id/buttonUpload"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintHorizontal_bias="0.5"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toBottomOf="@+id/ivDisplayImage" />

  <ImageView
      android:id="@+id/imageView2"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_marginStart="8dp"
      android:layout_marginEnd="8dp"
      android:layout_marginBottom="16dp"
      app:layout_constraintBottom_toTopOf="@+id/tvSelectedFilePath"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:srcCompat="@drawable/pencil" />

  <TextView
      android:id="@+id/textView2"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_marginStart="8dp"
      android:layout_marginTop="32dp"
      android:layout_marginEnd="8dp"
      android:text="File Uploading using Service  Demo App"
      android:textColor="@color/colorPrimary"
      android:textSize="18sp"
      android:textStyle="bold"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toTopOf="parent" />

  <TextView
      android:id="@+id/txvResult"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_marginStart="8dp"
      android:layout_marginTop="8dp"
      android:layout_marginEnd="8dp"
      android:layout_marginBottom="8dp"
      android:text="Result"
      android:textSize="17sp"
      android:textStyle="bold"
      app:layout_constraintBottom_toBottomOf="parent"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toBottomOf="@+id/buttonUpload" />
</android.support.constraint.ConstraintLayout>

6. Write a File Provider

In this demo, we will capture image from camera and gallery with the help of FileProvider. I have written a separate article on capturing image from camera/gallery using FileProvider. I would like to suggest Read this article more clarity.

6.1 Go to res => xml => create a new xml file named is file_provider_path.xml and paste that code

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-path
        name="my_images"
        path="Android/data/com.wave.fileuploadservice/files/Pictures" />
    <! – replace com.wave.fileuploadservice with your package name -->
</paths>

6.2 Now open the AndroidManifest.xml and declare file provider inside the application tag

  <provider
      android:name="android.support.v4.content.FileProvider"
      android:authorities="${applicationId}.provider"
      android:exported="false"
      android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_provider_paths" />
  </provider>

6.3 Declare storage and camera permission in manifest

  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
  <uses-permission android:name="android.permission.CAMERA" />
  <uses-permission android:name="android.permission.INTERNET" />
  <uses-feature android:name="android.hardware.camera" />
  <uses-feature android:name="android.hardware.camera.autofocus" />
  <uses-feature android:name="android.hardware.camera.flash" />

7. Finally, Open the Activity (MainActivity) add do below operation

  • We are using Dexter for using permission on run time. So Expose requestStoragePermission() for requesting permission
  • Create methods for preparing intent for camera and gallery names is startCamera() and chooseGallery()
  • Handle callback result in onActivityResult()
  • Register and UnRegister local BroadcastReceiver

Final code of Activity looks like below

package com.wave.fileuploadservice;

import android.Manifest;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.v4.content.FileProvider;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import com.karumi.dexter.Dexter;
import com.karumi.dexter.MultiplePermissionsReport;
import com.karumi.dexter.PermissionToken;
import com.karumi.dexter.listener.PermissionRequest;
import com.karumi.dexter.listener.multi.MultiplePermissionsListener;
import java.io.File;
import java.io.IOException;
import java.util.Calendar;
import java.util.List;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
  static final int REQUEST_TAKE_PHOTO = 101;
  static final int REQUEST_GALLERY_PHOTO = 102;
  File mPhotoFile;
  ImageView ivDisplayImage;
  Button buttonUpload;
  TextView tvSelectedFilePath;
  ImageView ivSelectImage;
  TextView txvResult;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    ivDisplayImage = findViewById(R.id.ivDisplayImage);
    buttonUpload = findViewById(R.id.buttonUpload);
    tvSelectedFilePath = findViewById(R.id.tvSelectedFilePath);
    ivSelectImage = findViewById(R.id.imageView2);
    txvResult = findViewById(R.id.txvResult);
    buttonUpload.setOnClickListener(this);
    ivSelectImage.setOnClickListener(this);
  }

  @Override
  public void onClick(View v) {
    switch (v.getId()) {
      case R.id.buttonUpload:
        if (tvSelectedFilePath.getText().toString().isEmpty()) {
          Toast.makeText(this, "Select file first", Toast.LENGTH_LONG).show();
          return;
        }
        Intent mIntent = new Intent(this, FileUploadService.class);
        mIntent.putExtra("mFilePath", tvSelectedFilePath.getText().toString());
        FileUploadService.enqueueWork(this, mIntent);
        break;
      case R.id.imageView2:
        selectImage();
        break;
    }
  }

  /**
   * Alert dialog for capture or select from galley
   */
  private void selectImage() {
    final CharSequence[] items = {
        "Take Photo", "Choose from Library",
        "Cancel"
    };
    AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
    builder.setItems(items, (dialog, item) -> {
      if (items[item].equals("Take Photo")) {
        requestStoragePermission(true);
      } else if (items[item].equals("Choose from Library")) {
        requestStoragePermission(false);
      } else if (items[item].equals("Cancel")) {
        dialog.dismiss();
      }
    });
    builder.show();
  }

  /**
   * Requesting multiple permissions (storage and camera) at once
   * This uses multiple permission model from dexter
   * On permanent denial opens settings dialog
   */
  private void requestStoragePermission(boolean isCamera) {
    Dexter.withActivity(this)
        .withPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA)
        .withListener(new MultiplePermissionsListener() {
          @Override
          public void onPermissionsChecked(MultiplePermissionsReport report) {
            // check if all permissions are granted
            if (report.areAllPermissionsGranted()) {
              if (isCamera) {
                startCamera();
              } else {
                chooseGallery();
              }
            }
            // check for permanent denial of any permission
            if (report.isAnyPermissionPermanentlyDenied()) {
              // show alert dialog navigating to Settings
              chooseGallery();
            }
          }

          @Override
          public void onPermissionRationaleShouldBeShown(List<PermissionRequest> permissions,
              PermissionToken token) {
            token.continuePermissionRequest();
          }
        })
        .withErrorListener(
            error -> Toast.makeText(getApplicationContext(), "Error occurred! ", Toast.LENGTH_SHORT)
                .show())
        .onSameThread()
        .check();
  }

  public void startCamera() {
    mPhotoFile = newFile();
    Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
      if (mPhotoFile != null) {
        Uri photoURI = FileProvider.getUriForFile(this,
            BuildConfig.APPLICATION_ID + ".provider", mPhotoFile);
        takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
        startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
      }
    }
  }

  public void chooseGallery() {
    Intent pickPhoto = new Intent(Intent.ACTION_PICK,
        MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
    pickPhoto.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    startActivityForResult(pickPhoto, REQUEST_GALLERY_PHOTO);
  }

  @Override
  protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (resultCode == RESULT_OK) {
      if (requestCode == REQUEST_TAKE_PHOTO) {
        tvSelectedFilePath.setText(mPhotoFile.getAbsolutePath());
        Glide.with(MainActivity.this)
            .load(mPhotoFile)
            .apply(new RequestOptions().centerCrop().circleCrop())
            .into(ivDisplayImage);
      } else if (requestCode == REQUEST_GALLERY_PHOTO) {
        Uri selectedImage = data.getData();
        tvSelectedFilePath.setText(getRealPathFromUri(selectedImage));
        Glide.with(MainActivity.this)
            .load(getRealPathFromUri(selectedImage))
            .apply(new RequestOptions().centerCrop().circleCrop())
            .into(ivDisplayImage);
      }
    }
  }

  public File newFile() {
    Calendar cal = Calendar.getInstance();
    long timeInMillis = cal.getTimeInMillis();
    String mFileName = String.valueOf(timeInMillis) + ".jpeg";
    File mFilePath = getFilePath();
    try {
      File newFile = new File(mFilePath.getAbsolutePath(), mFileName);
      newFile.createNewFile();
      return newFile;
    } catch (IOException e) {
      e.printStackTrace();
    }

    return null;
  }

  public File getFilePath() {
    return getExternalFilesDir(Environment.DIRECTORY_PICTURES);
  }

  public String getRealPathFromUri(Uri contentUri) {
    Cursor cursor = null;
    try {
      String[] proj = { MediaStore.Images.Media.DATA };
      cursor = getContentResolver().query(contentUri, proj, null, null, null);
      assert cursor != null;
      int columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
      cursor.moveToFirst();
      return cursor.getString(columnIndex);
    } finally {
      if (cursor != null) {
        cursor.close();
      }
    }
  }

  @Override
  protected void onResume() {
    super.onResume();

    IntentFilter intentFilter = new IntentFilter("my.own.broadcast");
    LocalBroadcastManager.getInstance(this)
        .registerReceiver(myLocalBroadcastReceiver, intentFilter);
  }

  private BroadcastReceiver myLocalBroadcastReceiver = new BroadcastReceiver() {

    @Override
    public void onReceive(Context context, Intent intent) {

      String result = intent.getStringExtra("result");
      txvResult.setText(result);
    }
  };

  @Override
  protected void onPause() {
    super.onPause();
    LocalBroadcastManager.getInstance(this).unregisterReceiver(myLocalBroadcastReceiver);
  }
}

I’m new in Android so If you have any queries or suggestions, feel free to ask them in the comment section below. Happy Coding ๐Ÿ™‚

Download Sample Project- Upload Files to Server using Service

In the previous tutorials, I was explained how to upload the file to the server using Retrofit and RxJava in Android. Most of the people were appreciated that article and request to write an article on display ProgressBar in head-up notification while file uploading to the server. So, Now this article I’m going to explain, how to upload the file to the server with Notification ProgressBar.

As you know the previous article was on File Uploading with Retrofit. So I carried forward previous source code and focus on explaining how to display in progress bar notification while file uploading? So I have recommended my previous article here.

Objective

  • Get an image from camera/gallery
  • While uploading show progress bar in notification bar
  • If due to some network failure notify the user in giving to action button in Notification Bar RETRY or CANCEL
  • In case user hits the retry button the file upload request again lineup.
  • If hit cancels action button then cancel the request and clear the notification.

This article is outdated for this solution. Read our new article is upload manager


1. Add dependency for using EventBus

We are going to use EventBus for simplifies the communication between components. so open build.gradle and add below dependency

implementation 'org.greenrobot:eventbus:3.1.1'

2. Register/UnRegister EventBus Receiver

Open Activity an register EventBus receiver in onCreate methods using below code

EventBus.getDefault().register(this);

And unregister using this

  @Override
    protected void onDestroy() {
        super.onDestroy();
        EventBus.getDefault().unregister(this);
    }

3. Create a Job for Event Bus

Go src folder and create a new class with OnReceiverEvent,java name just like getter and setter

package com.androidwave.fileupload.receiver;

/**
 * Created on : Jan 11, 2019
 */
public class OnReceiverEvent {
  private String mFilePath;

  public OnReceiverEvent(String filePath) {
    this.mFilePath = filePath;
  }

  public String getFilePath() {
    return mFilePath;
  }
}

4. Post job for file uploading using EventBus

Create a new object of OnReceiverEvent and pass file path in the constructor. For now, the object is holding the current file path. Furthermore using EventBus post a job so It notifies all subscribers.

On upload button OnClickListner() post the job like

  @OnClick({ R.id.upload_file_progress })
  public void onViewClicked(View view) {
    switch (view.getId()) {
      case R.id.upload_file_progress:
        EventBus.getDefault().post(new OnReceiverEvent(mImagePresenter.getImage()));
      default:
        break;
    }
  }

5. Now prepare subscribers using annotate for listening OnReceiverEvent

  @Subscribe
  public void onEvent(OnReceiverEvent event) {
  }

6. Create an ongoing notification with progress bar

  @Subscribe
  public void onEvent(OnReceiverEvent event) {
    notificationId = (int) System.currentTimeMillis();
    Context mContext = MainActivity.this;
    Intent resultIntent = new Intent();
    PendingIntent resultPendingIntent = PendingIntent.getActivity(mContext,
        0 /* Request code */, resultIntent,
        PendingIntent.FLAG_UPDATE_CURRENT);

    mBuilder = new NotificationCompat.Builder(mContext, NOTIFICATION_CHANNEL_ID);
    mBuilder.setSmallIcon(R.drawable.ic_stat_notification);
    mBuilder.setColor(ContextCompat.getColor(mContext, R.color.colorPrimary));
    mBuilder.setContentTitle(getString(R.string.uploading))
        .setOngoing(true)
        .setContentText(getString(R.string.in_progress))
        .setContentIntent(resultPendingIntent)
        .setPriority(NotificationCompat.PRIORITY_HIGH);

    mBuilder.setSound(null);
    mBuilder.setVibrate(new long[] { 0L });
    mBuilder.build().flags |= Notification.FLAG_ONGOING_EVENT;
    mBuilder.setWhen(System.currentTimeMillis());
    mNotificationManager =
        (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
      int importance = NotificationManager.IMPORTANCE_HIGH;
      NotificationChannel notificationChannel =
          new NotificationChannel(NOTIFICATION_CHANNEL_ID, NOTIFICATION_CHANNEL_NAME, importance);
      notificationChannel.setDescription("no sound");
      notificationChannel.setSound(null, null);
      notificationChannel.enableLights(false);
      notificationChannel.enableVibration(false);
      mBuilder.setChannelId(NOTIFICATION_CHANNEL_ID);
      mNotificationManager.createNotificationChannel(notificationChannel);
    }
    mBuilder.setProgress(100, 0, false);
    mNotificationManager.notify(notificationId, mBuilder.build());
  }

7. Now Call onFileSelected() on FileUploadPresenter that upload the file to the server

 mUploaderPresenter.onFileSelected(event.getFilePath(), "androidwave", "info@androidwave.com");

As previous example we implemented FileUploaderContract.View in MainActivity, So view have three methods

  1. void setUploadProgress(int progress) Notify progress during file upload
  2. void uploadCompleted() – Call when file upload operation completed
  3. void showErrorMessage(String message) – Call when some error occurred during file upload
7.2 Notify progress during file upload
  @Override
  public void setUploadProgress(int progress) {
    txtProgress.setText("Uploading ..." + String.valueOf(progress));
    mBuilder.setProgress(PROGRESS_MAX, progress, false);
    mNotificationManager.notify(notificationId, mBuilder.build());
    if (progress == 100) {
      mBuilder.setProgress(0, 0, false);
      mBuilder.setContentText(getString(R.string.message_file_uploaded));
    }
  }
7.2 When File Upload Successfully then update the notification
  @Override
  public void uploadCompleted() {
    Toast.makeText(getApplicationContext(), getString(R.string.file_upload_successful),
        Toast.LENGTH_SHORT).show();
    Intent resultIntent = new Intent(MainActivity.this, MainActivity.class);
    updateNotification(getString(R.string.message_upload_success),
        getString(R.string.message_file_uploaded), resultIntent, notificationId);
  }
7.3 When some error occurred during file upload
  @Override
  public void showErrorMessage(String message) {
    Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
    Intent resultIntent = new Intent();
    retryNotification(getString(R.string.error_upload_falied),
        getString(R.string.messge_upload_failed), resultIntent, notificationId);
  }

8. Create retry notification with action button

During file upload operation is not get succeed then generate a notification with action button

  /**
   * Create and push the notification
   */
  public void retryNotification(String title, String message, Intent resultIntent,
      int notificationId) {
    PendingIntent resultPendingIntent = PendingIntent.getActivity(MainActivity.this,
        0 /* Request code */, resultIntent,
        PendingIntent.FLAG_UPDATE_CURRENT);
    mBuilder = new NotificationCompat.Builder(MainActivity.this, NOTIFICATION_CHANNEL_ID);
    mBuilder.setSmallIcon(R.drawable.ic_stat_notification);
    mBuilder.setColor(ContextCompat.getColor(MainActivity.this, R.color.colorPrimary));
    mBuilder.setContentTitle(title)
        .setContentText(message)
        .setOngoing(true)
        .setContentIntent(resultPendingIntent)
        .setDefaults(NotificationCompat.DEFAULT_ALL)
        .setPriority(NotificationCompat.PRIORITY_HIGH);

    mBuilder.setVibrate(new long[] { 0L });
    mBuilder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
    mNotificationManager =
        (NotificationManager) MainActivity.this.getSystemService(Context.NOTIFICATION_SERVICE);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
      int importance = NotificationManager.IMPORTANCE_HIGH;
      NotificationChannel notificationChannel =
          new NotificationChannel(NOTIFICATION_CHANNEL_ID, NOTIFICATION_CHANNEL_NAME, importance);
      notificationChannel.enableLights(false);
      notificationChannel.enableVibration(false);
      mBuilder.setChannelId(NOTIFICATION_CHANNEL_ID);
      mNotificationManager.createNotificationChannel(notificationChannel);
    }

    Intent retryIntent = new Intent(MainActivity.this, NotificationActionReceiver.class);
    retryIntent.putExtra("notificationId", notificationId);
    retryIntent.putExtra("file_path", mImagePresenter.getImage());
    retryIntent.setAction(ACTION_RETRY);

    Intent clearIntent = new Intent(MainActivity.this, NotificationActionReceiver.class);
    clearIntent.putExtra("notificationId", notificationId);
    clearIntent.putExtra("file_path", mImagePresenter.getImage());
    clearIntent.setAction(ACTION_CLEAR);

    PendingIntent retryPendingIntent =
        PendingIntent.getBroadcast(MainActivity.this, 0, retryIntent, 0);
    PendingIntent clearPendingIntent =
        PendingIntent.getBroadcast(MainActivity.this, 0, clearIntent, 0);
    mBuilder.addAction(android.R.drawable.ic_menu_revert, getString(R.string.btn_retry_not),
        retryPendingIntent);
    mBuilder.addAction(android.R.drawable.ic_menu_revert, getString(R.string.btn_cancel_not),
        clearPendingIntent);
    assert mNotificationManager != null;
    mNotificationManager.notify(notificationId, mBuilder.build());
  }

9. Create a Broadcast Receiver for receiving broadcast event

So we are using two action button Retry and Cancel in the notification. To create a broadcast receiver with name NotificationActionReceiver. onReceive() is receive action and we manage to cancel and Retry action

package com.androidwave.fileupload.receiver;

import android.app.NotificationManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

import org.greenrobot.eventbus.EventBus;

import java.util.Objects;

  /**
   * Created on : Jan 11, 2019
   */
  public class NotificationActionReceiver extends BroadcastReceiver {
    private static final String TAG = "NotificationActionRecei";
    public static final String ACTION_RETRY = "com.androidwave.ACTION_RETRY";
    public static final String ACTION_CLEAR = "com.androidwave.ACTION_CLEAR";

    @Override
    public void onReceive(Context context, Intent intent) {
      int notificationId = intent.getIntExtra("notificationId", 0);
      String mFilePath = intent.getStringExtra("file_path");
      NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
      switch (Objects.requireNonNull(intent.getAction())) {
        case ACTION_RETRY:
          manager.cancel(notificationId);
          EventBus.getDefault().post(new OnRetryReceiverEvent(mFilePath));
          break;
        case ACTION_CLEAR:
          manager.cancel(notificationId);
          break;
        default:
          break;
      }


    }
  }

10. Create a class OnRetryReceiverEvent class for retry job

package com.androidwave.fileupload.receiver;

/**
 * Created on : Jan 11, 2019
 */
public class OnRetryReceiverEvent {
  private String mFilePath;

  public OnRetryReceiverEvent(String filePath) {
    this.mFilePath = filePath;
  }

  public String getFilePath() {
    return mFilePath;
  }
}

11. Now register and unregister receiver in MainActivity

Open Activity and register receiver in onCreate()

  mActionReceiver = new NotificationActionReceiver();
  IntentFilter filterRetry = new IntentFilter();
        filterRetry.addAction(ACTION_RETRY);
        filterRetry.addAction(ACTION_CLEAR);
  registerReceiver(mActionReceiver, filterRetry);

In onDestroy() unregister receiver

  @Override
  protected void onDestroy() {
    super.onDestroy();
    unregisterReceiver(mActionReceiver);
  }

Finally, MainActivity looks like

package com.androidwave.fileupload;

import android.Manifest;
import android.app.AlertDialog;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.NotificationCompat;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.FileProvider;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import com.androidwave.fileupload.network.FileUploaderContract;
import com.androidwave.fileupload.network.FileUploaderModel;
import com.androidwave.fileupload.network.FileUploaderPresenter;
import com.androidwave.fileupload.network.ServiceGenerator;
import com.androidwave.fileupload.picker.ImageContract;
import com.androidwave.fileupload.picker.ImagePresenter;
import com.androidwave.fileupload.receiver.NotificationActionReceiver;
import com.androidwave.fileupload.receiver.OnReceiverEvent;
import com.androidwave.fileupload.receiver.OnRetryReceiverEvent;
import com.androidwave.fileupload.utils.FileCompressor;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import com.karumi.dexter.Dexter;
import com.karumi.dexter.MultiplePermissionsReport;
import com.karumi.dexter.PermissionToken;
import com.karumi.dexter.listener.PermissionRequest;
import com.karumi.dexter.listener.multi.MultiplePermissionsListener;
import java.io.File;
import java.io.IOException;
import java.util.Calendar;
import java.util.List;
import java.util.Objects;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;

import static com.androidwave.fileupload.receiver.NotificationActionReceiver.ACTION_CLEAR;
import static com.androidwave.fileupload.receiver.NotificationActionReceiver.ACTION_RETRY;

public class MainActivity extends AppCompatActivity
    implements ImageContract.View, FileUploaderContract.View {

  static final int REQUEST_TAKE_PHOTO = 1001;
  static final int REQUEST_GALLERY_PHOTO = 1002;
  private static final int PROGRESS_MAX = 100;
  static String[] permissions =
      new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA };
  @BindView(R.id.header_cover_image)
  ImageView headerCoverImage;
  @BindView(R.id.user_profile_photo)
  ImageButton userProfilePhoto;
  @BindView(R.id.user_profile_name)
  TextView userProfileName;
  @BindView(R.id.user_profile_short_bio)
  TextView userProfileShortBio;
  @BindView(R.id.profile_layout)
  RelativeLayout profileLayout;
  @BindView(R.id.textViewProgress)
  TextView txtProgress;
  @BindView(R.id.upload_file_progress)
  Button uploadFileProgress;
  @BindView(R.id.btn_upload_file_without_progress)
  Button btnUploadFileWithoutProgress;

  private ImagePresenter mImagePresenter;
  private FileUploaderPresenter mUploaderPresenter;
  private FileCompressor mCompressor;
  File mPhotoFile;

  private NotificationManager mNotificationManager;
  private NotificationCompat.Builder mBuilder;
  int notificationId;

  BroadcastReceiver mActionReceiver;
  public static final String LINK_TYPE = "link_type";
  public static final String LINK_ID = "link_id";

  public static final String NOTIFICATION_CHANNEL_ID = "androidwave_1002";
  public static final String NOTIFICATION_CHANNEL_NAME = "androidwave";

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    ButterKnife.bind(this);
    mImagePresenter = new ImagePresenter(this);
    mUploaderPresenter =
        new FileUploaderPresenter(this, new FileUploaderModel(ServiceGenerator.createService()));
    mCompressor = new FileCompressor(this);
    EventBus.getDefault().register(this);
    mActionReceiver = new NotificationActionReceiver();
    IntentFilter filterRetry = new IntentFilter();
    filterRetry.addAction(ACTION_RETRY);
    filterRetry.addAction(ACTION_CLEAR);
    registerReceiver(mActionReceiver, filterRetry);
  }

  @Override
  public boolean checkPermission() {
    for (String mPermission : permissions) {
      int result = ActivityCompat.checkSelfPermission(this, mPermission);
      if (result == PackageManager.PERMISSION_DENIED) return false;
    }
    return true;
  }

  @Override
  public void showPermissionDialog(boolean isGallery) {
    Dexter.withActivity(this).withPermissions(permissions)
        .withListener(new MultiplePermissionsListener() {
          @Override
          public void onPermissionsChecked(MultiplePermissionsReport report) {
            // check if all permissions are granted
            if (report.areAllPermissionsGranted()) {
              if (isGallery) {
                mImagePresenter.chooseGalleryClick();
              } else {
                mImagePresenter.cameraClick();
              }
            }
            // check for permanent denial of any permission
            if (report.isAnyPermissionPermanentlyDenied()) {
              // show alert dialog navigating to Settings
              showSettingsDialog();
            }
          }

          @Override
          public void onPermissionRationaleShouldBeShown(List<PermissionRequest> permissions,
              PermissionToken token) {
            token.continuePermissionRequest();
          }
        }).withErrorListener(error -> showErrorDialog())
        .onSameThread()
        .check();
  }

  @Override
  public File getFilePath() {
    return getExternalFilesDir(Environment.DIRECTORY_PICTURES);
  }

  @Override
  public void openSettings() {

  }

  @Override
  public void startCamera(File file) {
    Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
      if (file != null) {
        Uri mPhotoURI = FileProvider.getUriForFile(this,
            BuildConfig.APPLICATION_ID + ".provider", file);
        takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, mPhotoURI);
        mPhotoFile = file;
        startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
      }
    }
  }

  @Override
  public void chooseGallery() {
    Intent pickPhoto = new Intent(Intent.ACTION_PICK,
        MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
    pickPhoto.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    startActivityForResult(pickPhoto, REQUEST_GALLERY_PHOTO);
  }

  @Override
  protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (resultCode == RESULT_OK) {
      if (requestCode == REQUEST_TAKE_PHOTO) {
        try {
          File resultedFile = mCompressor.compressToFile(mPhotoFile);
          mImagePresenter.saveImage(resultedFile.getPath());
          mImagePresenter.showPreview(resultedFile);
        } catch (IOException e) {
          e.printStackTrace();
        }
      } else if (requestCode == REQUEST_GALLERY_PHOTO) {
        Uri selectedImage = data.getData();
        try {
          File resultedFile = mCompressor.compressToFile(
              new File(Objects.requireNonNull(getRealPathFromUri(selectedImage))));
          mImagePresenter.saveImage(resultedFile.getPath());
          mImagePresenter.showPreview(resultedFile);
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
    }
  }

  @Override
  public File newFile() {
    Calendar cal = Calendar.getInstance();
    long timeInMillis = cal.getTimeInMillis();
    String mFileName = String.valueOf(timeInMillis) + ".jpeg";
    File mFilePath = getFilePath();
    try {
      File newFile = new File(mFilePath.getAbsolutePath(), mFileName);
      newFile.createNewFile();
      return newFile;
    } catch (IOException e) {
      e.printStackTrace();
    }

    return null;
  }

  @Override
  public void showErrorDialog() {
    Toast.makeText(getApplicationContext(), getString(R.string.error_message), Toast.LENGTH_SHORT)
        .show();
  }

  @Override
  public void displayImagePreview(File mFile) {
    Glide.with(MainActivity.this)
        .load(mFile)
        .apply(new RequestOptions().centerCrop().circleCrop().placeholder(R.drawable.user))
        .into(userProfilePhoto);
  }

  @Override
  public String getRealPathFromUri(Uri contentUri) {
    Cursor cursor = null;
    try {
      String[] proj = { MediaStore.Images.Media.DATA };
      cursor = getContentResolver().query(contentUri, proj, null, null, null);
      assert cursor != null;
      int columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
      cursor.moveToFirst();
      return cursor.getString(columnIndex);
    } finally {
      if (cursor != null) {
        cursor.close();
      }
    }
  }

  public void showSettingsDialog() {
    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setTitle(getString(R.string.message_need_permission));
    builder.setMessage(getString(R.string.message_grant_permission));
    builder.setPositiveButton(getString(R.string.label_setting), (dialog, which) -> {
      dialog.cancel();
      openSettings();
    });
    builder.setNegativeButton(getString(R.string.cancel), (dialog, which) -> dialog.cancel());
    builder.show();
  }

  @Override
  public void showErrorMessage(String message) {
    Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
    Intent resultIntent = new Intent();
    retryNotification(getString(R.string.error_upload_falied),
        getString(R.string.messge_upload_failed), resultIntent, notificationId);
  }

  @Override
  public void uploadCompleted() {
    Toast.makeText(getApplicationContext(), getString(R.string.file_upload_successful),
        Toast.LENGTH_SHORT).show();
    Intent resultIntent = new Intent(MainActivity.this, MainActivity.class);
    updateNotification(getString(R.string.message_upload_success),
        getString(R.string.message_file_uploaded), resultIntent, notificationId);
  }

  @Override
  public void setUploadProgress(int progress) {
    txtProgress.setText("Uploading ..." + String.valueOf(progress));
    mBuilder.setProgress(PROGRESS_MAX, progress, false);
    mNotificationManager.notify(notificationId, mBuilder.build());
    if (progress == 100) {
      mBuilder.setProgress(0, 0, false);
      mBuilder.setContentText(getString(R.string.message_file_uploaded));
    }
  }

  @OnClick({ R.id.user_profile_photo, R.id.upload_file_progress })
  public void onViewClicked(View view) {
    switch (view.getId()) {
      case R.id.user_profile_photo:
        selectImage();
        break;
      case R.id.upload_file_progress:
        EventBus.getDefault().post(new OnReceiverEvent(mImagePresenter.getImage()));
        ;
      default:
        break;
    }
  }

  private void selectImage() {
    txtProgress.setText("");
    final CharSequence[] items = {
        getString(R.string.take_photo), getString(R.string.choose_gallery),
        getString(R.string.cancel)
    };
    AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
    builder.setItems(items, (dialog, item) -> {
      if (items[item].equals("Capture Photo")) {
        mImagePresenter.cameraClick();
      } else if (items[item].equals("Choose from Library")) {
        mImagePresenter.chooseGalleryClick();
      } else if (items[item].equals("Cancel")) {
        dialog.dismiss();
      }
    });
    builder.show();
  }

  @Subscribe
  public void onEvent(OnReceiverEvent event) {
    notificationId = (int) System.currentTimeMillis();
    Context mContext = MainActivity.this;
    Intent resultIntent = new Intent();
    PendingIntent resultPendingIntent = PendingIntent.getActivity(mContext,
        0 /* Request code */, resultIntent,
        PendingIntent.FLAG_UPDATE_CURRENT);

    mBuilder = new NotificationCompat.Builder(mContext, NOTIFICATION_CHANNEL_ID);
    mBuilder.setSmallIcon(R.drawable.ic_stat_notification);
    mBuilder.setColor(ContextCompat.getColor(mContext, R.color.colorPrimary));
    mBuilder.setContentTitle(getString(R.string.uploading))
        .setOngoing(true)
        .setContentText(getString(R.string.in_progress))
        .setContentIntent(resultPendingIntent)
        .setPriority(NotificationCompat.PRIORITY_HIGH);

    mBuilder.setSound(null);
    mBuilder.setVibrate(new long[] { 0L });
    mBuilder.build().flags |= Notification.FLAG_ONGOING_EVENT;
    mBuilder.setWhen(System.currentTimeMillis());
    mNotificationManager =
        (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
      int importance = NotificationManager.IMPORTANCE_HIGH;
      NotificationChannel notificationChannel =
          new NotificationChannel(NOTIFICATION_CHANNEL_ID, NOTIFICATION_CHANNEL_NAME, importance);
      notificationChannel.setDescription("no sound");
      notificationChannel.setSound(null, null);
      notificationChannel.enableLights(false);
      notificationChannel.enableVibration(false);
      mBuilder.setChannelId(NOTIFICATION_CHANNEL_ID);
      mNotificationManager.createNotificationChannel(notificationChannel);
    }
    mBuilder.setProgress(100, 0, false);
    mNotificationManager.notify(notificationId, mBuilder.build());
    mUploaderPresenter.onFileSelected(event.getFilePath(), "androidwave", "info@androidwave.com");
  }

  /**
   * Create and push the notification
   */
  public void retryNotification(String title, String message, Intent resultIntent,
      int notificationId) {
    PendingIntent resultPendingIntent = PendingIntent.getActivity(MainActivity.this,
        0 /* Request code */, resultIntent,
        PendingIntent.FLAG_UPDATE_CURRENT);
    mBuilder = new NotificationCompat.Builder(MainActivity.this, NOTIFICATION_CHANNEL_ID);
    mBuilder.setSmallIcon(R.drawable.ic_stat_notification);
    mBuilder.setColor(ContextCompat.getColor(MainActivity.this, R.color.colorPrimary));
    mBuilder.setContentTitle(title)
        .setContentText(message)
        .setOngoing(true)
        .setContentIntent(resultPendingIntent)
        .setDefaults(NotificationCompat.DEFAULT_ALL)
        .setPriority(NotificationCompat.PRIORITY_HIGH);

    mBuilder.setVibrate(new long[] { 0L });
    mBuilder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
    mNotificationManager =
        (NotificationManager) MainActivity.this.getSystemService(Context.NOTIFICATION_SERVICE);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
      int importance = NotificationManager.IMPORTANCE_HIGH;
      NotificationChannel notificationChannel =
          new NotificationChannel(NOTIFICATION_CHANNEL_ID, NOTIFICATION_CHANNEL_NAME, importance);
      notificationChannel.enableLights(false);
      notificationChannel.enableVibration(false);
      mBuilder.setChannelId(NOTIFICATION_CHANNEL_ID);
      mNotificationManager.createNotificationChannel(notificationChannel);
    }

    Intent retryIntent = new Intent(MainActivity.this, NotificationActionReceiver.class);
    retryIntent.putExtra("notificationId", notificationId);
    retryIntent.putExtra("file_path", mImagePresenter.getImage());
    retryIntent.setAction(ACTION_RETRY);

    Intent clearIntent = new Intent(MainActivity.this, NotificationActionReceiver.class);
    clearIntent.putExtra("notificationId", notificationId);
    clearIntent.putExtra("file_path", mImagePresenter.getImage());
    clearIntent.setAction(ACTION_CLEAR);

    PendingIntent retryPendingIntent =
        PendingIntent.getBroadcast(MainActivity.this, 0, retryIntent, 0);
    PendingIntent clearPendingIntent =
        PendingIntent.getBroadcast(MainActivity.this, 0, clearIntent, 0);
    mBuilder.addAction(android.R.drawable.ic_menu_revert, getString(R.string.btn_retry_not),
        retryPendingIntent);
    mBuilder.addAction(android.R.drawable.ic_menu_revert, getString(R.string.btn_cancel_not),
        clearPendingIntent);
    assert mNotificationManager != null;
    mNotificationManager.notify(notificationId, mBuilder.build());
  }

  @Subscribe
  public void onRetryEventReceived(OnRetryReceiverEvent event) {
    NotificationManager notifManager =
        (NotificationManager) MainActivity.this.getSystemService(Context.NOTIFICATION_SERVICE);
    notifManager.cancel(notificationId);
    EventBus.getDefault().post(new OnReceiverEvent(event.getFilePath()));
  }

  /**
   * Create and push the notification
   */
  public void updateNotification(String title, String message, Intent resultIntent,
      int notificationId) {
    Context mContext = MainActivity.this;
    PendingIntent resultPendingIntent = PendingIntent.getActivity(mContext,
        0 /* Request code */, resultIntent,
        PendingIntent.FLAG_UPDATE_CURRENT);
    mBuilder = new NotificationCompat.Builder(mContext, NOTIFICATION_CHANNEL_ID);
    mBuilder.setSmallIcon(R.drawable.ic_stat_notification);
    mBuilder.setColor(ContextCompat.getColor(mContext, R.color.design_default_color_primary));
    mBuilder.setContentTitle(title)
        .setContentText(message)
        .setAutoCancel(true)
        .setContentIntent(resultPendingIntent).setDefaults(NotificationCompat.DEFAULT_ALL)
        .setPriority(NotificationCompat.PRIORITY_HIGH);
    ;
    mBuilder.setVibrate(new long[] { 0L });
    mBuilder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
    mNotificationManager =
        (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
      int importance = NotificationManager.IMPORTANCE_HIGH;
      NotificationChannel notificationChannel =
          new NotificationChannel(NOTIFICATION_CHANNEL_ID, NOTIFICATION_CHANNEL_NAME, importance);
      notificationChannel.enableLights(false);
      notificationChannel.enableVibration(false);
      mBuilder.setChannelId(NOTIFICATION_CHANNEL_ID);
      mNotificationManager.createNotificationChannel(notificationChannel);
    }
    assert mNotificationManager != null;
    mNotificationManager.notify(notificationId, mBuilder.build());
  }

  @Override
  protected void onDestroy() {
    super.onDestroy();
    unregisterReceiver(mActionReceiver);
    EventBus.getDefault().unregister(this);
  }
}
Download Sample Project – Display ProgressBar in Notification while Uploading Image