mirror of https://github.com/ThmmyNoLife/mTHMMY
Ezerous
7 years ago
22 changed files with 338 additions and 410 deletions
@ -0,0 +1,73 @@ |
|||
package gr.thmmy.mthmmy.services; |
|||
|
|||
import android.app.DownloadManager; |
|||
import android.content.Context; |
|||
import android.net.Uri; |
|||
import android.os.Environment; |
|||
import android.widget.Toast; |
|||
|
|||
import java.io.File; |
|||
|
|||
import gr.thmmy.mthmmy.base.BaseApplication; |
|||
import gr.thmmy.mthmmy.model.ThmmyFile; |
|||
import okhttp3.Cookie; |
|||
import timber.log.Timber; |
|||
|
|||
import static gr.thmmy.mthmmy.utils.FileUtils.getMimeType; |
|||
|
|||
/** |
|||
* Not an actual service, but simply a helper class that adds a download to the queue of Android's |
|||
* DownloadManager system service. |
|||
*/ |
|||
public class DownloadHelper { |
|||
public static final File SAVE_DIR = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS); |
|||
|
|||
public static void enqueueDownload(ThmmyFile thmmyFile){ |
|||
Context applicationContext = BaseApplication.getInstance().getApplicationContext(); |
|||
Toast.makeText(applicationContext, "Download started!", Toast.LENGTH_SHORT).show(); |
|||
|
|||
try { |
|||
String fileName = renameFileIfExists(thmmyFile.getFilename()); |
|||
Uri downloadURI = Uri.parse(thmmyFile.getFileUrl().toString()); |
|||
|
|||
DownloadManager downloadManager = (DownloadManager)applicationContext.getSystemService(Context.DOWNLOAD_SERVICE); |
|||
DownloadManager.Request request = new DownloadManager.Request(downloadURI); |
|||
|
|||
Cookie thmmyCookie = BaseApplication.getInstance().getSessionManager().getThmmyCookie(); |
|||
request.addRequestHeader("Cookie", thmmyCookie.name() + "=" + thmmyCookie.value()); |
|||
request.setTitle(fileName); |
|||
request.setMimeType(getMimeType(fileName)); |
|||
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); |
|||
request.setDestinationInExternalPublicDir(SAVE_DIR.getName(), fileName); |
|||
request.allowScanningByMediaScanner(); |
|||
|
|||
downloadManager.enqueue(request); |
|||
} catch (Exception e) { |
|||
Toast.makeText(applicationContext, "Download failed...", Toast.LENGTH_SHORT).show(); |
|||
Timber.e(e, "Exception while enqueuing download."); |
|||
} |
|||
} |
|||
|
|||
private static String renameFileIfExists(String originalFileName) { |
|||
final String dirPath = SAVE_DIR.getAbsolutePath(); |
|||
File file = new File(dirPath, originalFileName); |
|||
|
|||
String nameFormat; |
|||
String[] tokens = originalFileName.split("\\.(?=[^.]+$)"); |
|||
|
|||
if (tokens.length != 2) { |
|||
Timber.w("Couldn't get file extension..."); |
|||
nameFormat = originalFileName + "(%d)"; |
|||
} else |
|||
nameFormat = tokens[0] + "-%d." + tokens[1]; |
|||
|
|||
for (int i = 1; ; i++) { |
|||
if (!file.isFile()) |
|||
break; |
|||
|
|||
file = new File(dirPath, String.format(nameFormat, i)); |
|||
} |
|||
|
|||
return file.getName(); |
|||
} |
|||
} |
@ -1,88 +0,0 @@ |
|||
package gr.thmmy.mthmmy.services.downloads; |
|||
|
|||
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.net.Uri; |
|||
import android.os.Build; |
|||
import android.os.Bundle; |
|||
import android.support.v4.app.NotificationCompat; |
|||
import android.webkit.MimeTypeMap; |
|||
|
|||
import java.io.File; |
|||
|
|||
import timber.log.Timber; |
|||
|
|||
import static gr.thmmy.mthmmy.services.downloads.DownloadsService.ACTION_DOWNLOAD; |
|||
import static gr.thmmy.mthmmy.services.downloads.DownloadsService.COMPLETED; |
|||
import static gr.thmmy.mthmmy.services.downloads.DownloadsService.EXTRA_DOWNLOAD_ID; |
|||
import static gr.thmmy.mthmmy.services.downloads.DownloadsService.EXTRA_DOWNLOAD_STATE; |
|||
import static gr.thmmy.mthmmy.services.downloads.DownloadsService.EXTRA_FILE_NAME; |
|||
import static gr.thmmy.mthmmy.services.downloads.DownloadsService.EXTRA_NOTIFICATION_TEXT; |
|||
import static gr.thmmy.mthmmy.services.downloads.DownloadsService.EXTRA_NOTIFICATION_TICKER; |
|||
import static gr.thmmy.mthmmy.services.downloads.DownloadsService.EXTRA_NOTIFICATION_TITLE; |
|||
import static gr.thmmy.mthmmy.services.downloads.DownloadsService.SAVE_DIR; |
|||
import static gr.thmmy.mthmmy.services.downloads.DownloadsService.STARTED; |
|||
|
|||
public class DownloadsReceiver extends BroadcastReceiver { |
|||
private static final String NOTIFICATION_TAG = "DOWNLOADS"; |
|||
private static final String DOWNLOADS_CHANNEL_ID = "Downloads"; |
|||
private static final String DOWNLOADS_CHANNEL_NAME = "Downloads"; |
|||
|
|||
public DownloadsReceiver() {} |
|||
|
|||
@Override |
|||
public void onReceive(Context context, Intent intent) { |
|||
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context, DOWNLOADS_CHANNEL_ID); |
|||
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); |
|||
|
|||
if (intent.getAction().equals(ACTION_DOWNLOAD)) { |
|||
Bundle extras = intent.getExtras(); |
|||
int id = extras.getInt(EXTRA_DOWNLOAD_ID); |
|||
String state = extras.getString(EXTRA_DOWNLOAD_STATE, "NONE"); |
|||
String title = extras.getString(EXTRA_NOTIFICATION_TITLE); |
|||
String text = extras.getString(EXTRA_NOTIFICATION_TEXT); |
|||
String ticker = extras.getString(EXTRA_NOTIFICATION_TICKER); |
|||
|
|||
notificationBuilder.setContentTitle(title) |
|||
.setContentText(text) |
|||
.setTicker(ticker) |
|||
.setAutoCancel(true); |
|||
|
|||
if (state.equals(STARTED)) |
|||
notificationBuilder.setOngoing(true) |
|||
.setSmallIcon(android.R.drawable.stat_sys_download); |
|||
else if (state.equals(COMPLETED)) { |
|||
String fileName = extras.getString(EXTRA_FILE_NAME, "NONE"); |
|||
|
|||
File file = new File(SAVE_DIR, fileName); |
|||
if (file.exists()) { |
|||
String type = MimeTypeMap.getSingleton().getMimeTypeFromExtension( |
|||
MimeTypeMap.getFileExtensionFromUrl(file.getAbsolutePath())); |
|||
|
|||
|
|||
Intent chooserIntent = new Intent(Intent.ACTION_VIEW); |
|||
chooserIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
|||
chooserIntent.setDataAndType(Uri.fromFile(file), type); |
|||
Intent chooser = Intent.createChooser(chooserIntent, "Open With..."); |
|||
|
|||
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, chooser, PendingIntent.FLAG_CANCEL_CURRENT); |
|||
notificationBuilder.setContentIntent(pendingIntent) |
|||
.setSmallIcon(android.R.drawable.stat_sys_download_done); |
|||
|
|||
} else |
|||
Timber.w("File doesn't exist."); |
|||
} |
|||
|
|||
// Since Android Oreo notification channel is needed.
|
|||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) |
|||
notificationManager.createNotificationChannel(new NotificationChannel(DOWNLOADS_CHANNEL_ID, DOWNLOADS_CHANNEL_NAME, NotificationManager.IMPORTANCE_HIGH)); |
|||
|
|||
notificationManager.notify(NOTIFICATION_TAG, id, notificationBuilder.build()); |
|||
} |
|||
} |
|||
|
|||
} |
@ -1,225 +0,0 @@ |
|||
package gr.thmmy.mthmmy.services.downloads; |
|||
|
|||
import android.app.DownloadManager; |
|||
import android.app.IntentService; |
|||
import android.content.Context; |
|||
import android.content.Intent; |
|||
import android.content.IntentFilter; |
|||
import android.os.Environment; |
|||
import android.support.annotation.NonNull; |
|||
import android.webkit.MimeTypeMap; |
|||
|
|||
import java.io.File; |
|||
import java.io.FileNotFoundException; |
|||
import java.io.IOException; |
|||
|
|||
import gr.thmmy.mthmmy.base.BaseApplication; |
|||
import okhttp3.OkHttpClient; |
|||
import okhttp3.Request; |
|||
import okhttp3.Response; |
|||
import okio.BufferedSink; |
|||
import okio.Okio; |
|||
import timber.log.Timber; |
|||
|
|||
/** |
|||
* An {@link IntentService} subclass for handling asynchronous task requests in |
|||
* a service on a separate handler thread. |
|||
*/ |
|||
public class DownloadsService extends IntentService { |
|||
private static final String TAG = "DownloadsService"; |
|||
private static int sDownloadId = 0; |
|||
|
|||
private DownloadsReceiver receiver; |
|||
|
|||
public static final String SAVE_DIR = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "mthmmy"; |
|||
|
|||
public static final String ACTION_DOWNLOAD = "gr.thmmy.mthmmy.services.action.DOWNLOAD"; |
|||
public static final String EXTRA_DOWNLOAD_URL = "gr.thmmy.mthmmy.services.extra.DOWNLOAD_URL"; |
|||
|
|||
public static final String EXTRA_DOWNLOAD_ID = "gr.thmmy.mthmmy.services.extra.DOWNLOAD_ID"; |
|||
public static final String EXTRA_DOWNLOAD_STATE = "gr.thmmy.mthmmy.services.extra.DOWNLOAD_STATE"; |
|||
public static final String EXTRA_FILE_NAME = "gr.thmmy.mthmmy.services.extra.FILE_NAME"; |
|||
public static final String EXTRA_NOTIFICATION_TITLE = "gr.thmmy.mthmmy.services.extra.NOTIFICATION_TITLE"; |
|||
public static final String EXTRA_NOTIFICATION_TEXT = "gr.thmmy.mthmmy.services.extra.NOTIFICATION_TEXT"; |
|||
public static final String EXTRA_NOTIFICATION_TICKER = "gr.thmmy.mthmmy.services.extra.NOTIFICATION_TICKER"; |
|||
|
|||
public static final String STARTED = "Started"; |
|||
public static final String COMPLETED = "Completed"; |
|||
public static final String FAILED = "Failed"; |
|||
|
|||
|
|||
public DownloadsService() { |
|||
super("DownloadsService"); |
|||
} |
|||
|
|||
@Override |
|||
public void onCreate() { |
|||
super.onCreate(); |
|||
final IntentFilter filter = new IntentFilter(DownloadsService.ACTION_DOWNLOAD); |
|||
receiver = new DownloadsReceiver(); |
|||
registerReceiver(receiver, filter); |
|||
|
|||
} |
|||
|
|||
@Override |
|||
public void onDestroy() { |
|||
super.onDestroy(); |
|||
this.unregisterReceiver(receiver); |
|||
} |
|||
|
|||
/** |
|||
* Starts this service to perform action Download with the given parameters. If |
|||
* the service is already performing a task this action will be queued. |
|||
* |
|||
* @see IntentService |
|||
*/ |
|||
public static void startActionDownload(Context context, String downloadUrl) { |
|||
Intent intent = new Intent(context, DownloadsService.class); |
|||
intent.setAction(ACTION_DOWNLOAD); |
|||
intent.putExtra(EXTRA_DOWNLOAD_URL, downloadUrl); |
|||
context.startService(intent); |
|||
} |
|||
|
|||
@Override |
|||
protected void onHandleIntent(Intent intent) { |
|||
if (intent != null) { |
|||
final String action = intent.getAction(); |
|||
if (ACTION_DOWNLOAD.equals(action)) { |
|||
final String downloadLink = intent.getStringExtra(EXTRA_DOWNLOAD_URL); |
|||
handleActionDownload(downloadLink); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Handle action Foo in the provided background thread with the provided |
|||
* parameters. |
|||
*/ |
|||
private void handleActionDownload(String downloadLink) { |
|||
OkHttpClient client = BaseApplication.getInstance().getClient(); |
|||
BufferedSink sink = null; |
|||
String fileName = "file"; |
|||
|
|||
int downloadId = sDownloadId; |
|||
sDownloadId++; |
|||
|
|||
try { |
|||
Request request = new Request.Builder().url(downloadLink).build(); |
|||
Response response = client.newCall(request).execute(); |
|||
|
|||
String contentDisposition = response.headers("Content-Disposition").toString(); //check if link provides an attachment
|
|||
if (contentDisposition.contains("attachment")) { |
|||
fileName = contentDisposition.split("\"")[1]; |
|||
|
|||
File dirPath = new File(SAVE_DIR); |
|||
if (!dirPath.isDirectory()) { |
|||
if (dirPath.mkdirs()) |
|||
Timber.i("mTHMMY's directory created successfully!"); |
|||
else |
|||
Timber.e("Couldn't create mTHMMY's directory..."); |
|||
} |
|||
|
|||
|
|||
String nameFormat; |
|||
String[] tokens = fileName.split("\\.(?=[^\\.]+$)"); |
|||
|
|||
if (tokens.length != 2) { |
|||
Timber.w("Couldn't get file extension..."); |
|||
nameFormat = fileName + "(%d)"; |
|||
} else |
|||
nameFormat = tokens[0] + "(%d)." + tokens[1]; |
|||
|
|||
|
|||
File file = new File(dirPath, fileName); |
|||
|
|||
for (int i = 1; ; i++) { |
|||
if (!file.exists()) |
|||
break; |
|||
|
|||
file = new File(dirPath, String.format(nameFormat, i)); |
|||
} |
|||
|
|||
fileName = file.getName(); |
|||
|
|||
Timber.v("Started saving file %s", fileName); |
|||
sendNotification(downloadId, STARTED, fileName); |
|||
|
|||
sink = Okio.buffer(Okio.sink(file)); |
|||
sink.writeAll(response.body().source()); |
|||
sink.flush(); |
|||
Timber.i("Download OK!"); |
|||
sendNotification(downloadId, COMPLETED, fileName); |
|||
|
|||
// Register download
|
|||
DownloadManager mManager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE); |
|||
long length = file.length(); |
|||
mManager.addCompletedDownload(fileName, fileName, false, getMimeType(file), SAVE_DIR +File.separator+ fileName, length, false); |
|||
|
|||
} else |
|||
Timber.e("No attachment in response!"); |
|||
} catch (FileNotFoundException e) { |
|||
Timber.i("Download failed..."); |
|||
Timber.e(e, "FileNotFound"); |
|||
sendNotification(downloadId, FAILED, fileName); |
|||
} catch (IOException e) { |
|||
Timber.i("Download failed..."); |
|||
Timber.e(e, "IOException"); |
|||
sendNotification(downloadId, FAILED, fileName); |
|||
} finally { |
|||
if (sink != null) { |
|||
try { |
|||
sink.close(); |
|||
} catch (IOException e) { |
|||
// Ignore - Significant errors should already have been reported
|
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
private void sendNotification(int downloadId, String type, @NonNull String fileName) { |
|||
Intent intent = new Intent(ACTION_DOWNLOAD); |
|||
switch (type) { |
|||
case STARTED: { |
|||
intent.putExtra(EXTRA_NOTIFICATION_TITLE, "\"" + fileName + "\""); |
|||
intent.putExtra(EXTRA_NOTIFICATION_TEXT, "Download Started"); |
|||
intent.putExtra(EXTRA_NOTIFICATION_TICKER, "Downloading..."); |
|||
break; |
|||
} |
|||
case COMPLETED: { |
|||
intent.putExtra(EXTRA_NOTIFICATION_TITLE, "\"" + fileName + "\""); |
|||
intent.putExtra(EXTRA_NOTIFICATION_TEXT, "Download Completed"); |
|||
intent.putExtra(EXTRA_NOTIFICATION_TICKER, "Download Completed"); |
|||
break; |
|||
} |
|||
case FAILED: { |
|||
intent.putExtra(EXTRA_NOTIFICATION_TITLE, "\"" + fileName + "\""); |
|||
intent.putExtra(EXTRA_NOTIFICATION_TEXT, "Download Failed"); |
|||
intent.putExtra(EXTRA_NOTIFICATION_TICKER, "Download Failed"); |
|||
break; |
|||
} |
|||
default: { |
|||
Timber.e("Invalid notification case!"); |
|||
return; |
|||
} |
|||
} |
|||
intent.putExtra(EXTRA_DOWNLOAD_ID, downloadId); |
|||
intent.putExtra(EXTRA_DOWNLOAD_STATE, type); |
|||
intent.putExtra(EXTRA_FILE_NAME, fileName); |
|||
sendBroadcast(intent); |
|||
|
|||
} |
|||
|
|||
@NonNull |
|||
static String getMimeType(@NonNull File file) { |
|||
String type = null; |
|||
final String url = file.toString(); |
|||
final String extension = MimeTypeMap.getFileExtensionFromUrl(url); |
|||
if (extension != null) |
|||
type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension.toLowerCase()); |
|||
if (type == null) |
|||
type = "*/*"; |
|||
|
|||
return type; |
|||
} |
|||
|
|||
} |
@ -0,0 +1,26 @@ |
|||
package gr.thmmy.mthmmy.utils; |
|||
|
|||
import android.support.annotation.NonNull; |
|||
import android.webkit.MimeTypeMap; |
|||
|
|||
import java.io.File; |
|||
|
|||
import static gr.thmmy.mthmmy.services.DownloadHelper.SAVE_DIR; |
|||
|
|||
public class FileUtils { |
|||
@NonNull |
|||
public static String getMimeType(@NonNull String fileName) { |
|||
String type = null; |
|||
final String extension = MimeTypeMap.getFileExtensionFromUrl(fileName); |
|||
if (extension != null) |
|||
type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension.toLowerCase()); |
|||
if (type == null) |
|||
type = "*/*"; |
|||
|
|||
return type; |
|||
} |
|||
|
|||
public static boolean fileNameExists (String fileName) { |
|||
return fileName != null && (new File(SAVE_DIR.getAbsolutePath(), fileName)).isFile(); |
|||
} |
|||
} |
@ -0,0 +1,48 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="match_parent" |
|||
android:orientation="vertical" |
|||
android:background="@color/primary_light" |
|||
android:padding="4dp"> |
|||
|
|||
|
|||
<TextView |
|||
android:id="@+id/downloadPromptTextView" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="wrap_content" |
|||
android:layout_weight="1" |
|||
android:padding="8dp" |
|||
android:textSize="16sp" |
|||
android:textColor="@color/white" /> |
|||
|
|||
<LinearLayout |
|||
android:layout_width="match_parent" |
|||
android:layout_height="wrap_content" |
|||
android:layout_weight="1" |
|||
android:orientation="horizontal"> |
|||
|
|||
<Button |
|||
android:id="@+id/cancel" |
|||
android:layout_width="wrap_content" |
|||
android:layout_height="wrap_content" |
|||
android:layout_weight="1" |
|||
style="?android:attr/borderlessButtonStyle" |
|||
android:text="@string/cancel" /> |
|||
|
|||
<Button |
|||
android:id="@+id/open" |
|||
android:layout_width="wrap_content" |
|||
android:layout_height="wrap_content" |
|||
android:layout_weight="1" |
|||
android:text="@string/open" /> |
|||
|
|||
<Button |
|||
android:id="@+id/download" |
|||
android:layout_width="wrap_content" |
|||
android:layout_height="wrap_content" |
|||
android:layout_weight="1" |
|||
android:text="@string/download" /> |
|||
</LinearLayout> |
|||
|
|||
</LinearLayout> |
@ -1,10 +1,4 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<paths> |
|||
<external-path |
|||
name="my_downloads" |
|||
path="Downloads/"/> |
|||
|
|||
<files-path |
|||
name="my_downloads" |
|||
path="Downloads/"/> |
|||
<external-path name="my_downloads" path="."/> |
|||
</paths> |
Loading…
Reference in new issue