Changes for Android 9 (Pie)

* validate the stored file before start the mission
* add warning on StoredFileHelper.java
* simplify the communication between MissionAdapter and DownloadManagerService.java since shares the same looper
* simplify setVisible() "start/pause all downloads" buttons logic
This commit is contained in:
kapodamy 2019-09-01 18:17:54 -03:00
parent 85d1888ba7
commit 1a643126de
6 changed files with 66 additions and 69 deletions

View File

@ -1,7 +1,6 @@
package us.shandian.giga.get; package us.shandian.giga.get;
import android.os.Handler; import android.os.Handler;
import android.os.Message;
import android.util.Log; import android.util.Log;
import org.schabi.newpipe.Downloader; import org.schabi.newpipe.Downloader;
@ -264,11 +263,7 @@ public class DownloadMission extends Mission {
private void notify(int what) { private void notify(int what) {
Message m = new Message(); mHandler.obtainMessage(what, this).sendToTarget();
m.what = what;
m.obj = this;
mHandler.sendMessage(m);
} }
synchronized void notifyProgress(long deltaLen) { synchronized void notifyProgress(long deltaLen) {
@ -408,6 +403,7 @@ public class DownloadMission extends Mission {
} }
} }
/** /**
* Start downloading with multiple threads. * Start downloading with multiple threads.
*/ */
@ -416,14 +412,20 @@ public class DownloadMission extends Mission {
// ensure that the previous state is completely paused. // ensure that the previous state is completely paused.
joinForThread(init); joinForThread(init);
if (threads != null) if (threads != null) {
for (Thread thread : threads) joinForThread(thread); for (Thread thread : threads) joinForThread(thread);
threads = null;
}
running = true; running = true;
errCode = ERROR_NOTHING; errCode = ERROR_NOTHING;
if (hasInvalidStorage()) {
notifyError(ERROR_FILE_CREATION, null);
return;
}
if (current >= urls.length) { if (current >= urls.length) {
threads = null;
runAsync(1, this::notifyFinished); runAsync(1, this::notifyFinished);
return; return;
} }
@ -664,7 +666,7 @@ public class DownloadMission extends Mission {
* @return {@code true} is this mission its "healthy", otherwise, {@code false} * @return {@code true} is this mission its "healthy", otherwise, {@code false}
*/ */
public boolean isCorrupt() { public boolean isCorrupt() {
return (isPsFailed() || errCode == ERROR_POSTPROCESSING_HOLD) || isFinished() || hasInvalidStorage(); return (isPsFailed() || errCode == ERROR_POSTPROCESSING_HOLD) || isFinished();
} }
private boolean doPostprocessing() { private boolean doPostprocessing() {

View File

@ -251,6 +251,7 @@ public class StoredFileHelper implements Serializable {
public boolean existsAsFile() { public boolean existsAsFile() {
if (source == null) return false; if (source == null) return false;
// WARNING: DocumentFile.exists() and DocumentFile.isFile() methods are slow
boolean exists = docFile == null ? ioFile.exists() : docFile.exists(); boolean exists = docFile == null ? ioFile.exists() : docFile.exists();
boolean isFile = docFile == null ? ioFile.isFile() : docFile.isFile();// ¿docFile.isVirtual() means is no-physical? boolean isFile = docFile == null ? ioFile.isFile() : docFile.isFile();// ¿docFile.isVirtual() means is no-physical?

View File

@ -424,10 +424,12 @@ public class DownloadManager {
boolean flag = false; boolean flag = false;
for (DownloadMission mission : mMissionsPending) { for (DownloadMission mission : mMissionsPending) {
if (mission.running || !mission.enqueued || mission.isFinished() || mission.hasInvalidStorage()) if (mission.running || !mission.enqueued || mission.isFinished())
continue; continue;
resumeMission(mission); resumeMission(mission);
if (mission.errCode != DownloadMission.ERROR_NOTHING) continue;
if (mPrefQueueLimit) return true; if (mPrefQueueLimit) return true;
flag = true; flag = true;
} }

View File

@ -9,6 +9,7 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.BitmapFactory; import android.graphics.BitmapFactory;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
@ -19,6 +20,7 @@ import android.net.Uri;
import android.os.Binder; import android.os.Binder;
import android.os.Build; import android.os.Build;
import android.os.Handler; import android.os.Handler;
import android.os.Handler.Callback;
import android.os.IBinder; import android.os.IBinder;
import android.os.Looper; import android.os.Looper;
import android.os.Message; import android.os.Message;
@ -88,14 +90,14 @@ public class DownloadManagerService extends Service {
private Builder downloadDoneNotification = null; private Builder downloadDoneNotification = null;
private StringBuilder downloadDoneList = null; private StringBuilder downloadDoneList = null;
private final ArrayList<Handler> mEchoObservers = new ArrayList<>(1); private final ArrayList<Callback> mEchoObservers = new ArrayList<>(1);
private ConnectivityManager mConnectivityManager; private ConnectivityManager mConnectivityManager;
private BroadcastReceiver mNetworkStateListener = null; private BroadcastReceiver mNetworkStateListener = null;
private ConnectivityManager.NetworkCallback mNetworkStateListenerL = null; private ConnectivityManager.NetworkCallback mNetworkStateListenerL = null;
private SharedPreferences mPrefs = null; private SharedPreferences mPrefs = null;
private final SharedPreferences.OnSharedPreferenceChangeListener mPrefChangeListener = this::handlePreferenceChange; private final OnSharedPreferenceChangeListener mPrefChangeListener = this::handlePreferenceChange;
private boolean mLockAcquired = false; private boolean mLockAcquired = false;
private LockManager mLock = null; private LockManager mLock = null;
@ -128,12 +130,7 @@ public class DownloadManagerService extends Service {
} }
mBinder = new DownloadManagerBinder(); mBinder = new DownloadManagerBinder();
mHandler = new Handler(Looper.myLooper()) { mHandler = new Handler(this::handleMessage);
@Override
public void handleMessage(Message msg) {
DownloadManagerService.this.handleMessage(msg);
}
};
mPrefs = PreferenceManager.getDefaultSharedPreferences(this); mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
@ -272,7 +269,7 @@ public class DownloadManagerService extends Service {
return mBinder; return mBinder;
} }
public void handleMessage(Message msg) { private boolean handleMessage(@NonNull Message msg) {
DownloadMission mission = (DownloadMission) msg.obj; DownloadMission mission = (DownloadMission) msg.obj;
switch (msg.what) { switch (msg.what) {
@ -300,14 +297,12 @@ public class DownloadManagerService extends Service {
mFailedDownloads.delete(mFailedDownloads.indexOfValue(mission)); mFailedDownloads.delete(mFailedDownloads.indexOfValue(mission));
synchronized (mEchoObservers) { synchronized (mEchoObservers) {
for (Handler handler : mEchoObservers) { for (Callback observer : mEchoObservers) {
Message echo = new Message(); observer.handleMessage(msg);
echo.what = msg.what;
echo.obj = msg.obj;
handler.sendMessage(echo);
} }
} }
return true;
} }
private void handleConnectivityState(boolean updateOnly) { private void handleConnectivityState(boolean updateOnly) {
@ -515,7 +510,7 @@ public class DownloadManagerService extends Service {
return PendingIntent.getService(this, intent.hashCode(), intent, PendingIntent.FLAG_UPDATE_CURRENT); return PendingIntent.getService(this, intent.hashCode(), intent, PendingIntent.FLAG_UPDATE_CURRENT);
} }
private void manageObservers(Handler handler, boolean add) { private void manageObservers(Callback handler, boolean add) {
synchronized (mEchoObservers) { synchronized (mEchoObservers) {
if (add) { if (add) {
mEchoObservers.add(handler); mEchoObservers.add(handler);
@ -596,11 +591,11 @@ public class DownloadManagerService extends Service {
); );
} }
public void addMissionEventListener(Handler handler) { public void addMissionEventListener(Callback handler) {
manageObservers(handler, true); manageObservers(handler, true);
} }
public void removeMissionEventListener(Handler handler) { public void removeMissionEventListener(Callback handler) {
manageObservers(handler, false); manageObservers(handler, false);
} }

View File

@ -9,7 +9,6 @@ import android.net.Uri;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Build; import android.os.Build;
import android.os.Handler; import android.os.Handler;
import android.os.Looper;
import android.os.Message; import android.os.Message;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
@ -77,7 +76,7 @@ import static us.shandian.giga.get.DownloadMission.ERROR_TIMEOUT;
import static us.shandian.giga.get.DownloadMission.ERROR_UNKNOWN_EXCEPTION; import static us.shandian.giga.get.DownloadMission.ERROR_UNKNOWN_EXCEPTION;
import static us.shandian.giga.get.DownloadMission.ERROR_UNKNOWN_HOST; import static us.shandian.giga.get.DownloadMission.ERROR_UNKNOWN_HOST;
public class MissionAdapter extends Adapter<ViewHolder> { public class MissionAdapter extends Adapter<ViewHolder> implements Handler.Callback {
private static final SparseArray<String> ALGORITHMS = new SparseArray<>(); private static final SparseArray<String> ALGORITHMS = new SparseArray<>();
private static final String TAG = "MissionAdapter"; private static final String TAG = "MissionAdapter";
private static final String UNDEFINED_PROGRESS = "--.-%"; private static final String UNDEFINED_PROGRESS = "--.-%";
@ -111,21 +110,7 @@ public class MissionAdapter extends Adapter<ViewHolder> {
mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mLayout = R.layout.mission_item; mLayout = R.layout.mission_item;
mHandler = new Handler(Looper.myLooper()) { mHandler = new Handler(context.getMainLooper());
@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)
checkMasterButtonsVisibility();
}
};
mEmptyMessage = emptyMessage; mEmptyMessage = emptyMessage;
@ -403,29 +388,40 @@ public class MissionAdapter extends Adapter<ViewHolder> {
return true; return true;
} }
public Handler getMessenger() { @Override
return mHandler; public boolean handleMessage(@NonNull Message msg) {
} if (mStartButton != null && mPauseButton != null) {
checkMasterButtonsVisibility();
private void onServiceMessage(@NonNull Message msg) {
if (msg.what == DownloadManagerService.MESSAGE_PROGRESS) {
setAutoRefresh(true);
return;
} }
for (int i = 0; i < mPendingDownloadsItems.size(); i++) { switch (msg.what) {
ViewHolderItem h = mPendingDownloadsItems.get(i); case DownloadManagerService.MESSAGE_PROGRESS:
case DownloadManagerService.MESSAGE_ERROR:
case DownloadManagerService.MESSAGE_FINISHED:
break;
default:
return false;
}
if (msg.what == DownloadManagerService.MESSAGE_PROGRESS) {
setAutoRefresh(true);
return true;
}
for (ViewHolderItem h : mPendingDownloadsItems) {
if (h.item.mission != msg.obj) continue; if (h.item.mission != msg.obj) continue;
if (msg.what == DownloadManagerService.MESSAGE_FINISHED) { if (msg.what == DownloadManagerService.MESSAGE_FINISHED) {
// DownloadManager should mark the download as finished // DownloadManager should mark the download as finished
applyChanges(); applyChanges();
return; return true;
} }
updateProgress(h); updateProgress(h);
return; return true;
} }
return false;
} }
private void showError(@NonNull DownloadMission mission) { private void showError(@NonNull DownloadMission mission) {
@ -563,16 +559,15 @@ public class MissionAdapter extends Adapter<ViewHolder> {
updateProgress(h); updateProgress(h);
return true; return true;
case R.id.retry: case R.id.retry:
if (mission.hasInvalidStorage()) { if (mission.isPsRunning()) {
mission.psContinue(true);
} else {
mDownloadManager.tryRecover(mission); mDownloadManager.tryRecover(mission);
if (mission.storage.isInvalid()) if (mission.storage.isInvalid())
mRecover.tryRecover(mission); mRecover.tryRecover(mission);
else else
recoverMission(mission); recoverMission(mission);
return true;
} }
mission.psContinue(true);
return true; return true;
case R.id.cancel: case R.id.cancel:
mission.psContinue(false); mission.psContinue(false);
@ -659,9 +654,13 @@ public class MissionAdapter extends Adapter<ViewHolder> {
public void checkMasterButtonsVisibility() { public void checkMasterButtonsVisibility() {
boolean[] state = mIterator.hasValidPendingMissions(); boolean[] state = mIterator.hasValidPendingMissions();
setButtonVisible(mPauseButton, state[0]);
setButtonVisible(mStartButton, state[1]);
}
mPauseButton.setVisible(state[0]); private static void setButtonVisible(MenuItem button, boolean visible) {
mStartButton.setVisible(state[1]); if (button.isVisible() != visible)
button.setVisible(visible);
} }
public void ensurePausedMissions() { public void ensurePausedMissions() {

View File

@ -79,7 +79,7 @@ public class MissionsFragment extends Fragment {
setAdapterButtons(); setAdapterButtons();
mBinder.addMissionEventListener(mAdapter.getMessenger()); mBinder.addMissionEventListener(mAdapter);
mBinder.enableNotifications(false); mBinder.enableNotifications(false);
updateList(); updateList();
@ -159,7 +159,7 @@ public class MissionsFragment extends Fragment {
super.onDestroy(); super.onDestroy();
if (mBinder == null || mAdapter == null) return; if (mBinder == null || mAdapter == null) return;
mBinder.removeMissionEventListener(mAdapter.getMessenger()); mBinder.removeMissionEventListener(mAdapter);
mBinder.enableNotifications(true); mBinder.enableNotifications(true);
mContext.unbindService(mConnection); mContext.unbindService(mConnection);
mAdapter.deleterDispose(true); mAdapter.deleterDispose(true);
@ -197,12 +197,10 @@ public class MissionsFragment extends Fragment {
return true; return true;
case R.id.start_downloads: case R.id.start_downloads:
item.setVisible(false); item.setVisible(false);
mPause.setVisible(true);
mBinder.getDownloadManager().startAllMissions(); mBinder.getDownloadManager().startAllMissions();
return true; return true;
case R.id.pause_downloads: case R.id.pause_downloads:
item.setVisible(false); item.setVisible(false);
mStart.setVisible(true);
mBinder.getDownloadManager().pauseAllMissions(false); mBinder.getDownloadManager().pauseAllMissions(false);
mAdapter.ensurePausedMissions();// update items view mAdapter.ensurePausedMissions();// update items view
default: default:
@ -280,7 +278,7 @@ public class MissionsFragment extends Fragment {
if (mAdapter != null) { if (mAdapter != null) {
mAdapter.deleterDispose(false); mAdapter.deleterDispose(false);
mForceUpdate = true; mForceUpdate = true;
mBinder.removeMissionEventListener(mAdapter.getMessenger()); mBinder.removeMissionEventListener(mAdapter);
} }
} }
@ -296,7 +294,7 @@ public class MissionsFragment extends Fragment {
mAdapter.forceUpdate(); mAdapter.forceUpdate();
} }
mBinder.addMissionEventListener(mAdapter.getMessenger()); mBinder.addMissionEventListener(mAdapter);
mAdapter.checkMasterButtonsVisibility(); mAdapter.checkMasterButtonsVisibility();
} }
if (mBinder != null) mBinder.enableNotifications(false); if (mBinder != null) mBinder.enableNotifications(false);