NewPipe/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java

942 lines
32 KiB
Java

package us.shandian.giga.ui.adapter;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
import android.support.v4.content.FileProvider;
import android.support.v4.view.ViewCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.util.DiffUtil;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.Adapter;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.util.Log;
import android.util.SparseArray;
import android.view.HapticFeedbackConstants;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.MimeTypeMap;
import android.widget.ImageView;
import android.widget.PopupMenu;
import android.widget.TextView;
import android.widget.Toast;
import org.schabi.newpipe.BuildConfig;
import org.schabi.newpipe.R;
import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.NavigationHelper;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
import us.shandian.giga.get.DownloadMission;
import us.shandian.giga.get.FinishedMission;
import us.shandian.giga.get.Mission;
import us.shandian.giga.io.StoredFileHelper;
import us.shandian.giga.service.DownloadManager;
import us.shandian.giga.service.DownloadManagerService;
import us.shandian.giga.ui.common.Deleter;
import us.shandian.giga.ui.common.ProgressDrawable;
import us.shandian.giga.util.Utility;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.Intent.FLAG_GRANT_PREFIX_URI_PERMISSION;
import static android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION;
import static us.shandian.giga.get.DownloadMission.ERROR_CONNECT_HOST;
import static us.shandian.giga.get.DownloadMission.ERROR_FILE_CREATION;
import static us.shandian.giga.get.DownloadMission.ERROR_HTTP_NO_CONTENT;
import static us.shandian.giga.get.DownloadMission.ERROR_HTTP_UNSUPPORTED_RANGE;
import static us.shandian.giga.get.DownloadMission.ERROR_INSUFFICIENT_STORAGE;
import static us.shandian.giga.get.DownloadMission.ERROR_NOTHING;
import static us.shandian.giga.get.DownloadMission.ERROR_PATH_CREATION;
import static us.shandian.giga.get.DownloadMission.ERROR_PERMISSION_DENIED;
import static us.shandian.giga.get.DownloadMission.ERROR_POSTPROCESSING;
import static us.shandian.giga.get.DownloadMission.ERROR_POSTPROCESSING_HOLD;
import static us.shandian.giga.get.DownloadMission.ERROR_POSTPROCESSING_STOPPED;
import static us.shandian.giga.get.DownloadMission.ERROR_PROGRESS_LOST;
import static us.shandian.giga.get.DownloadMission.ERROR_SSL_EXCEPTION;
import static us.shandian.giga.get.DownloadMission.ERROR_UNKNOWN_EXCEPTION;
import static us.shandian.giga.get.DownloadMission.ERROR_UNKNOWN_HOST;
public class MissionAdapter extends Adapter<ViewHolder> {
private static final SparseArray<String> ALGORITHMS = new SparseArray<>();
private static final String TAG = "MissionAdapter";
private static final String UNDEFINED_PROGRESS = "--.-%";
private static final String DEFAULT_MIME_TYPE = "*/*";
static {
ALGORITHMS.put(R.id.md5, "MD5");
ALGORITHMS.put(R.id.sha1, "SHA1");
}
private Context mContext;
private LayoutInflater mInflater;
private DownloadManager mDownloadManager;
private Deleter mDeleter;
private int mLayout;
private DownloadManager.MissionIterator mIterator;
private ArrayList<ViewHolderItem> mPendingDownloadsItems = new ArrayList<>();
private Handler mHandler;
private MenuItem mClear;
private MenuItem mStartButton;
private MenuItem mPauseButton;
private View mEmptyMessage;
private RecoverHelper mRecover;
public MissionAdapter(Context context, @NonNull DownloadManager downloadManager, View emptyMessage) {
mContext = context;
mDownloadManager = downloadManager;
mDeleter = null;
mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mLayout = R.layout.mission_item;
mHandler = new Handler(Looper.myLooper()) {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case DownloadManagerService.MESSAGE_PROGRESS:
case DownloadManagerService.MESSAGE_ERROR:
case DownloadManagerService.MESSAGE_FINISHED:
onServiceMessage(msg);
break;
}
if (mStartButton != null && mPauseButton != null) switch (msg.what) {
case DownloadManagerService.MESSAGE_DELETED:
case DownloadManagerService.MESSAGE_ERROR:
case DownloadManagerService.MESSAGE_FINISHED:
case DownloadManagerService.MESSAGE_PAUSED:
checkMasterButtonsVisibility();
break;
}
}
};
mEmptyMessage = emptyMessage;
mIterator = downloadManager.getIterator();
checkEmptyMessageVisibility();
}
@Override
@NonNull
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
switch (viewType) {
case DownloadManager.SPECIAL_PENDING:
case DownloadManager.SPECIAL_FINISHED:
return new ViewHolderHeader(mInflater.inflate(R.layout.missions_header, parent, false));
}
return new ViewHolderItem(mInflater.inflate(mLayout, parent, false));
}
@Override
public void onViewRecycled(@NonNull ViewHolder view) {
super.onViewRecycled(view);
if (view instanceof ViewHolderHeader) return;
ViewHolderItem h = (ViewHolderItem) view;
if (h.item.mission instanceof DownloadMission) {
mPendingDownloadsItems.remove(h);
if (mPendingDownloadsItems.size() < 1) {
setAutoRefresh(false);
if (mStartButton != null) mStartButton.setVisible(false);
if (mPauseButton != null) mPauseButton.setVisible(false);
}
}
h.popupMenu.dismiss();
h.item = null;
h.lastTimeStamp = -1;
h.lastDone = -1;
h.lastCurrent = -1;
h.state = 0;
}
@Override
@SuppressLint("SetTextI18n")
public void onBindViewHolder(@NonNull ViewHolder view, @SuppressLint("RecyclerView") int pos) {
DownloadManager.MissionItem item = mIterator.getItem(pos);
if (view instanceof ViewHolderHeader) {
if (item.special == DownloadManager.SPECIAL_NOTHING) return;
int str;
if (item.special == DownloadManager.SPECIAL_PENDING) {
str = R.string.missions_header_pending;
} else {
str = R.string.missions_header_finished;
if (mClear != null) mClear.setVisible(true);
}
((ViewHolderHeader) view).header.setText(str);
return;
}
ViewHolderItem h = (ViewHolderItem) view;
h.item = item;
Utility.FileType type = Utility.getFileType(item.mission.kind, item.mission.storage.getName());
h.icon.setImageResource(Utility.getIconForFileType(type));
h.name.setText(item.mission.storage.getName());
h.progress.setColors(Utility.getBackgroundForFileType(mContext, type), Utility.getForegroundForFileType(mContext, type));
if (h.item.mission instanceof DownloadMission) {
DownloadMission mission = (DownloadMission) item.mission;
String length = Utility.formatBytes(mission.getLength());
if (mission.running && !mission.isPsRunning()) length += " --.- kB/s";
h.size.setText(length);
h.pause.setTitle(mission.unknownLength ? R.string.stop : R.string.pause);
h.lastCurrent = mission.current;
updateProgress(h);
mPendingDownloadsItems.add(h);
} else {
h.progress.setMarquee(false);
h.status.setText("100%");
h.progress.setProgress(1f);
h.size.setText(Utility.formatBytes(item.mission.length));
}
}
@Override
public int getItemCount() {
return mIterator.getOldListSize();
}
@Override
public int getItemViewType(int position) {
return mIterator.getSpecialAtItem(position);
}
@SuppressLint("DefaultLocale")
private void updateProgress(ViewHolderItem h) {
if (h == null || h.item == null || h.item.mission instanceof FinishedMission) return;
long now = System.currentTimeMillis();
DownloadMission mission = (DownloadMission) h.item.mission;
if (h.lastCurrent != mission.current) {
h.lastCurrent = mission.current;
h.lastTimeStamp = now;
h.lastDone = 0;
} else {
if (h.lastTimeStamp == -1) h.lastTimeStamp = now;
if (h.lastDone == -1) h.lastDone = mission.done;
}
long deltaTime = now - h.lastTimeStamp;
long deltaDone = mission.done - h.lastDone;
boolean hasError = mission.errCode != ERROR_NOTHING;
// hide on error
// show if current resource length is not fetched
// show if length is unknown
h.progress.setMarquee(!hasError && (!mission.isInitialized() || mission.unknownLength));
float progress;
if (mission.unknownLength) {
progress = Float.NaN;
h.progress.setProgress(0f);
} else {
progress = (float) ((double) mission.done / mission.length);
if (mission.urls.length > 1 && mission.current < mission.urls.length) {
progress = (progress / mission.urls.length) + ((float) mission.current / mission.urls.length);
}
}
if (hasError) {
h.progress.setProgress(isNotFinite(progress) ? 1f : progress);
h.status.setText(R.string.msg_error);
} else if (isNotFinite(progress)) {
h.status.setText(UNDEFINED_PROGRESS);
} else {
h.status.setText(String.format("%.2f%%", progress * 100));
h.progress.setProgress(progress);
}
long length = mission.getLength();
int state;
if (mission.isPsFailed() || mission.errCode == ERROR_POSTPROCESSING_HOLD) {
state = 0;
} else if (!mission.running) {
state = mission.enqueued ? 1 : 2;
} else if (mission.isPsRunning()) {
state = 3;
} else {
state = 0;
}
if (state != 0) {
// update state without download speed
if (h.state != state) {
String statusStr;
h.state = state;
switch (state) {
case 1:
statusStr = mContext.getString(R.string.queued);
break;
case 2:
statusStr = mContext.getString(R.string.paused);
break;
case 3:
statusStr = mContext.getString(R.string.post_processing);
break;
default:
statusStr = "?";
break;
}
h.size.setText(Utility.formatBytes(length).concat(" (").concat(statusStr).concat(")"));
} else if (deltaDone > 0) {
h.lastTimeStamp = now;
h.lastDone = mission.done;
}
return;
}
if (deltaDone > 0 && deltaTime > 0) {
float speed = (deltaDone * 1000f) / deltaTime;
String speedStr = Utility.formatSpeed(speed);
String sizeStr = Utility.formatBytes(length);
h.size.setText(sizeStr.concat(" ").concat(speedStr));
h.lastTimeStamp = now;
h.lastDone = mission.done;
}
}
private void viewWithFileProvider(Mission mission) {
if (checkInvalidFile(mission)) return;
String mimeType = resolveMimeType(mission);
if (BuildConfig.DEBUG)
Log.v(TAG, "Mime: " + mimeType + " package: " + BuildConfig.APPLICATION_ID + ".provider");
Uri uri;
if (mission.storage.isDirect()) {
uri = FileProvider.getUriForFile(
mContext,
BuildConfig.APPLICATION_ID + ".provider",
mission.storage.getIOFile()
);
} else {
uri = mission.storage.getUri();
}
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(uri, mimeType);
intent.addFlags(FLAG_GRANT_READ_URI_PERMISSION);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
intent.addFlags(FLAG_GRANT_PREFIX_URI_PERMISSION);
}
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
intent.addFlags(FLAG_ACTIVITY_NEW_TASK);
}
//mContext.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
if (intent.resolveActivity(mContext.getPackageManager()) != null) {
mContext.startActivity(intent);
} else {
Toast.makeText(mContext, R.string.toast_no_player, Toast.LENGTH_LONG).show();
}
}
private void shareFile(Mission mission) {
if (checkInvalidFile(mission)) return;
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType(resolveMimeType(mission));
intent.putExtra(Intent.EXTRA_STREAM, mission.storage.getUri());
mContext.startActivity(Intent.createChooser(intent, null));
}
private static String resolveMimeType(@NonNull Mission mission) {
String ext = Utility.getFileExt(mission.storage.getName());
if (ext == null) return DEFAULT_MIME_TYPE;
String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(ext.substring(1));
return mimeType == null ? DEFAULT_MIME_TYPE : mimeType;
}
private boolean checkInvalidFile(@NonNull Mission mission) {
if (mission.storage.existsAsFile()) return false;
Toast.makeText(mContext, R.string.missing_file, Toast.LENGTH_SHORT).show();
return true;
}
public Handler getMessenger() {
return mHandler;
}
private void onServiceMessage(@NonNull Message msg) {
if (msg.what == DownloadManagerService.MESSAGE_PROGRESS) {
setAutoRefresh(true);
return;
}
for (int i = 0; i < mPendingDownloadsItems.size(); i++) {
ViewHolderItem h = mPendingDownloadsItems.get(i);
if (h.item.mission != msg.obj) continue;
if (msg.what == DownloadManagerService.MESSAGE_FINISHED) {
// DownloadManager should mark the download as finished
applyChanges();
return;
}
updateProgress(h);
return;
}
}
private void showError(@NonNull DownloadMission mission) {
@StringRes int msg = R.string.general_error;
String msgEx = null;
switch (mission.errCode) {
case 416:
msg = R.string.error_http_requested_range_not_satisfiable;
break;
case 404:
msg = R.string.error_http_not_found;
break;
case ERROR_NOTHING:
return;// this never should happen
case ERROR_FILE_CREATION:
msg = R.string.error_file_creation;
break;
case ERROR_HTTP_NO_CONTENT:
msg = R.string.error_http_no_content;
break;
case ERROR_HTTP_UNSUPPORTED_RANGE:
msg = R.string.error_http_unsupported_range;
break;
case ERROR_PATH_CREATION:
msg = R.string.error_path_creation;
break;
case ERROR_PERMISSION_DENIED:
msg = R.string.permission_denied;
break;
case ERROR_SSL_EXCEPTION:
msg = R.string.error_ssl_exception;
break;
case ERROR_UNKNOWN_HOST:
msg = R.string.error_unknown_host;
break;
case ERROR_CONNECT_HOST:
msg = R.string.error_connect_host;
break;
case ERROR_POSTPROCESSING_STOPPED:
msg = R.string.error_postprocessing_stopped;
break;
case ERROR_POSTPROCESSING:
case ERROR_POSTPROCESSING_HOLD:
showError(mission.errObject, UserAction.DOWNLOAD_POSTPROCESSING, R.string.error_postprocessing_failed);
return;
case ERROR_INSUFFICIENT_STORAGE:
msg = R.string.error_insufficient_storage;
break;
case ERROR_UNKNOWN_EXCEPTION:
showError(mission.errObject, UserAction.DOWNLOAD_FAILED, R.string.general_error);
return;
case ERROR_PROGRESS_LOST:
msg = R.string.error_progress_lost;
default:
if (mission.errCode >= 100 && mission.errCode < 600) {
msgEx = "HTTP " + mission.errCode;
} else if (mission.errObject == null) {
msgEx = "(not_decelerated_error_code)";
} else {
showError(mission.errObject, UserAction.DOWNLOAD_FAILED, msg);
return;
}
break;
}
AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
if (msgEx != null)
builder.setMessage(msgEx);
else
builder.setMessage(msg);
// add report button for non-HTTP errors (range 100-599)
if (mission.errObject != null && (mission.errCode < 100 || mission.errCode >= 600)) {
@StringRes final int mMsg = msg;
builder.setPositiveButton(R.string.error_report_title, (dialog, which) ->
showError(mission.errObject, UserAction.DOWNLOAD_FAILED, mMsg)
);
}
builder.setNegativeButton(android.R.string.ok, (dialog, which) -> dialog.cancel())
.setTitle(mission.storage.getName())
.create()
.show();
}
private void showError(Exception exception, UserAction action, @StringRes int reason) {
ErrorActivity.reportError(
mContext,
Collections.singletonList(exception),
null,
null,
ErrorActivity.ErrorInfo.make(action, "-", "-", reason)
);
}
public void clearFinishedDownloads() {
mDownloadManager.forgetFinishedDownloads();
applyChanges();
}
private boolean handlePopupItem(@NonNull ViewHolderItem h, @NonNull MenuItem option) {
int id = option.getItemId();
DownloadMission mission = h.item.mission instanceof DownloadMission ? (DownloadMission) h.item.mission : null;
if (mission != null) {
switch (id) {
case R.id.start:
h.status.setText(UNDEFINED_PROGRESS);
h.state = -1;
h.size.setText(Utility.formatBytes(mission.getLength()));
mDownloadManager.resumeMission(mission);
return true;
case R.id.pause:
h.state = -1;
mDownloadManager.pauseMission(mission);
updateProgress(h);
h.lastTimeStamp = -1;
h.lastDone = -1;
return true;
case R.id.error_message_view:
showError(mission);
return true;
case R.id.queue:
boolean flag = !h.queue.isChecked();
h.queue.setChecked(flag);
mission.setEnqueued(flag);
updateProgress(h);
return true;
case R.id.retry:
if (mission.hasInvalidStorage()) {
mRecover.tryRecover(mission);
return true;
}
mission.psContinue(true);
return true;
case R.id.cancel:
mission.psContinue(false);
return false;
}
}
switch (id) {
case R.id.menu_item_share:
shareFile(h.item.mission);
return true;
case R.id.delete:
if (mDeleter == null) {
mDownloadManager.deleteMission(h.item.mission);
} else {
mDeleter.append(h.item.mission);
}
applyChanges();
return true;
case R.id.md5:
case R.id.sha1:
new ChecksumTask(mContext).execute(h.item.mission.storage, ALGORITHMS.get(id));
return true;
case R.id.source:
/*Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(h.item.mission.source));
mContext.startActivity(intent);*/
try {
Intent intent = NavigationHelper.getIntentByLink(mContext, h.item.mission.source);
intent.addFlags(Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
mContext.startActivity(intent);
} catch (Exception e) {
Log.w(TAG, "Selected item has a invalid source", e);
}
return true;
default:
return false;
}
}
public void applyChanges() {
mIterator.start();
DiffUtil.calculateDiff(mIterator, true).dispatchUpdatesTo(this);
mIterator.end();
checkEmptyMessageVisibility();
if (mClear != null) mClear.setVisible(mIterator.hasFinishedMissions());
}
public void forceUpdate() {
mIterator.start();
mIterator.end();
for (ViewHolderItem item : mPendingDownloadsItems) {
item.lastTimeStamp = -1;
}
notifyDataSetChanged();
}
public void setLinear(boolean isLinear) {
mLayout = isLinear ? R.layout.mission_item_linear : R.layout.mission_item;
}
public void setClearButton(MenuItem clearButton) {
if (mClear == null)
clearButton.setVisible(mIterator.hasFinishedMissions());
mClear = clearButton;
}
public void setMasterButtons(MenuItem startButton, MenuItem pauseButton) {
boolean init = mStartButton == null || mPauseButton == null;
mStartButton = startButton;
mPauseButton = pauseButton;
if (init) checkMasterButtonsVisibility();
}
private void checkEmptyMessageVisibility() {
int flag = mIterator.getOldListSize() > 0 ? View.GONE : View.VISIBLE;
if (mEmptyMessage.getVisibility() != flag) mEmptyMessage.setVisibility(flag);
}
private void checkMasterButtonsVisibility() {
boolean[] state = mIterator.hasValidPendingMissions();
mStartButton.setVisible(state[0]);
mPauseButton.setVisible(state[1]);
}
public void ensurePausedMissions() {
for (ViewHolderItem h : mPendingDownloadsItems) {
if (((DownloadMission) h.item.mission).running) continue;
updateProgress(h);
h.lastTimeStamp = -1;
h.lastDone = -1;
}
}
public void deleterDispose(boolean commitChanges) {
if (mDeleter != null) mDeleter.dispose(commitChanges);
}
public void deleterLoad(View view) {
if (mDeleter == null)
mDeleter = new Deleter(view, mContext, this, mDownloadManager, mIterator, mHandler);
}
public void deleterResume() {
if (mDeleter != null) mDeleter.resume();
}
public void recoverMission(DownloadMission mission, StoredFileHelper newStorage) {
for (ViewHolderItem h : mPendingDownloadsItems) {
if (mission != h.item.mission) continue;
mission.changeStorage(newStorage);
mission.errCode = DownloadMission.ERROR_NOTHING;
mission.errObject = null;
h.status.setText(UNDEFINED_PROGRESS);
h.state = -1;
h.size.setText(Utility.formatBytes(mission.getLength()));
h.progress.setMarquee(true);
mDownloadManager.resumeMission(mission);
return;
}
}
private boolean mUpdaterRunning = false;
private final Runnable rUpdater = this::updater;
public void onPaused() {
setAutoRefresh(false);
}
private void setAutoRefresh(boolean enabled) {
if (enabled && !mUpdaterRunning) {
mUpdaterRunning = true;
updater();
} else if (!enabled && mUpdaterRunning) {
mUpdaterRunning = false;
mHandler.removeCallbacks(rUpdater);
}
}
private void updater() {
if (!mUpdaterRunning) return;
boolean running = false;
for (ViewHolderItem h : mPendingDownloadsItems) {
// check if the mission is running first
if (!((DownloadMission) h.item.mission).running) continue;
updateProgress(h);
running = true;
}
if (running) {
mHandler.postDelayed(rUpdater, 1000);
} else {
mUpdaterRunning = false;
}
}
private boolean isNotFinite(Float value) {
return Float.isNaN(value) || Float.isInfinite(value);
}
public void setRecover(@NonNull RecoverHelper callback) {
mRecover = callback;
}
class ViewHolderItem extends RecyclerView.ViewHolder {
DownloadManager.MissionItem item;
TextView status;
ImageView icon;
TextView name;
TextView size;
ProgressDrawable progress;
PopupMenu popupMenu;
MenuItem retry;
MenuItem cancel;
MenuItem start;
MenuItem pause;
MenuItem open;
MenuItem queue;
MenuItem showError;
MenuItem delete;
MenuItem source;
MenuItem checksum;
long lastTimeStamp = -1;
long lastDone = -1;
int lastCurrent = -1;
int state = 0;
ViewHolderItem(View view) {
super(view);
progress = new ProgressDrawable();
ViewCompat.setBackground(itemView.findViewById(R.id.item_bkg), progress);
status = itemView.findViewById(R.id.item_status);
name = itemView.findViewById(R.id.item_name);
icon = itemView.findViewById(R.id.item_icon);
size = itemView.findViewById(R.id.item_size);
name.setSelected(true);
ImageView button = itemView.findViewById(R.id.item_more);
popupMenu = buildPopup(button);
button.setOnClickListener(v -> showPopupMenu());
Menu menu = popupMenu.getMenu();
retry = menu.findItem(R.id.retry);
cancel = menu.findItem(R.id.cancel);
start = menu.findItem(R.id.start);
pause = menu.findItem(R.id.pause);
open = menu.findItem(R.id.menu_item_share);
queue = menu.findItem(R.id.queue);
showError = menu.findItem(R.id.error_message_view);
delete = menu.findItem(R.id.delete);
source = menu.findItem(R.id.source);
checksum = menu.findItem(R.id.checksum);
itemView.setHapticFeedbackEnabled(true);
itemView.setOnClickListener(v -> {
if (item.mission instanceof FinishedMission)
viewWithFileProvider(item.mission);
});
itemView.setOnLongClickListener(v -> {
v.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
showPopupMenu();
return true;
});
}
private void showPopupMenu() {
retry.setVisible(false);
cancel.setVisible(false);
start.setVisible(false);
pause.setVisible(false);
open.setVisible(false);
queue.setVisible(false);
showError.setVisible(false);
delete.setVisible(false);
source.setVisible(false);
checksum.setVisible(false);
DownloadMission mission = item.mission instanceof DownloadMission ? (DownloadMission) item.mission : null;
if (mission != null) {
if (mission.hasInvalidStorage()) {
retry.setEnabled(true);
delete.setEnabled(true);
showError.setEnabled(true);
} else if (mission.isPsRunning()) {
switch (mission.errCode) {
case ERROR_INSUFFICIENT_STORAGE:
case ERROR_POSTPROCESSING_HOLD:
retry.setVisible(true);
cancel.setVisible(true);
showError.setVisible(true);
break;
}
} else {
if (mission.running) {
pause.setVisible(true);
} else {
if (mission.errCode != ERROR_NOTHING) {
showError.setVisible(true);
}
queue.setChecked(mission.enqueued);
delete.setVisible(true);
boolean flag = !mission.isPsFailed();
start.setVisible(flag);
queue.setVisible(flag);
}
}
} else {
open.setVisible(true);
delete.setVisible(true);
checksum.setVisible(true);
}
if (item.mission.source != null && !item.mission.source.isEmpty()) {
source.setVisible(true);
}
popupMenu.show();
}
private PopupMenu buildPopup(final View button) {
PopupMenu popup = new PopupMenu(mContext, button);
popup.inflate(R.menu.mission);
popup.setOnMenuItemClickListener(option -> handlePopupItem(this, option));
return popup;
}
}
class ViewHolderHeader extends RecyclerView.ViewHolder {
TextView header;
ViewHolderHeader(View view) {
super(view);
header = itemView.findViewById(R.id.item_name);
}
}
static class ChecksumTask extends AsyncTask<Object, Void, String> {
ProgressDialog progressDialog;
WeakReference<Activity> weakReference;
ChecksumTask(@NonNull Context context) {
weakReference = new WeakReference<>((Activity) context);
}
@Override
protected void onPreExecute() {
super.onPreExecute();
Activity activity = getActivity();
if (activity != null) {
// Create dialog
progressDialog = new ProgressDialog(activity);
progressDialog.setCancelable(false);
progressDialog.setMessage(activity.getString(R.string.msg_wait));
progressDialog.show();
}
}
@Override
protected String doInBackground(Object... params) {
return Utility.checksum((StoredFileHelper) params[0], (String) params[1]);
}
@Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
if (progressDialog != null) {
Utility.copyToClipboard(progressDialog.getContext(), result);
if (getActivity() != null) {
progressDialog.dismiss();
}
}
}
@Nullable
private Activity getActivity() {
Activity activity = weakReference.get();
if (activity != null && activity.isFinishing()) {
return null;
} else {
return activity;
}
}
}
public interface RecoverHelper {
void tryRecover(DownloadMission mission);
}
}