Skip to content

Instantly share code, notes, and snippets.

@rayworks
Last active December 5, 2019 03:31
Show Gist options
  • Save rayworks/69b8bb7720b46baa11ffb18b98161496 to your computer and use it in GitHub Desktop.
Save rayworks/69b8bb7720b46baa11ffb18b98161496 to your computer and use it in GitHub Desktop.
Foreground DownloadService
import android.app.IntentService;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.NotificationCompat;
import android.support.v4.content.FileProvider;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.TimeUnit;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import timber.log.Timber;
import static android.os.Environment.DIRECTORY_DOWNLOADS;
// Usage :
// 1.Add the permission for foreground service
// <!-- OS 9.0+ --> <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
// 2. register it on your manifest
public class FileDownloadService extends IntentService {
private final static String DOWNLOAD_CHANNEL_ID = "download_channel_id";
private final static String DOWNLOAD_CHANNEL_NAME = "download_channel_name";
private final static String DOWNLOAD_CHANNEL_DESC = "download_channel_desc";
public static final String DOWNLOAD_URL = "download_url";
private static final String AUTHORITY = BuildConfig.APPLICATION_ID + ".fileprovider";
private String fileName;
public FileDownloadService() {
super("FileDownloadService");
}
@Override
public void onDestroy() {
super.onDestroy();
}
private void startInstall(@NonNull File file) {
Intent installIntent = new Intent();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
installIntent.setAction(Intent.ACTION_VIEW);
installIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
installIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
// Timber.e(">>> InstallPermission granted : %b", isHasInstallPermissionWithO(context));
Uri contentUri = FileProvider.getUriForFile(getApplicationContext(), AUTHORITY, file);
installIntent.setDataAndType(contentUri, "application/vnd.android.package-archive");
} else {
installIntent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
installIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
// IPackageManager localIPackageManager = IPackageManager.Stub.asInterface(context.getPackageManager());
try {
/*List<ResolveInfo> resolveInfos = getApplicationContext().getPackageManager().queryIntentActivities(installIntent, 0);
ResolveInfo target = null;
for (ResolveInfo ri : resolveInfos) {
ActivityInfo activityInfo = ri.activityInfo;
String activityName = activityInfo.name;
String pkg = activityInfo.packageName;
String appName = activityInfo.applicationInfo.name;
Timber.i(">>> filtered ResolveInfo: activity- %s | appName- %s | pkg - %s", activityName, appName, pkg);
if(pkg != null && pkg.endsWith("packageinstaller")) {
installIntent.setComponent(new ComponentName(pkg, activityName));
break;
}
}*/
Timber.w(">>> intent dumped : %s", installIntent);
// ResolveInfo: activity- com.android.packageinstaller.PackageInstallerActivity | appName- com.android.packageinstaller.InstallerApplication | pkg - com.miui.packageinstaller
startActivity(installIntent);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
if (intent != null) {
String downloadUrl = intent.getStringExtra(DOWNLOAD_URL);
File filesDir = Environment.getExternalStoragePublicDirectory(DIRECTORY_DOWNLOADS); //getApplicationContext().getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS);
if (filesDir == null) {
filesDir = getFilesDir();
} else {
if (!filesDir.exists()) {
filesDir.mkdir();
}
}
int sepPosition = downloadUrl.lastIndexOf("/");
int endPosition = downloadUrl.lastIndexOf(".");
//Uri.fromFile("").getLastPathSegment();
long millis = System.currentTimeMillis();
fileName = downloadUrl.substring(sepPosition + 1, endPosition) + millis + downloadUrl.substring(endPosition);
File out = new File(filesDir, fileName);
Timber.w(">>> File will be put here : %s", out.getAbsolutePath());
startForeground(0xEF, buildNotification());
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.build();
Request request = new Request.Builder().url(downloadUrl).get().build();
InputStream in = null;
BufferedOutputStream bos = null;
try {
Response response = client.newCall(request).execute();
if (response.code() == 200) {
in = response.body().byteStream();
FileOutputStream fos = new FileOutputStream(out);
bos = new BufferedOutputStream(fos);
byte[] buffer = new byte[8192];
int len = 0;
while ((len = in.read(buffer)) >= 0) {
bos.write(buffer, 0, len);
}
bos.flush();
Timber.i(">>> download completed!");
startInstall(out);
} else {
Timber.i(">>> download error: %s", response.message());
}
} catch (IOException e) {
e.printStackTrace();
} finally {
IOUtils.closeSilently(bos);
IOUtils.closeSilently(in);
try {
Thread.sleep(50000);
stopForeground(true);
stopSelf();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
private Notification buildNotification() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel = new NotificationChannel(DOWNLOAD_CHANNEL_ID, DOWNLOAD_CHANNEL_NAME, importance);
channel.setDescription(DOWNLOAD_CHANNEL_DESC);
NotificationManager notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
NotificationCompat.Builder b = new NotificationCompat.Builder(this, DOWNLOAD_CHANNEL_ID);
b.setOngoing(true)
.setContentText(fileName)
.setSmallIcon(android.R.drawable.stat_sys_download)
.setTicker("Downloading...")
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setAutoCancel(true);
return b.build();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment