add Stop action to download notifications

This commit is contained in:
Akinwale Ariwodola 2020-01-20 21:42:25 +01:00
parent ae9364ad7e
commit 8fcf135280
4 changed files with 107 additions and 33 deletions

2
app

@ -1 +1 @@
Subproject commit 32c1770c34ecc5e80c5542aeb64ff11312704cea Subproject commit 46bfbd242a841f770a59ec88f9c7fbd94e5a06da

View file

@ -10,6 +10,7 @@ import android.net.Uri;
import android.os.Build; import android.os.Build;
import androidx.core.app.NotificationCompat; import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat; import androidx.core.app.NotificationManagerCompat;
import androidx.core.content.ContextCompat;
import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactContextBaseJavaModule;
@ -31,6 +32,8 @@ public class DownloadManager {
private List<String> completedDownloads = new ArrayList<String>(); private List<String> completedDownloads = new ArrayList<String>();
private Map<String, String> downloadIdOutpointsMap = new HashMap<String, String>();
// maintain a map of uris to writtenBytes, so that we check if it's changed and don't flood RN with update events every 500ms // maintain a map of uris to writtenBytes, so that we check if it's changed and don't flood RN with update events every 500ms
private Map<String, Double> writtenDownloadBytes = new HashMap<String, Double>(); private Map<String, Double> writtenDownloadBytes = new HashMap<String, Double>();
@ -144,7 +147,15 @@ public class DownloadManager {
} }
} }
public void startDownload(String id, String filename) { private Intent getDeleteDownloadIntent(String uri) {
Intent intent = new Intent();
intent.setAction(LbrynetService.ACTION_DELETE_DOWNLOAD);
intent.putExtra("uri", uri);
intent.putExtra("nativeDelete", true);
return intent;
}
public void startDownload(String id, String filename, String outpoint) {
if (filename == null || filename.trim().length() == 0) { if (filename == null || filename.trim().length() == 0) {
return; return;
} }
@ -152,20 +163,26 @@ public class DownloadManager {
synchronized (this) { synchronized (this) {
if (!isDownloadActive(id)) { if (!isDownloadActive(id)) {
activeDownloads.add(id); activeDownloads.add(id);
downloadIdOutpointsMap.put(id, outpoint);
} }
createNotificationChannel(); createNotificationChannel();
createNotificationGroup(); createNotificationGroup();
PendingIntent stopDownloadIntent = PendingIntent.getBroadcast(context, 0, getDeleteDownloadIntent(id), PendingIntent.FLAG_CANCEL_CURRENT);
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context); NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID); NotificationCompat.Builder builder = new NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID);
// The file URI is used as the unique ID // The file URI is used as the unique ID
builder.setContentIntent(getLaunchPendingIntent(id, context)) builder.setColor(ContextCompat.getColor(context, R.color.lbryGreen))
.setContentIntent(getLaunchPendingIntent(id, context))
.setContentTitle(String.format("Downloading %s", truncateFilename(filename))) .setContentTitle(String.format("Downloading %s", truncateFilename(filename)))
.setGroup(GROUP_DOWNLOADS) .setGroup(GROUP_DOWNLOADS)
.setPriority(NotificationCompat.PRIORITY_LOW) .setPriority(NotificationCompat.PRIORITY_LOW)
.setProgress(MAX_PROGRESS, 0, false) .setProgress(MAX_PROGRESS, 0, false)
.setSmallIcon(android.R.drawable.stat_sys_download); .setSmallIcon(android.R.drawable.stat_sys_download)
.setOngoing(true)
.addAction(android.R.drawable.ic_menu_close_clear_cancel, "Stop", stopDownloadIntent);
int notificationId = getNotificationId(id); int notificationId = getNotificationId(id);
downloadIdNotificationIdMap.put(id, notificationId); downloadIdNotificationIdMap.put(id, notificationId);
@ -194,9 +211,13 @@ public class DownloadManager {
if (builders.containsKey(notificationId)) { if (builders.containsKey(notificationId)) {
builder = builders.get(notificationId); builder = builders.get(notificationId);
} else { } else {
PendingIntent stopDownloadIntent = PendingIntent.getBroadcast(context, 0, getDeleteDownloadIntent(id), PendingIntent.FLAG_CANCEL_CURRENT);
builder = new NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID); builder = new NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID);
builder.setContentTitle(String.format("Downloading %s", truncateFilename(filename))) builder.setColor(ContextCompat.getColor(context, R.color.lbryGreen))
.setPriority(NotificationCompat.PRIORITY_LOW); .setContentTitle(String.format("Downloading %s", truncateFilename(filename)))
.setPriority(NotificationCompat.PRIORITY_LOW)
.setOngoing(true)
.addAction(android.R.drawable.ic_menu_close_clear_cancel, "Stop", stopDownloadIntent);
builders.put(notificationId, builder); builders.put(notificationId, builder);
} }
@ -213,7 +234,9 @@ public class DownloadManager {
.setContentText(String.format("%s", formatBytes(totalBytes))) .setContentText(String.format("%s", formatBytes(totalBytes)))
.setGroup(GROUP_DOWNLOADS) .setGroup(GROUP_DOWNLOADS)
.setProgress(0, 0, false) .setProgress(0, 0, false)
.setSmallIcon(android.R.drawable.stat_sys_download_done); .setSmallIcon(android.R.drawable.stat_sys_download_done)
.setOngoing(false);
builder.mActions.clear();
notificationManager.notify(notificationId, builder.build()); notificationManager.notify(notificationId, builder.build());
if (downloadIdNotificationIdMap.containsKey(id)) { if (downloadIdNotificationIdMap.containsKey(id)) {
@ -258,11 +281,13 @@ public class DownloadManager {
.setContentText(String.format("%s", formatBytes(totalBytes))) .setContentText(String.format("%s", formatBytes(totalBytes)))
.setGroup(GROUP_DOWNLOADS) .setGroup(GROUP_DOWNLOADS)
.setProgress(0, 0, false) .setProgress(0, 0, false)
.setSmallIcon(android.R.drawable.stat_sys_download_done); .setSmallIcon(android.R.drawable.stat_sys_download_done)
notificationManager.notify(notificationId, builder.build()); .setOngoing(false);
builder.mActions.clear();
notificationManager.notify(notificationId, builder.build());
// If there are no more downloads and the group exists, set the icon to stop animating // If there are no more downloads and the group exists, set the icon to stop animating
checkGroupDownloadIcon(notificationManager); checkGroupDownloadIcon(notificationManager);
} }
} }
@ -295,11 +320,22 @@ public class DownloadManager {
return completedDownloads; return completedDownloads;
} }
public String getOutpointForDownload(String uri) {
if (downloadIdOutpointsMap.containsKey(uri)) {
return downloadIdOutpointsMap.get(uri);
}
return null;
}
public void deleteDownloadUri(String uri) { public void deleteDownloadUri(String uri) {
synchronized (this) { synchronized (this) {
activeDownloads.remove(uri); activeDownloads.remove(uri);
completedDownloads.remove(uri); completedDownloads.remove(uri);
if (downloadIdOutpointsMap.containsKey(uri)) {
downloadIdOutpointsMap.remove(uri);
}
if (downloadIdNotificationIdMap.containsKey(uri)) { if (downloadIdNotificationIdMap.containsKey(uri)) {
removeDownloadNotification(uri); removeDownloadNotification(uri);
} }

View file

@ -123,7 +123,8 @@ public class LbrynetService extends PythonService {
} }
} else if (ACTION_DELETE_DOWNLOAD.equals(action)) { } else if (ACTION_DELETE_DOWNLOAD.equals(action)) {
String uri = intent.getStringExtra("uri"); String uri = intent.getStringExtra("uri");
LbrynetService.this.deleteDownload(uri); boolean nativeDelete = intent.getBooleanExtra("nativeDelete", false);
LbrynetService.this.deleteDownload(uri, nativeDelete);
} else if (ACTION_CHECK_DOWNLOADS.equals(action)) { } else if (ACTION_CHECK_DOWNLOADS.equals(action)) {
LbrynetService.this.checkDownloads(); LbrynetService.this.checkDownloads();
} }
@ -212,8 +213,10 @@ public class LbrynetService extends PythonService {
if (streamManagerReady) { if (streamManagerReady) {
Map<String, Object> params = new HashMap<String, Object>(); Map<String, Object> params = new HashMap<String, Object>();
params.put("page_size", 100); params.put("page_size", 100);
params.put("status", "stopped"); params.put("reverse", true);
params.put("comparison", "ne"); params.put("sort", "added_on");
/*params.put("status", "stopped");
params.put("comparison", "ne");*/
String fileList = Utils.sdkCall("file_list", params); String fileList = Utils.sdkCall("file_list", params);
if (fileList != null) { if (fileList != null) {
@ -266,7 +269,7 @@ public class LbrynetService extends PythonService {
File file = new File(downloadPath); File file = new File(downloadPath);
Intent intent = createDownloadEventIntent(uri, outpoint, item.toString()); Intent intent = createDownloadEventIntent(uri, outpoint, item.toString());
intent.putExtra("action", "start"); intent.putExtra("action", "start");
downloadManager.startDownload(uri, file.getName()); downloadManager.startDownload(uri, file.getName(), outpoint);
Context context = getApplicationContext(); Context context = getApplicationContext();
if (context != null) { if (context != null) {
@ -286,10 +289,45 @@ public class LbrynetService extends PythonService {
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); }).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} }
private void deleteDownload(String uri) { private void deleteDownload(String uri, boolean nativeDelete) {
final String outpoint = downloadManager.getOutpointForDownload(uri);
if (nativeDelete && outpoint != null) {
// send call sdk to delete the file on the corresponding outpoint
removeDownloadFromManager(uri);
(new AsyncTask<Void, Void, String>() {
protected String doInBackground(Void... param) {
try {
Map<String, Object> params = new HashMap<String, Object>();
params.put("outpoint", outpoint);
params.put("delete_from_download_dir", true);
return Utils.sdkCall("file_delete", params);
} catch (ConnectException ex) {
return null;
}
}
protected void onPostExecute(String response) {
// after deletion, remove the download from the download manager
Intent intent = createDownloadEventIntent(uri, outpoint, null);
intent.putExtra("action", "abort");
Context context = getApplicationContext();
if (context != null) {
context.sendBroadcast(intent);
}
}
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} else {
removeDownloadFromManager(uri);
}
}
private void removeDownloadFromManager(String uri) {
if (downloadManager.isDownloadActive(uri)) { if (downloadManager.isDownloadActive(uri)) {
downloadManager.abortDownload(uri); downloadManager.abortDownload(uri);
} }
downloadManager.deleteDownloadUri(uri); downloadManager.deleteDownloadUri(uri);
} }
@ -359,23 +397,13 @@ public class LbrynetService extends PythonService {
if (!completed && downloadPath != null) { if (!completed && downloadPath != null) {
downloadManager.clearWrittenBytesForDownload(uri); downloadManager.clearWrittenBytesForDownload(uri);
intent.putExtra("action", "start"); intent.putExtra("action", "start");
downloadManager.startDownload(uri, file.getName()); downloadManager.startDownload(uri, file.getName(), outpoint);
if (context != null) { if (context != null) {
context.sendBroadcast(intent); context.sendBroadcast(intent);
} }
} }
} }
} }
// check download manager uris and clear downloads that may have been cancelled / deleted
/*List<String> activeUris = downloadManager.getActiveDownloads();
for (int i = 0; i < activeUris.size(); i++) {
String activeUri = activeUris.get(i);
if (!itemUris.contains(activeUri)) {
downloadManager.abortDownload(activeUri);
fileListUris.remove(activeUri); // remove URIs from the session that may have been deleted
}
}*/
} catch (JSONException ex) { } catch (JSONException ex) {
// pass // pass
Log.e(TAG, ex.getMessage(), ex); Log.e(TAG, ex.getMessage(), ex);

View file

@ -212,17 +212,28 @@ public class MainActivity extends FragmentActivity implements DefaultHardwareBac
String outpoint = intent.getStringExtra("outpoint"); String outpoint = intent.getStringExtra("outpoint");
String fileInfoJson = intent.getStringExtra("file_info"); String fileInfoJson = intent.getStringExtra("file_info");
if (uri == null || outpoint == null || fileInfoJson == null) {
if (uri == null || outpoint == null || (fileInfoJson == null && !"abort".equals(downloadAction))) {
return;
}
String eventName = null;
WritableMap params = Arguments.createMap();
params.putString("uri", uri);
params.putString("outpoint", outpoint);
ReactContext reactContext = mReactInstanceManager.getCurrentReactContext();
if ("abort".equals(downloadAction)) {
eventName = "onDownloadAborted";
if (reactContext != null) {
reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit(eventName, params);
}
return; return;
} }
try { try {
String eventName = null;
JSONObject json = new JSONObject(fileInfoJson); JSONObject json = new JSONObject(fileInfoJson);
WritableMap fileInfo = JSONObjectToMap(json); WritableMap fileInfo = JSONObjectToMap(json);
WritableMap params = Arguments.createMap();
params.putString("uri", uri);
params.putString("outpoint", outpoint);
params.putMap("fileInfo", fileInfo); params.putMap("fileInfo", fileInfo);
if (DownloadManager.ACTION_UPDATE.equals(downloadAction)) { if (DownloadManager.ACTION_UPDATE.equals(downloadAction)) {
@ -233,7 +244,6 @@ public class MainActivity extends FragmentActivity implements DefaultHardwareBac
eventName = (DownloadManager.ACTION_START.equals(downloadAction)) ? "onDownloadStarted" : "onDownloadCompleted"; eventName = (DownloadManager.ACTION_START.equals(downloadAction)) ? "onDownloadStarted" : "onDownloadCompleted";
} }
ReactContext reactContext = mReactInstanceManager.getCurrentReactContext();
if (reactContext != null) { if (reactContext != null) {
reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit(eventName, params); reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit(eventName, params);
} }