Code improvements

* Replace unchecked casts with checked casts
 * remove Utility.finViewById
 * Fix return activity checking
 * Create UserAction enum
 * Fix typos
 * Add instrumented test for error info
 * ErrorInfo make fields final
 * Log exception using logger
 * Add inherited annotations
 * Resolve deprecation warnings
 * Remove unused methods from utility
 * Reformat code
 * Remove unused methods from Utility and improve getFileExt
 * Create OnScrollBelowItemsListener
This commit is contained in:
Coffeemakr 2017-06-28 07:27:32 +02:00
parent 40213b2d6a
commit b03723c3fb
40 changed files with 2077 additions and 1981 deletions

View file

@ -5,7 +5,7 @@ READ THIS GUIDELINES CAREFULLY BEFORE CONTRIBUTING.
## Crash reporting ## Crash reporting
Do not report crashes in the GitHub issue tracker. NewPipe has an automated crash report system that will ask you to send a report if a crash occures. Do not report crashes in the GitHub issue tracker. NewPipe has an automated crash report system that will ask you to send a report if a crash occurs.
## Issue reporting/feature request ## Issue reporting/feature request

View file

@ -10,6 +10,8 @@ android {
targetSdkVersion 25 targetSdkVersion 25
versionCode 35 versionCode 35
versionName "0.9.8" versionName "0.9.8"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
} }
buildTypes { buildTypes {
release { release {
@ -31,6 +33,11 @@ android {
} }
dependencies { dependencies {
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2') {
exclude module: 'support-annotations'
}
testCompile 'junit:junit:4.12' testCompile 'junit:junit:4.12'
testCompile 'org.mockito:mockito-core:1.10.19' testCompile 'org.mockito:mockito-core:1.10.19'
testCompile 'org.json:json:20160810' testCompile 'org.json:json:20160810'

View file

@ -0,0 +1,37 @@
package org.schabi.newpipe.report;
import android.os.Parcel;
import android.support.test.filters.LargeTest;
import android.support.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.schabi.newpipe.R;
import org.schabi.newpipe.report.ErrorActivity.ErrorInfo;
import static org.junit.Assert.assertEquals;
/**
* Instrumented tests for {@link ErrorInfo}
*/
@RunWith(AndroidJUnit4.class)
@LargeTest
public class ErrorInfoTest {
@Test
public void errorInfo_testParcelable() {
ErrorInfo info = ErrorInfo.make(UserAction.USER_REPORT, "youtube", "request", R.string.general_error);
// Obtain a Parcel object and write the parcelable object to it:
Parcel parcel = Parcel.obtain();
info.writeToParcel(parcel, 0);
parcel.setDataPosition(0);
ErrorInfo infoFromParcel = ErrorInfo.CREATOR.createFromParcel(parcel);
assertEquals(UserAction.USER_REPORT, infoFromParcel.userAction);
assertEquals("youtube", infoFromParcel.serviceName);
assertEquals("request", infoFromParcel.request);
assertEquals(R.string.general_error, infoFromParcel.message);
parcel.recycle();
}
}

View file

@ -14,6 +14,7 @@ import org.acra.sender.ReportSenderFactory;
import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.report.AcraReportSenderFactory; import org.schabi.newpipe.report.AcraReportSenderFactory;
import org.schabi.newpipe.report.ErrorActivity; import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.settings.SettingsActivity; import org.schabi.newpipe.settings.SettingsActivity;
import org.schabi.newpipe.util.ThemeHelper; import org.schabi.newpipe.util.ThemeHelper;
@ -59,7 +60,7 @@ public class App extends Application {
} catch(ACRAConfigurationException ace) { } catch(ACRAConfigurationException ace) {
ace.printStackTrace(); ace.printStackTrace();
ErrorActivity.reportError(this, ace, null, null, ErrorActivity.reportError(this, ace, null, null,
ErrorActivity.ErrorInfo.make(ErrorActivity.SEARCHED,"none", ErrorActivity.ErrorInfo.make(UserAction.SEARCHED,"none",
"Could not initialize ACRA crash report", R.string.app_ui_crash)); "Could not initialize ACRA crash report", R.string.app_ui_crash));
} }

View file

@ -9,6 +9,7 @@ import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.report.ErrorActivity; import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.UserAction;
/** /**
* Created by Christian Schabesberger on 01.08.16. * Created by Christian Schabesberger on 01.08.16.
@ -49,7 +50,7 @@ public class ImageErrorLoadingListener implements ImageLoadingListener {
public void onLoadingFailed(String imageUri, View view, FailReason failReason) { public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
ErrorActivity.reportError(context, ErrorActivity.reportError(context,
failReason.getCause(), null, rootView, failReason.getCause(), null, rootView,
ErrorActivity.ErrorInfo.make(ErrorActivity.LOAD_IMAGE, ErrorActivity.ErrorInfo.make(UserAction.LOAD_IMAGE,
NewPipe.getNameOfService(serviceId), imageUri, NewPipe.getNameOfService(serviceId), imageUri,
R.string.could_not_load_image)); R.string.could_not_load_image));
} }

View file

@ -35,7 +35,6 @@ import us.shandian.giga.service.DownloadManagerService;
import us.shandian.giga.ui.fragment.AllMissionsFragment; import us.shandian.giga.ui.fragment.AllMissionsFragment;
import us.shandian.giga.ui.fragment.MissionsFragment; import us.shandian.giga.ui.fragment.MissionsFragment;
import us.shandian.giga.util.CrashHandler; import us.shandian.giga.util.CrashHandler;
import us.shandian.giga.util.Utility;
public class DownloadActivity extends AppCompatActivity implements AdapterView.OnItemClickListener { public class DownloadActivity extends AppCompatActivity implements AdapterView.OnItemClickListener {
@ -125,11 +124,11 @@ public class DownloadActivity extends AppCompatActivity implements AdapterView.O
// Create the view // Create the view
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = inflater.inflate(R.layout.dialog_url, null); View v = inflater.inflate(R.layout.dialog_url, null);
final EditText name = Utility.findViewById(v, R.id.file_name); final EditText name = (EditText) v.findViewById(R.id.file_name);
final TextView tCount = Utility.findViewById(v, R.id.threads_count); final TextView tCount = (TextView) v.findViewById(R.id.threads_count);
final SeekBar threads = Utility.findViewById(v, R.id.threads); final SeekBar threads = (SeekBar) v.findViewById(R.id.threads);
final Toolbar toolbar = Utility.findViewById(v, R.id.toolbar); final Toolbar toolbar = (Toolbar) v.findViewById(R.id.toolbar);
final RadioButton audioButton = (RadioButton) Utility.findViewById(v, R.id.audio_button); final RadioButton audioButton = (RadioButton) v.findViewById(R.id.audio_button);
threads.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { threads.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {

View file

@ -253,7 +253,7 @@ public class DownloadDialog extends DialogFragment implements RadioGroup.OnCheck
} }
/** /**
* #143 #44 #42 #22: make shure that the filename does not contain illegal chars. * #143 #44 #42 #22: make sure that the filename does not contain illegal chars.
* This should fix some of the "cannot download" problems. * This should fix some of the "cannot download" problems.
*/ */
private String createFileName(String fileName) { private String createFileName(String fileName) {

View file

@ -26,6 +26,7 @@ import org.schabi.newpipe.R;
import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.channel.ChannelInfo; import org.schabi.newpipe.extractor.channel.ChannelInfo;
import org.schabi.newpipe.fragments.BaseFragment; import org.schabi.newpipe.fragments.BaseFragment;
import org.schabi.newpipe.fragments.search.OnScrollBelowItemsListener;
import org.schabi.newpipe.info_list.InfoItemBuilder; import org.schabi.newpipe.info_list.InfoItemBuilder;
import org.schabi.newpipe.info_list.InfoListAdapter; import org.schabi.newpipe.info_list.InfoListAdapter;
import org.schabi.newpipe.util.Constants; import org.schabi.newpipe.util.Constants;
@ -245,25 +246,14 @@ public class ChannelFragment extends BaseFragment implements ChannelExtractorWor
}); });
channelVideosList.clearOnScrollListeners(); channelVideosList.clearOnScrollListeners();
channelVideosList.addOnScrollListener(new RecyclerView.OnScrollListener() { channelVideosList.addOnScrollListener(new OnScrollBelowItemsListener() {
@Override @Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) { public void onScrolledDown(RecyclerView recyclerView) {
int pastVisiblesItems, visibleItemCount, totalItemCount; if ((currentChannelWorker == null || !currentChannelWorker.isRunning()) && hasNextPage && !isLoading.get()) {
super.onScrolled(recyclerView, dx, dy);
//check for scroll down
if (dy > 0) {
LinearLayoutManager layoutManager = (LinearLayoutManager) channelVideosList.getLayoutManager();
visibleItemCount = layoutManager.getChildCount();
totalItemCount = layoutManager.getItemCount();
pastVisiblesItems = layoutManager.findFirstVisibleItemPosition();
if ((visibleItemCount + pastVisiblesItems) >= totalItemCount && (currentChannelWorker == null || !currentChannelWorker.isRunning()) && hasNextPage && !isLoading.get()) {
pageNumber++; pageNumber++;
loadMoreVideos(); loadMoreVideos();
} }
} }
}
}); });
headerRssButton.setOnClickListener(new View.OnClickListener() { headerRssButton.setOnClickListener(new View.OnClickListener() {

View file

@ -61,6 +61,7 @@ import org.schabi.newpipe.player.MainVideoPlayer;
import org.schabi.newpipe.player.PlayVideoActivity; import org.schabi.newpipe.player.PlayVideoActivity;
import org.schabi.newpipe.player.PopupVideoPlayer; import org.schabi.newpipe.player.PopupVideoPlayer;
import org.schabi.newpipe.report.ErrorActivity; import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.Constants; import org.schabi.newpipe.util.Constants;
import org.schabi.newpipe.util.Localization; import org.schabi.newpipe.util.Localization;
import org.schabi.newpipe.util.NavigationHelper; import org.schabi.newpipe.util.NavigationHelper;
@ -578,7 +579,7 @@ public class VideoDetailFragment extends BaseFragment implements StreamExtractor
imageLoader.displayImage(info.thumbnail_url, thumbnailImageView, displayImageOptions, new SimpleImageLoadingListener() { imageLoader.displayImage(info.thumbnail_url, thumbnailImageView, displayImageOptions, new SimpleImageLoadingListener() {
@Override @Override
public void onLoadingFailed(String imageUri, View view, FailReason failReason) { public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
ErrorActivity.reportError(activity, failReason.getCause(), null, activity.findViewById(android.R.id.content), ErrorActivity.ErrorInfo.make(ErrorActivity.LOAD_IMAGE, NewPipe.getNameOfService(currentStreamInfo.service_id), imageUri, R.string.could_not_load_thumbnails)); ErrorActivity.reportError(activity, failReason.getCause(), null, activity.findViewById(android.R.id.content), ErrorActivity.ErrorInfo.make(UserAction.LOAD_IMAGE, NewPipe.getNameOfService(currentStreamInfo.service_id), imageUri, R.string.could_not_load_thumbnails));
} }
}); });
} else thumbnailImageView.setImageResource(R.drawable.dummy_thumbnail_dark); } else thumbnailImageView.setImageResource(R.drawable.dummy_thumbnail_dark);

View file

@ -0,0 +1,33 @@
package org.schabi.newpipe.fragments.search;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
/**
* Recycler view scroll listener which calls the method {@link #onScrolledDown(RecyclerView)}
* if the view is scrolled below the last item.
*/
public abstract class OnScrollBelowItemsListener extends RecyclerView.OnScrollListener {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
//check for scroll down
if (dy > 0) {
int pastVisibleItems, visibleItemCount, totalItemCount;
LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
visibleItemCount = recyclerView.getLayoutManager().getChildCount();
totalItemCount = recyclerView.getLayoutManager().getItemCount();
pastVisibleItems = layoutManager.findFirstVisibleItemPosition();
if ((visibleItemCount + pastVisibleItems) >= totalItemCount) {
onScrolledDown(recyclerView);
}
}
}
/**
* Called when the recycler view is scrolled below the last item.
* @param recyclerView the recycler view
*/
public abstract void onScrolledDown(RecyclerView recyclerView);
}

View file

@ -242,19 +242,10 @@ public class SearchFragment extends BaseFragment implements SuggestionWorker.OnS
protected void initListeners() { protected void initListeners() {
super.initListeners(); super.initListeners();
resultRecyclerView.clearOnScrollListeners(); resultRecyclerView.clearOnScrollListeners();
resultRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { resultRecyclerView.addOnScrollListener(new OnScrollBelowItemsListener() {
@Override @Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) { public void onScrolledDown(RecyclerView recyclerView) {
int pastVisiblesItems, visibleItemCount, totalItemCount; if(!isLoading.get()) {
super.onScrolled(recyclerView, dx, dy);
//check for scroll down
if (dy > 0) {
LinearLayoutManager layoutManager = (LinearLayoutManager) resultRecyclerView.getLayoutManager();
visibleItemCount = resultRecyclerView.getLayoutManager().getChildCount();
totalItemCount = resultRecyclerView.getLayoutManager().getItemCount();
pastVisiblesItems = layoutManager.findFirstVisibleItemPosition();
if ((visibleItemCount + pastVisiblesItems) >= totalItemCount && !isLoading.get()) {
pageNumber++; pageNumber++;
recyclerView.post(new Runnable() { recyclerView.post(new Runnable() {
@Override @Override
@ -265,10 +256,10 @@ public class SearchFragment extends BaseFragment implements SuggestionWorker.OnS
search(searchQuery, pageNumber); search(searchQuery, pageNumber);
} }
} }
}
}); });
} }
@Override @Override
protected void reloadContent() { protected void reloadContent() {
if (DEBUG) Log.d(TAG, "reloadContent() called"); if (DEBUG) Log.d(TAG, "reloadContent() called");

View file

@ -155,7 +155,7 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
@Override @Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int i) { public void onBindViewHolder(RecyclerView.ViewHolder holder, int i) {
//god damen f*** ANDROID SH** //god damn f*** ANDROID SH**
if(holder instanceof InfoItemHolder) { if(holder instanceof InfoItemHolder) {
if(header != null) { if(header != null) {
i--; i--;

View file

@ -1,6 +1,7 @@
package org.schabi.newpipe.report; package org.schabi.newpipe.report;
import android.content.Context; import android.content.Context;
import android.support.annotation.NonNull;
import org.acra.collector.CrashReportData; import org.acra.collector.CrashReportData;
import org.acra.sender.ReportSender; import org.acra.sender.ReportSender;
@ -30,9 +31,9 @@ import org.schabi.newpipe.R;
public class AcraReportSender implements ReportSender { public class AcraReportSender implements ReportSender {
@Override @Override
public void send(Context context, CrashReportData report) throws ReportSenderException { public void send(@NonNull Context context, @NonNull CrashReportData report) throws ReportSenderException {
ErrorActivity.reportError(context, report, ErrorActivity.reportError(context, report,
ErrorActivity.ErrorInfo.make(ErrorActivity.UI_ERROR,"none", ErrorActivity.ErrorInfo.make(UserAction.UI_ERROR,"none",
"App crash, UI failure", R.string.app_ui_crash)); "App crash, UI failure", R.string.app_ui_crash));
} }
} }

View file

@ -1,6 +1,7 @@
package org.schabi.newpipe.report; package org.schabi.newpipe.report;
import android.content.Context; import android.content.Context;
import android.support.annotation.NonNull;
import org.acra.config.ACRAConfiguration; import org.acra.config.ACRAConfiguration;
import org.acra.sender.ReportSender; import org.acra.sender.ReportSender;
@ -28,7 +29,8 @@ import org.schabi.newpipe.report.AcraReportSender;
*/ */
public class AcraReportSenderFactory implements ReportSenderFactory { public class AcraReportSenderFactory implements ReportSenderFactory {
public ReportSender create(Context context, ACRAConfiguration config) { @NonNull
public ReportSender create(@NonNull Context context, @NonNull ACRAConfiguration config) {
return new AcraReportSender(); return new AcraReportSender();
} }
} }

View file

@ -11,6 +11,8 @@ import android.os.Handler;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
import android.support.design.widget.Snackbar; import android.support.design.widget.Snackbar;
import android.support.v4.app.NavUtils; import android.support.v4.app.NavUtils;
import android.support.v7.app.ActionBar; import android.support.v7.app.ActionBar;
@ -71,24 +73,7 @@ public class ErrorActivity extends AppCompatActivity {
// BUNDLE TAGS // BUNDLE TAGS
public static final String ERROR_INFO = "error_info"; public static final String ERROR_INFO = "error_info";
public static final String ERROR_LIST = "error_list"; public static final String ERROR_LIST = "error_list";
// MESSAGE ID
public static final int SEARCHED = 0;
public static final int REQUESTED_STREAM = 1;
public static final int GET_SUGGESTIONS = 2;
public static final int SOMETHING_ELSE = 3;
public static final int USER_REPORT = 4;
public static final int LOAD_IMAGE = 5;
public static final int UI_ERROR = 6;
public static final int REQUESTED_CHANNEL = 7;
// MESSAGE STRING
public static final String SEARCHED_STRING = "searched";
public static final String REQUESTED_STREAM_STRING = "requested stream";
public static final String GET_SUGGESTIONS_STRING = "get suggestions";
public static final String SOMETHING_ELSE_STRING = "something";
public static final String USER_REPORT_STRING = "user report";
public static final String LOAD_IMAGE_STRING = "load image";
public static final String UI_ERROR_STRING = "ui error";
public static final String REQUESTED_CHANNEL_STRING = "requested channel";
public static final String ERROR_EMAIL_ADDRESS = "crashreport@newpipe.schabi.org"; public static final String ERROR_EMAIL_ADDRESS = "crashreport@newpipe.schabi.org";
public static final String ERROR_EMAIL_SUBJECT = "Exception in NewPipe " + BuildConfig.VERSION_NAME; public static final String ERROR_EMAIL_SUBJECT = "Exception in NewPipe " + BuildConfig.VERSION_NAME;
Thread globIpRangeThread; Thread globIpRangeThread;
@ -105,11 +90,11 @@ public class ErrorActivity extends AppCompatActivity {
private TextView errorMessageView; private TextView errorMessageView;
public static void reportUiError(final AppCompatActivity activity, final Throwable el) { public static void reportUiError(final AppCompatActivity activity, final Throwable el) {
reportError(activity, el, activity.getClass(), null, ErrorInfo.make(UI_ERROR, "none", "", R.string.app_ui_crash)); reportError(activity, el, activity.getClass(), null, ErrorInfo.make(UserAction.UI_ERROR, "none", "", R.string.app_ui_crash));
} }
public static void reportError(final Context context, final List<Throwable> el, public static void reportError(final Context context, final List<Throwable> el,
final Class returnAcitivty, View rootView, final ErrorInfo errorInfo) { final Class returnActivity, View rootView, final ErrorInfo errorInfo) {
if (rootView != null) { if (rootView != null) {
Snackbar.make(rootView, R.string.error_snackbar_message, Snackbar.LENGTH_LONG) Snackbar.make(rootView, R.string.error_snackbar_message, Snackbar.LENGTH_LONG)
@ -118,7 +103,7 @@ public class ErrorActivity extends AppCompatActivity {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
ActivityCommunicator ac = ActivityCommunicator.getCommunicator(); ActivityCommunicator ac = ActivityCommunicator.getCommunicator();
ac.returnActivity = returnAcitivty; ac.returnActivity = returnActivity;
Intent intent = new Intent(context, ErrorActivity.class); Intent intent = new Intent(context, ErrorActivity.class);
intent.putExtra(ERROR_INFO, errorInfo); intent.putExtra(ERROR_INFO, errorInfo);
intent.putExtra(ERROR_LIST, elToSl(el)); intent.putExtra(ERROR_LIST, elToSl(el));
@ -128,7 +113,7 @@ public class ErrorActivity extends AppCompatActivity {
}).show(); }).show();
} else { } else {
ActivityCommunicator ac = ActivityCommunicator.getCommunicator(); ActivityCommunicator ac = ActivityCommunicator.getCommunicator();
ac.returnActivity = returnAcitivty; ac.returnActivity = returnActivity;
Intent intent = new Intent(context, ErrorActivity.class); Intent intent = new Intent(context, ErrorActivity.class);
intent.putExtra(ERROR_INFO, errorInfo); intent.putExtra(ERROR_INFO, errorInfo);
intent.putExtra(ERROR_LIST, elToSl(el)); intent.putExtra(ERROR_LIST, elToSl(el));
@ -138,34 +123,34 @@ public class ErrorActivity extends AppCompatActivity {
} }
public static void reportError(final Context context, final Throwable e, public static void reportError(final Context context, final Throwable e,
final Class returnAcitivty, View rootView, final ErrorInfo errorInfo) { final Class returnActivity, View rootView, final ErrorInfo errorInfo) {
List<Throwable> el = null; List<Throwable> el = null;
if(e != null) { if(e != null) {
el = new Vector<>(); el = new Vector<>();
el.add(e); el.add(e);
} }
reportError(context, el, returnAcitivty, rootView, errorInfo); reportError(context, el, returnActivity, rootView, errorInfo);
} }
// async call // async call
public static void reportError(Handler handler, final Context context, final Throwable e, public static void reportError(Handler handler, final Context context, final Throwable e,
final Class returnAcitivty, final View rootView, final ErrorInfo errorInfo) { final Class returnActivity, final View rootView, final ErrorInfo errorInfo) {
List<Throwable> el = null; List<Throwable> el = null;
if(e != null) { if(e != null) {
el = new Vector<>(); el = new Vector<>();
el.add(e); el.add(e);
} }
reportError(handler, context, el, returnAcitivty, rootView, errorInfo); reportError(handler, context, el, returnActivity, rootView, errorInfo);
} }
// async call // async call
public static void reportError(Handler handler, final Context context, final List<Throwable> el, public static void reportError(Handler handler, final Context context, final List<Throwable> el,
final Class returnAcitivty, final View rootView, final ErrorInfo errorInfo) { final Class returnActivity, final View rootView, final ErrorInfo errorInfo) {
handler.post(new Runnable() { handler.post(new Runnable() {
@Override @Override
public void run() { public void run() {
reportError(context, el, returnAcitivty, rootView, errorInfo); reportError(context, el, returnActivity, rootView, errorInfo);
} }
}); });
} }
@ -232,7 +217,7 @@ public class ErrorActivity extends AppCompatActivity {
errorInfo = intent.getParcelableExtra(ERROR_INFO); errorInfo = intent.getParcelableExtra(ERROR_INFO);
errorList = intent.getStringArrayExtra(ERROR_LIST); errorList = intent.getStringArrayExtra(ERROR_LIST);
//importand add gurumeditaion // important add guru meditation
addGuruMeditaion(); addGuruMeditaion();
currentTimeStamp = getCurrentTimeStamp(); currentTimeStamp = getCurrentTimeStamp();
@ -250,7 +235,7 @@ public class ErrorActivity extends AppCompatActivity {
}); });
reportButton.setEnabled(false); reportButton.setEnabled(false);
globIpRangeThread = new Thread(new IpRagneRequester()); globIpRangeThread = new Thread(new IpRangeRequester());
globIpRangeThread.start(); globIpRangeThread.start();
// normal bugreport // normal bugreport
@ -308,17 +293,30 @@ public class ErrorActivity extends AppCompatActivity {
return text; return text;
} }
/**
* Get the checked activity.
* @param returnActivity the activity to return to
* @return the casted return activity or null
*/
@Nullable
static Class<? extends Activity> getReturnActivity(Class<?> returnActivity) {
Class<? extends Activity> checkedReturnActivity = null;
if (returnActivity != null){
if (Activity.class.isAssignableFrom(returnActivity)) {
checkedReturnActivity = returnActivity.asSubclass(Activity.class);
} else {
checkedReturnActivity = MainActivity.class;
}
}
return checkedReturnActivity;
}
private void goToReturnActivity() { private void goToReturnActivity() {
if (returnActivity == null) { Class<? extends Activity> checkedReturnActivity = getReturnActivity(returnActivity);
if (checkedReturnActivity == null) {
super.onBackPressed(); super.onBackPressed();
} else { } else {
Intent intent; Intent intent = new Intent(this, checkedReturnActivity);
if (returnActivity != null &&
returnActivity.isAssignableFrom(Activity.class)) {
intent = new Intent(this, returnActivity);
} else {
intent = new Intent(this, MainActivity.class);
}
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
NavUtils.navigateUpTo(this, intent); NavUtils.navigateUpTo(this, intent);
} }
@ -376,26 +374,11 @@ public class ErrorActivity extends AppCompatActivity {
return ""; return "";
} }
private String getUserActionString(int userAction) { private String getUserActionString(UserAction userAction) {
switch (userAction) { if(userAction == null) {
case REQUESTED_STREAM:
return REQUESTED_STREAM_STRING;
case SEARCHED:
return SEARCHED_STRING;
case GET_SUGGESTIONS:
return GET_SUGGESTIONS_STRING;
case SOMETHING_ELSE:
return SOMETHING_ELSE_STRING;
case USER_REPORT:
return USER_REPORT_STRING;
case LOAD_IMAGE:
return LOAD_IMAGE_STRING;
case UI_ERROR:
return UI_ERROR_STRING;
case REQUESTED_CHANNEL:
return REQUESTED_CHANNEL_STRING;
default:
return "Your description is in another castle."; return "Your description is in another castle.";
} else {
return userAction.getMessage();
} }
} }
@ -444,28 +427,28 @@ public class ErrorActivity extends AppCompatActivity {
return new ErrorInfo[size]; return new ErrorInfo[size];
} }
}; };
public int userAction; final public UserAction userAction;
public String request; final public String request;
public String serviceName; final public String serviceName;
public int message; @StringRes
final public int message;
public ErrorInfo() { private ErrorInfo(UserAction userAction, String serviceName, String request, @StringRes int message) {
this.userAction = userAction;
this.serviceName = serviceName;
this.request = request;
this.message = message;
} }
protected ErrorInfo(Parcel in) { protected ErrorInfo(Parcel in) {
this.userAction = in.readInt(); this.userAction = UserAction.valueOf(in.readString());
this.request = in.readString(); this.request = in.readString();
this.serviceName = in.readString(); this.serviceName = in.readString();
this.message = in.readInt(); this.message = in.readInt();
} }
public static ErrorInfo make(int userAction, String serviceName, String request, int message) { public static ErrorInfo make(UserAction userAction, String serviceName, String request, @StringRes int message) {
ErrorInfo info = new ErrorInfo(); return new ErrorInfo(userAction, serviceName, request, message);
info.userAction = userAction;
info.serviceName = serviceName;
info.request = request;
info.message = message;
return info;
} }
@Override @Override
@ -475,14 +458,14 @@ public class ErrorActivity extends AppCompatActivity {
@Override @Override
public void writeToParcel(Parcel dest, int flags) { public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(this.userAction); dest.writeString(this.userAction.name());
dest.writeString(this.request); dest.writeString(this.request);
dest.writeString(this.serviceName); dest.writeString(this.serviceName);
dest.writeInt(this.message); dest.writeInt(this.message);
} }
} }
private class IpRagneRequester implements Runnable { private class IpRangeRequester implements Runnable {
Handler h = new Handler(); Handler h = new Handler();
public void run() { public void run() {
String ipRange = "none"; String ipRange = "none";
@ -493,17 +476,16 @@ public class ErrorActivity extends AppCompatActivity {
ipRange = Parser.matchGroup1("([0-9]*\\.[0-9]*\\.)[0-9]*\\.[0-9]*", ip) ipRange = Parser.matchGroup1("([0-9]*\\.[0-9]*\\.)[0-9]*\\.[0-9]*", ip)
+ "0.0"; + "0.0";
} catch(Throwable e) { } catch(Throwable e) {
Log.d(TAG, "Error while error: could not get iprange"); Log.w(TAG, "Error while error: could not get iprange", e);
e.printStackTrace();
} finally { } finally {
h.post(new IpRageReturnRunnable(ipRange)); h.post(new IpRangeReturnRunnable(ipRange));
} }
} }
} }
private class IpRageReturnRunnable implements Runnable { private class IpRangeReturnRunnable implements Runnable {
String ipRange; String ipRange;
public IpRageReturnRunnable(String ipRange) { public IpRangeReturnRunnable(String ipRange) {
this.ipRange = ipRange; this.ipRange = ipRange;
} }
public void run() { public void run() {

View file

@ -0,0 +1,26 @@
package org.schabi.newpipe.report;
/**
* The user actions that can cause an error.
*/
public enum UserAction {
SEARCHED("searched"),
REQUESTED_STREAM("requested stream"),
GET_SUGGESTIONS("get suggestions"),
SOMETHING_ELSE("something"),
USER_REPORT("user report"),
LOAD_IMAGE("load image"),
UI_ERROR("ui error"),
REQUESTED_CHANNEL("requested channel");
private final String message;
UserAction(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
}

View file

@ -72,9 +72,7 @@ public class NewPipeSettings {
public static String getVideoDownloadPath(Context context) { public static String getVideoDownloadPath(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
final String key = context.getString(R.string.download_path_key); final String key = context.getString(R.string.download_path_key);
String downloadPath = prefs.getString(key, Environment.DIRECTORY_MOVIES); return prefs.getString(key, Environment.DIRECTORY_MOVIES);
return downloadPath;
} }
public static File getAudioDownloadFolder(Context context) { public static File getAudioDownloadFolder(Context context) {
@ -84,9 +82,7 @@ public class NewPipeSettings {
public static String getAudioDownloadPath(Context context) { public static String getAudioDownloadPath(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
final String key = context.getString(R.string.download_path_audio_key); final String key = context.getString(R.string.download_path_audio_key);
String downloadPath = prefs.getString(key, Environment.DIRECTORY_MUSIC); return prefs.getString(key, Environment.DIRECTORY_MUSIC);
return downloadPath;
} }
private static File getFolder(Context context, int keyID, String defaultDirectoryName) { private static File getFolder(Context context, int keyID, String defaultDirectoryName) {

View file

@ -12,6 +12,8 @@ import org.schabi.newpipe.report.ErrorActivity;
import java.io.IOException; import java.io.IOException;
import static org.schabi.newpipe.report.UserAction.REQUESTED_CHANNEL;
/** /**
* Extract {@link ChannelInfo} with {@link ChannelExtractor} from the given url of the given service * Extract {@link ChannelInfo} with {@link ChannelExtractor} from the given url of the given service
* *
@ -67,7 +69,7 @@ public class ChannelExtractorWorker extends ExtractorWorker {
ChannelExtractor extractor = getService().getChannelExtractorInstance(url, pageNumber); ChannelExtractor extractor = getService().getChannelExtractorInstance(url, pageNumber);
channelInfo = ChannelInfo.getInfo(extractor); channelInfo = ChannelInfo.getInfo(extractor);
if (!channelInfo.errors.isEmpty()) handleErrorsDuringExtraction(channelInfo.errors, ErrorActivity.REQUESTED_CHANNEL); if (!channelInfo.errors.isEmpty()) handleErrorsDuringExtraction(channelInfo.errors, REQUESTED_CHANNEL);
if (callback != null && channelInfo != null && !isInterrupted()) getHandler().post(new Runnable() { if (callback != null && channelInfo != null && !isInterrupted()) getHandler().post(new Runnable() {
@Override @Override
@ -93,7 +95,7 @@ public class ChannelExtractorWorker extends ExtractorWorker {
} }
}); });
} else if (exception instanceof ParsingException || exception instanceof ExtractionException) { } else if (exception instanceof ParsingException || exception instanceof ExtractionException) {
ErrorActivity.reportError(getHandler(), getContext(), exception, MainActivity.class, null, ErrorActivity.ErrorInfo.make(ErrorActivity.REQUESTED_CHANNEL, getServiceName(), url, R.string.parsing_error)); ErrorActivity.reportError(getHandler(), getContext(), exception, MainActivity.class, null, ErrorActivity.ErrorInfo.make(REQUESTED_CHANNEL, getServiceName(), url, R.string.parsing_error));
getHandler().post(new Runnable() { getHandler().post(new Runnable() {
@Override @Override
public void run() { public void run() {
@ -101,7 +103,7 @@ public class ChannelExtractorWorker extends ExtractorWorker {
} }
}); });
} else { } else {
ErrorActivity.reportError(getHandler(), getContext(), exception, MainActivity.class, null, ErrorActivity.ErrorInfo.make(ErrorActivity.REQUESTED_CHANNEL, getServiceName(), url, R.string.general_error)); ErrorActivity.reportError(getHandler(), getContext(), exception, MainActivity.class, null, ErrorActivity.ErrorInfo.make(REQUESTED_CHANNEL, getServiceName(), url, R.string.general_error));
getHandler().post(new Runnable() { getHandler().post(new Runnable() {
@Override @Override
public void run() { public void run() {

View file

@ -6,6 +6,7 @@ import android.util.Log;
import android.view.View; import android.view.View;
import org.schabi.newpipe.report.ErrorActivity; import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.UserAction;
import java.util.List; import java.util.List;
@ -59,14 +60,14 @@ public abstract class ExtractorWorker extends AbstractWorker {
* @param errorUserAction what action was the user performing during the error. * @param errorUserAction what action was the user performing during the error.
* (One of the {@link ErrorActivity}.REQUEST_* error (message) ids) * (One of the {@link ErrorActivity}.REQUEST_* error (message) ids)
*/ */
protected void handleErrorsDuringExtraction(List<Throwable> errorsList, int errorUserAction){ protected void handleErrorsDuringExtraction(List<Throwable> errorsList, UserAction errorUserAction){
String errorString = "<error id>"; String errorString = "<error id>";
switch (errorUserAction) { switch (errorUserAction) {
case ErrorActivity.REQUESTED_STREAM: case REQUESTED_STREAM:
errorString= ErrorActivity.REQUESTED_STREAM_STRING; errorString= errorUserAction.getMessage();
break; break;
case ErrorActivity.REQUESTED_CHANNEL: case REQUESTED_CHANNEL:
errorString= ErrorActivity.REQUESTED_CHANNEL_STRING; errorString= errorUserAction.getMessage();
break; break;
} }

View file

@ -13,10 +13,13 @@ import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
import org.schabi.newpipe.extractor.search.SearchEngine; import org.schabi.newpipe.extractor.search.SearchEngine;
import org.schabi.newpipe.extractor.search.SearchResult; import org.schabi.newpipe.extractor.search.SearchResult;
import org.schabi.newpipe.report.ErrorActivity; import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.UserAction;
import java.io.IOException; import java.io.IOException;
import java.util.EnumSet; import java.util.EnumSet;
import static org.schabi.newpipe.report.UserAction.*;
/** /**
* Return list of results based on a query * Return list of results based on a query
* *
@ -106,7 +109,7 @@ public class SearchWorker extends AbstractWorker {
}); });
} else if (exception instanceof ExtractionException) { } else if (exception instanceof ExtractionException) {
View rootView = getContext() instanceof Activity ? ((Activity) getContext()).findViewById(android.R.id.content) : null; View rootView = getContext() instanceof Activity ? ((Activity) getContext()).findViewById(android.R.id.content) : null;
ErrorActivity.reportError(getHandler(), getContext(), exception, null, rootView, ErrorActivity.ErrorInfo.make(ErrorActivity.SEARCHED, getServiceName(), query, R.string.parsing_error)); ErrorActivity.reportError(getHandler(), getContext(), exception, null, rootView, ErrorActivity.ErrorInfo.make(SEARCHED, getServiceName(), query, R.string.parsing_error));
getHandler().post(new Runnable() { getHandler().post(new Runnable() {
@Override @Override
public void run() { public void run() {
@ -115,7 +118,7 @@ public class SearchWorker extends AbstractWorker {
}); });
} else { } else {
View rootView = getContext() instanceof Activity ? ((Activity) getContext()).findViewById(android.R.id.content) : null; View rootView = getContext() instanceof Activity ? ((Activity) getContext()).findViewById(android.R.id.content) : null;
ErrorActivity.reportError(getHandler(), getContext(), exception, null, rootView, ErrorActivity.ErrorInfo.make(ErrorActivity.SEARCHED, getServiceName(), query, R.string.general_error)); ErrorActivity.reportError(getHandler(), getContext(), exception, null, rootView, ErrorActivity.ErrorInfo.make(SEARCHED, getServiceName(), query, R.string.general_error));
getHandler().post(new Runnable() { getHandler().post(new Runnable() {
@Override @Override
public void run() { public void run() {

View file

@ -10,9 +10,12 @@ import org.schabi.newpipe.extractor.services.youtube.YoutubeStreamExtractor;
import org.schabi.newpipe.extractor.stream_info.StreamExtractor; import org.schabi.newpipe.extractor.stream_info.StreamExtractor;
import org.schabi.newpipe.extractor.stream_info.StreamInfo; import org.schabi.newpipe.extractor.stream_info.StreamInfo;
import org.schabi.newpipe.report.ErrorActivity; import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.UserAction;
import java.io.IOException; import java.io.IOException;
import static org.schabi.newpipe.report.UserAction.*;
/** /**
* Extract {@link StreamInfo} with {@link StreamExtractor} from the given url of the given service * Extract {@link StreamInfo} with {@link StreamExtractor} from the given url of the given service
* *
@ -66,7 +69,7 @@ public class StreamExtractorWorker extends ExtractorWorker {
StreamExtractor streamExtractor = getService().getExtractorInstance(url); StreamExtractor streamExtractor = getService().getExtractorInstance(url);
streamInfo = StreamInfo.getVideoInfo(streamExtractor); streamInfo = StreamInfo.getVideoInfo(streamExtractor);
if (streamInfo != null && !streamInfo.errors.isEmpty()) handleErrorsDuringExtraction(streamInfo.errors, ErrorActivity.REQUESTED_STREAM); if (streamInfo != null && !streamInfo.errors.isEmpty()) handleErrorsDuringExtraction(streamInfo.errors, REQUESTED_STREAM);
if (callback != null && getHandler() != null && streamInfo != null && !isInterrupted()) getHandler().post(new Runnable() { if (callback != null && getHandler() != null && streamInfo != null && !isInterrupted()) getHandler().post(new Runnable() {
@Override @Override
@ -121,7 +124,7 @@ public class StreamExtractorWorker extends ExtractorWorker {
}); });
} else if (exception instanceof YoutubeStreamExtractor.DecryptException) { } else if (exception instanceof YoutubeStreamExtractor.DecryptException) {
// custom service related exceptions // custom service related exceptions
ErrorActivity.reportError(getHandler(), getContext(), exception, MainActivity.class, null, ErrorActivity.ErrorInfo.make(ErrorActivity.REQUESTED_STREAM, getServiceName(), url, R.string.youtube_signature_decryption_error)); ErrorActivity.reportError(getHandler(), getContext(), exception, MainActivity.class, null, ErrorActivity.ErrorInfo.make(REQUESTED_STREAM, getServiceName(), url, R.string.youtube_signature_decryption_error));
getHandler().post(new Runnable() { getHandler().post(new Runnable() {
@Override @Override
public void run() { public void run() {
@ -131,9 +134,9 @@ public class StreamExtractorWorker extends ExtractorWorker {
} else if (exception instanceof StreamInfo.StreamExctractException) { } else if (exception instanceof StreamInfo.StreamExctractException) {
if (!streamInfo.errors.isEmpty()) { if (!streamInfo.errors.isEmpty()) {
// !!! if this case ever kicks in someone gets kicked out !!! // !!! if this case ever kicks in someone gets kicked out !!!
ErrorActivity.reportError(getHandler(), getContext(), exception, MainActivity.class, null, ErrorActivity.ErrorInfo.make(ErrorActivity.REQUESTED_STREAM, getServiceName(), url, R.string.could_not_get_stream)); ErrorActivity.reportError(getHandler(), getContext(), exception, MainActivity.class, null, ErrorActivity.ErrorInfo.make(REQUESTED_STREAM, getServiceName(), url, R.string.could_not_get_stream));
} else { } else {
ErrorActivity.reportError(getHandler(), getContext(), streamInfo.errors, MainActivity.class, null, ErrorActivity.ErrorInfo.make(ErrorActivity.REQUESTED_STREAM, getServiceName(), url, R.string.could_not_get_stream)); ErrorActivity.reportError(getHandler(), getContext(), streamInfo.errors, MainActivity.class, null, ErrorActivity.ErrorInfo.make(REQUESTED_STREAM, getServiceName(), url, R.string.could_not_get_stream));
} }
getHandler().post(new Runnable() { getHandler().post(new Runnable() {
@ -143,7 +146,7 @@ public class StreamExtractorWorker extends ExtractorWorker {
} }
}); });
} else if (exception instanceof ParsingException) { } else if (exception instanceof ParsingException) {
ErrorActivity.reportError(getHandler(), getContext(), exception, MainActivity.class, null, ErrorActivity.ErrorInfo.make(ErrorActivity.REQUESTED_STREAM, getServiceName(), url, R.string.parsing_error)); ErrorActivity.reportError(getHandler(), getContext(), exception, MainActivity.class, null, ErrorActivity.ErrorInfo.make(REQUESTED_STREAM, getServiceName(), url, R.string.parsing_error));
getHandler().post(new Runnable() { getHandler().post(new Runnable() {
@Override @Override
public void run() { public void run() {
@ -151,7 +154,7 @@ public class StreamExtractorWorker extends ExtractorWorker {
} }
}); });
} else { } else {
ErrorActivity.reportError(getHandler(), getContext(), exception, MainActivity.class, null, ErrorActivity.ErrorInfo.make(ErrorActivity.REQUESTED_STREAM, getServiceName(), url, R.string.general_error)); ErrorActivity.reportError(getHandler(), getContext(), exception, MainActivity.class, null, ErrorActivity.ErrorInfo.make(REQUESTED_STREAM, getServiceName(), url, R.string.general_error));
getHandler().post(new Runnable() { getHandler().post(new Runnable() {
@Override @Override
public void run() { public void run() {

View file

@ -11,10 +11,13 @@ import org.schabi.newpipe.R;
import org.schabi.newpipe.extractor.SuggestionExtractor; import org.schabi.newpipe.extractor.SuggestionExtractor;
import org.schabi.newpipe.extractor.exceptions.ExtractionException; import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.report.ErrorActivity; import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.UserAction;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
import static org.schabi.newpipe.report.UserAction.*;
/** /**
* Worker that get suggestions based on the query * Worker that get suggestions based on the query
* *
@ -79,7 +82,7 @@ public class SuggestionWorker extends AbstractWorker {
if (exception instanceof ExtractionException) { if (exception instanceof ExtractionException) {
View rootView = getContext() instanceof Activity ? ((Activity) getContext()).findViewById(android.R.id.content) : null; View rootView = getContext() instanceof Activity ? ((Activity) getContext()).findViewById(android.R.id.content) : null;
ErrorActivity.reportError(getHandler(), getContext(), exception, null, rootView, ErrorActivity.ErrorInfo.make(ErrorActivity.GET_SUGGESTIONS, getServiceName(), query, R.string.parsing_error)); ErrorActivity.reportError(getHandler(), getContext(), exception, null, rootView, ErrorActivity.ErrorInfo.make(GET_SUGGESTIONS, getServiceName(), query, R.string.parsing_error));
getHandler().post(new Runnable() { getHandler().post(new Runnable() {
@Override @Override
public void run() { public void run() {
@ -95,7 +98,7 @@ public class SuggestionWorker extends AbstractWorker {
}); });
} else { } else {
View rootView = getContext() instanceof Activity ? ((Activity) getContext()).findViewById(android.R.id.content) : null; View rootView = getContext() instanceof Activity ? ((Activity) getContext()).findViewById(android.R.id.content) : null;
ErrorActivity.reportError(getHandler(), getContext(), exception, null, rootView, ErrorActivity.ErrorInfo.make(ErrorActivity.GET_SUGGESTIONS, getServiceName(), query, R.string.general_error)); ErrorActivity.reportError(getHandler(), getContext(), exception, null, rootView, ErrorActivity.ErrorInfo.make(GET_SUGGESTIONS, getServiceName(), query, R.string.general_error));
getHandler().post(new Runnable() { getHandler().post(new Runnable() {
@Override @Override
public void run() { public void run() {

View file

@ -9,12 +9,14 @@ public interface DownloadDataSource {
/** /**
* Load all missions * Load all missions
*
* @return a list of download missions * @return a list of download missions
*/ */
List<DownloadMission> loadMissions(); List<DownloadMission> loadMissions();
/** /**
* Add a downlaod mission to the storage * Add a download mission to the storage
*
* @param downloadMission the download mission to add * @param downloadMission the download mission to add
* @return the identifier of the mission * @return the identifier of the mission
*/ */
@ -22,6 +24,7 @@ public interface DownloadDataSource {
/** /**
* Update a download mission which exists in the storage * Update a download mission which exists in the storage
*
* @param downloadMission the download mission to update * @param downloadMission the download mission to update
* @throws IllegalArgumentException if the mission was not added to storage * @throws IllegalArgumentException if the mission was not added to storage
*/ */
@ -30,6 +33,7 @@ public interface DownloadDataSource {
/** /**
* Delete a download mission * Delete a download mission
*
* @param downloadMission the mission to delete * @param downloadMission the mission to delete
*/ */
void deleteMission(DownloadMission downloadMission); void deleteMission(DownloadMission downloadMission);

View file

@ -1,11 +1,11 @@
package us.shandian.giga.get; package us.shandian.giga.get;
public interface DownloadManager public interface DownloadManager {
{
int BLOCK_SIZE = 512 * 1024; int BLOCK_SIZE = 512 * 1024;
/** /**
* Start a new download mission * Start a new download mission
*
* @param url the url to download * @param url the url to download
* @param location the location * @param location the location
* @param name the name of the file to create * @param name the name of the file to create
@ -16,24 +16,28 @@ public interface DownloadManager
/** /**
* Resume the execution of a download mission. * Resume the execution of a download mission.
*
* @param id the identifier of the mission to resume. * @param id the identifier of the mission to resume.
*/ */
void resumeMission(int id); void resumeMission(int id);
/** /**
* Pause the execution of a download mission. * Pause the execution of a download mission.
*
* @param id the identifier of the mission to pause. * @param id the identifier of the mission to pause.
*/ */
void pauseMission(int id); void pauseMission(int id);
/** /**
* Deletes the mission from the downloaded list but keeps the downloaded file. * Deletes the mission from the downloaded list but keeps the downloaded file.
*
* @param id The mission identifier * @param id The mission identifier
*/ */
void deleteMission(int id); void deleteMission(int id);
/** /**
* Get the download mission by its identifier * Get the download mission by its identifier
*
* @param id the identifier of the download mission * @param id the identifier of the download mission
* @return the download mission or null if the mission doesn't exist * @return the download mission or null if the mission doesn't exist
*/ */
@ -41,6 +45,7 @@ public interface DownloadManager
/** /**
* Get the number of download missions. * Get the number of download missions.
*
* @return the number of download missions. * @return the number of download missions.
*/ */
int getCount(); int getCount();

View file

@ -18,10 +18,10 @@ import java.util.Comparator;
import java.util.List; import java.util.List;
import us.shandian.giga.util.Utility; import us.shandian.giga.util.Utility;
import static org.schabi.newpipe.BuildConfig.DEBUG; import static org.schabi.newpipe.BuildConfig.DEBUG;
public class DownloadManagerImpl implements DownloadManager public class DownloadManagerImpl implements DownloadManager {
{
private static final String TAG = DownloadManagerImpl.class.getSimpleName(); private static final String TAG = DownloadManagerImpl.class.getSimpleName();
private final DownloadDataSource mDownloadDataSource; private final DownloadDataSource mDownloadDataSource;
@ -29,6 +29,7 @@ public class DownloadManagerImpl implements DownloadManager
/** /**
* Create a new instance * Create a new instance
*
* @param searchLocations the directories to search for unfinished downloads * @param searchLocations the directories to search for unfinished downloads
* @param downloadDataSource the data source for finished downloads * @param downloadDataSource the data source for finished downloads
*/ */
@ -40,18 +41,18 @@ public class DownloadManagerImpl implements DownloadManager
@Override @Override
public int startMission(String url, String location, String name, boolean isAudio, int threads) { public int startMission(String url, String location, String name, boolean isAudio, int threads) {
DownloadMission existingMission = getMissionByLocation(location, name); DownloadMission existingMission = getMissionByLocation(location, name);
if(existingMission != null) { if (existingMission != null) {
// Already downloaded or downloading // Already downloaded or downloading
if(existingMission.finished) { if (existingMission.finished) {
// Overwrite mission // Overwrite mission
deleteMission(mMissions.indexOf(existingMission)); deleteMission(mMissions.indexOf(existingMission));
} else { } else {
// Rename file (?) // Rename file (?)
try { try {
name = generateUniqueName(location, name); name = generateUniqueName(location, name);
}catch (Exception e) { } catch (Exception e) {
Log.e(TAG, "Unable to generate unique name", e); Log.e(TAG, "Unable to generate unique name", e);
name = System.currentTimeMillis() + name ; name = System.currentTimeMillis() + name;
Log.i(TAG, "Using " + name); Log.i(TAG, "Using " + name);
} }
} }
@ -84,7 +85,7 @@ public class DownloadManagerImpl implements DownloadManager
@Override @Override
public void deleteMission(int i) { public void deleteMission(int i) {
DownloadMission mission = getMission(i); DownloadMission mission = getMission(i);
if(mission.finished) { if (mission.finished) {
mDownloadDataSource.deleteMission(mission); mDownloadDataSource.deleteMission(mission);
} }
mission.delete(); mission.delete();
@ -94,7 +95,7 @@ public class DownloadManagerImpl implements DownloadManager
private void loadMissions(Iterable<String> searchLocations) { private void loadMissions(Iterable<String> searchLocations) {
mMissions.clear(); mMissions.clear();
loadFinishedMissions(); loadFinishedMissions();
for(String location: searchLocations) { for (String location : searchLocations) {
loadMissions(location); loadMissions(location);
} }
@ -106,7 +107,7 @@ public class DownloadManagerImpl implements DownloadManager
*/ */
private void loadFinishedMissions() { private void loadFinishedMissions() {
List<DownloadMission> finishedMissions = mDownloadDataSource.loadMissions(); List<DownloadMission> finishedMissions = mDownloadDataSource.loadMissions();
if(finishedMissions == null) { if (finishedMissions == null) {
finishedMissions = new ArrayList<>(); finishedMissions = new ArrayList<>();
} }
// Ensure its sorted // Ensure its sorted
@ -117,10 +118,10 @@ public class DownloadManagerImpl implements DownloadManager
} }
}); });
mMissions.ensureCapacity(mMissions.size() + finishedMissions.size()); mMissions.ensureCapacity(mMissions.size() + finishedMissions.size());
for(DownloadMission mission: finishedMissions) { for (DownloadMission mission : finishedMissions) {
File downloadedFile = mission.getDownloadedFile(); File downloadedFile = mission.getDownloadedFile();
if(!downloadedFile.isFile()) { if (!downloadedFile.isFile()) {
if(DEBUG) { if (DEBUG) {
Log.d(TAG, "downloaded file removed: " + downloadedFile.getAbsolutePath()); Log.d(TAG, "downloaded file removed: " + downloadedFile.getAbsolutePath());
} }
mDownloadDataSource.deleteMission(mission); mDownloadDataSource.deleteMission(mission);
@ -140,7 +141,7 @@ public class DownloadManagerImpl implements DownloadManager
if (f.exists() && f.isDirectory()) { if (f.exists() && f.isDirectory()) {
File[] subs = f.listFiles(); File[] subs = f.listFiles();
if(subs == null) { if (subs == null) {
Log.e(TAG, "listFiles() returned null"); Log.e(TAG, "listFiles() returned null");
return; return;
} }
@ -158,7 +159,7 @@ public class DownloadManagerImpl implements DownloadManager
DownloadMission mis = new Gson().fromJson(str, DownloadMission.class); DownloadMission mis = new Gson().fromJson(str, DownloadMission.class);
if (mis.finished) { if (mis.finished) {
if(!sub.delete()) { if (!sub.delete()) {
Log.w(TAG, "Unable to delete .giga file: " + sub.getPath()); Log.w(TAG, "Unable to delete .giga file: " + sub.getPath());
} }
continue; continue;
@ -205,13 +206,16 @@ public class DownloadManagerImpl implements DownloadManager
/** /**
* Get a mission by its location and name * Get a mission by its location and name
*
* @param location the location * @param location the location
* @param name the name * @param name the name
* @return the mission or null if no such mission exists * @return the mission or null if no such mission exists
*/ */
private @Nullable DownloadMission getMissionByLocation(String location, String name) { private
for(DownloadMission mission: mMissions) { @Nullable
if(location.equals(mission.location) && name.equals(mission.name)) { DownloadMission getMissionByLocation(String location, String name) {
for (DownloadMission mission : mMissions) {
if (location.equals(mission.location) && name.equals(mission.name)) {
return mission; return mission;
} }
} }
@ -220,7 +224,7 @@ public class DownloadManagerImpl implements DownloadManager
/** /**
* Splits the filename into name and extension * Splits the filename into name and extension
* * <p>
* Dots are ignored if they appear: not at all, at the beginning of the file, * Dots are ignored if they appear: not at all, at the beginning of the file,
* at the end of the file * at the end of the file
* *
@ -229,7 +233,7 @@ public class DownloadManagerImpl implements DownloadManager
*/ */
private static String[] splitName(String name) { private static String[] splitName(String name) {
int dotIndex = name.lastIndexOf('.'); int dotIndex = name.lastIndexOf('.');
if(dotIndex <= 0 || (dotIndex == name.length() - 1)) { if (dotIndex <= 0 || (dotIndex == name.length() - 1)) {
return new String[]{name, ""}; return new String[]{name, ""};
} else { } else {
return new String[]{name.substring(0, dotIndex), name.substring(dotIndex + 1)}; return new String[]{name.substring(0, dotIndex), name.substring(dotIndex + 1)};
@ -238,8 +242,9 @@ public class DownloadManagerImpl implements DownloadManager
/** /**
* Generates a unique file name. * Generates a unique file name.
* * <p>
* e.g. "myname (1).txt" if the name "myname.txt" exists. * e.g. "myname (1).txt" if the name "myname.txt" exists.
*
* @param location the location (to check for existing files) * @param location the location (to check for existing files)
* @param name the name of the file * @param name the name of the file
* @return the unique file name * @return the unique file name
@ -247,10 +252,10 @@ public class DownloadManagerImpl implements DownloadManager
* @throws SecurityException if the location is not readable * @throws SecurityException if the location is not readable
*/ */
private static String generateUniqueName(String location, String name) { private static String generateUniqueName(String location, String name) {
if(location == null) throw new NullPointerException("location is null"); if (location == null) throw new NullPointerException("location is null");
if(name == null) throw new NullPointerException("name is null"); if (name == null) throw new NullPointerException("name is null");
File destination = new File(location); File destination = new File(location);
if(!destination.isDirectory()) { if (!destination.isDirectory()) {
throw new IllegalArgumentException("location is not a directory: " + location); throw new IllegalArgumentException("location is not a directory: " + location);
} }
final String[] nameParts = splitName(name); final String[] nameParts = splitName(name);
@ -266,7 +271,7 @@ public class DownloadManagerImpl implements DownloadManager
do { do {
newName = nameParts[0] + " (" + downloadIndex + ")." + nameParts[1]; newName = nameParts[0] + " (" + downloadIndex + ")." + nameParts[1];
++downloadIndex; ++downloadIndex;
if(downloadIndex == 1000) { // Probably an error on our side if (downloadIndex == 1000) { // Probably an error on our side
throw new RuntimeException("Too many existing files"); throw new RuntimeException("Too many existing files");
} }
} while (Arrays.binarySearch(existingName, newName) >= 0); } while (Arrays.binarySearch(existingName, newName) >= 0);
@ -346,7 +351,7 @@ public class DownloadManagerImpl implements DownloadManager
private final DownloadMission mMission; private final DownloadMission mMission;
private MissionListener(DownloadMission mission) { private MissionListener(DownloadMission mission) {
if(mission == null) throw new NullPointerException("mission is null"); if (mission == null) throw new NullPointerException("mission is null");
// Could the mission be passed in onFinish()? // Could the mission be passed in onFinish()?
mMission = mission; mMission = mission;
} }

View file

@ -18,15 +18,16 @@ import us.shandian.giga.util.Utility;
import static org.schabi.newpipe.BuildConfig.DEBUG; import static org.schabi.newpipe.BuildConfig.DEBUG;
public class DownloadMission public class DownloadMission {
{
private static final String TAG = DownloadMission.class.getSimpleName(); private static final String TAG = DownloadMission.class.getSimpleName();
public interface MissionListener { public interface MissionListener {
HashMap<MissionListener, Handler> handlerStore = new HashMap<>(); HashMap<MissionListener, Handler> handlerStore = new HashMap<>();
void onProgressUpdate(DownloadMission downloadMission, long done, long total); void onProgressUpdate(DownloadMission downloadMission, long done, long total);
void onFinish(DownloadMission downloadMission); void onFinish(DownloadMission downloadMission);
void onError(DownloadMission downloadMission, int errCode); void onError(DownloadMission downloadMission, int errCode);
} }
@ -84,12 +85,12 @@ public class DownloadMission
} }
public DownloadMission(String name, String url, String location) { public DownloadMission(String name, String url, String location) {
if(name == null) throw new NullPointerException("name is null"); if (name == null) throw new NullPointerException("name is null");
if(name.isEmpty()) throw new IllegalArgumentException("name is empty"); if (name.isEmpty()) throw new IllegalArgumentException("name is empty");
if(url == null) throw new NullPointerException("url is null"); if (url == null) throw new NullPointerException("url is null");
if(url.isEmpty()) throw new IllegalArgumentException("url is empty"); if (url.isEmpty()) throw new IllegalArgumentException("url is empty");
if(location == null) throw new NullPointerException("location is null"); if (location == null) throw new NullPointerException("location is null");
if(location.isEmpty()) throw new IllegalArgumentException("location is empty"); if (location.isEmpty()) throw new IllegalArgumentException("location is empty");
this.url = url; this.url = url;
this.name = name; this.name = name;
this.location = location; this.location = location;
@ -97,13 +98,14 @@ public class DownloadMission
private void checkBlock(long block) { private void checkBlock(long block) {
if(block < 0 || block >= blocks) { if (block < 0 || block >= blocks) {
throw new IllegalArgumentException("illegal block identifier"); throw new IllegalArgumentException("illegal block identifier");
} }
} }
/** /**
* Check if a block is reserved * Check if a block is reserved
*
* @param block the block identifier * @param block the block identifier
* @return true if the block is reserved and false if otherwise * @return true if the block is reserved and false if otherwise
*/ */
@ -121,6 +123,7 @@ public class DownloadMission
/** /**
* Set the download position of the file * Set the download position of the file
*
* @param threadId the identifier of the thread * @param threadId the identifier of the thread
* @param position the download position of the thread * @param position the download position of the thread
*/ */
@ -130,6 +133,7 @@ public class DownloadMission
/** /**
* Get the position of a thread * Get the position of a thread
*
* @param threadId the identifier of the thread * @param threadId the identifier of the thread
* @return the position for the thread * @return the position for the thread
*/ */
@ -154,7 +158,7 @@ public class DownloadMission
writeThisToFile(); writeThisToFile();
} }
for (WeakReference<MissionListener> ref: mListeners) { for (WeakReference<MissionListener> ref : mListeners) {
final MissionListener listener = ref.get(); final MissionListener listener = ref.get();
if (listener != null) { if (listener != null) {
MissionListener.handlerStore.get(listener).post(new Runnable() { MissionListener.handlerStore.get(listener).post(new Runnable() {
@ -234,8 +238,7 @@ public class DownloadMission
for (Iterator<WeakReference<MissionListener>> iterator = mListeners.iterator(); for (Iterator<WeakReference<MissionListener>> iterator = mListeners.iterator();
iterator.hasNext(); ) { iterator.hasNext(); ) {
WeakReference<MissionListener> weakRef = iterator.next(); WeakReference<MissionListener> weakRef = iterator.next();
if (listener!=null && listener == weakRef.get()) if (listener != null && listener == weakRef.get()) {
{
iterator.remove(); iterator.remove();
} }
} }
@ -315,6 +318,7 @@ public class DownloadMission
/** /**
* Get the path of the meta file * Get the path of the meta file
*
* @return the path to the meta file * @return the path to the meta file
*/ */
private String getMetaFilename() { private String getMetaFilename() {

View file

@ -13,15 +13,14 @@ import static org.schabi.newpipe.BuildConfig.DEBUG;
* Runnable to download blocks of a file until the file is completely downloaded, * Runnable to download blocks of a file until the file is completely downloaded,
* an error occurs or the process is stopped. * an error occurs or the process is stopped.
*/ */
public class DownloadRunnable implements Runnable public class DownloadRunnable implements Runnable {
{
private static final String TAG = DownloadRunnable.class.getSimpleName(); private static final String TAG = DownloadRunnable.class.getSimpleName();
private final DownloadMission mMission; private final DownloadMission mMission;
private final int mId; private final int mId;
public DownloadRunnable(DownloadMission mission, int id) { public DownloadRunnable(DownloadMission mission, int id) {
if(mission == null) throw new NullPointerException("mission is null"); if (mission == null) throw new NullPointerException("mission is null");
mMission = mission; mMission = mission;
mId = id; mId = id;
} }

View file

@ -6,13 +6,12 @@ import java.net.HttpURLConnection;
import java.net.URL; import java.net.URL;
// Single-threaded fallback mode // Single-threaded fallback mode
public class DownloadRunnableFallback implements Runnable public class DownloadRunnableFallback implements Runnable {
{
private final DownloadMission mMission; private final DownloadMission mMission;
//private int mId; //private int mId;
public DownloadRunnableFallback(DownloadMission mission) { public DownloadRunnableFallback(DownloadMission mission) {
if(mission == null) throw new NullPointerException("mission is null"); if (mission == null) throw new NullPointerException("mission is null");
//mId = id; //mId = id;
mMission = mission; mMission = mission;
} }

View file

@ -64,6 +64,7 @@ public class DownloadMissionSQLiteHelper extends SQLiteOpenHelper {
/** /**
* Returns all values of the download mission as ContentValues. * Returns all values of the download mission as ContentValues.
*
* @param downloadMission the download mission * @param downloadMission the download mission
* @return the content values * @return the content values
*/ */
@ -88,7 +89,7 @@ public class DownloadMissionSQLiteHelper extends SQLiteOpenHelper {
} }
public static DownloadMission getMissionFromCursor(Cursor cursor) { public static DownloadMission getMissionFromCursor(Cursor cursor) {
if(cursor == null) throw new NullPointerException("cursor is null"); if (cursor == null) throw new NullPointerException("cursor is null");
int pos; int pos;
String name = cursor.getString(cursor.getColumnIndexOrThrow(KEY_NAME)); String name = cursor.getString(cursor.getColumnIndexOrThrow(KEY_NAME));
String location = cursor.getString(cursor.getColumnIndexOrThrow(KEY_LOCATION)); String location = cursor.getString(cursor.getColumnIndexOrThrow(KEY_LOCATION));

View file

@ -37,7 +37,7 @@ public class SQLiteDownloadDataSource implements DownloadDataSource {
null, null, null, DownloadMissionSQLiteHelper.KEY_TIMESTAMP); null, null, null, DownloadMissionSQLiteHelper.KEY_TIMESTAMP);
int count = cursor.getCount(); int count = cursor.getCount();
if(count == 0) return new ArrayList<>(); if (count == 0) return new ArrayList<>();
result = new ArrayList<>(count); result = new ArrayList<>(count);
while (cursor.moveToNext()) { while (cursor.moveToNext()) {
result.add(DownloadMissionSQLiteHelper.getMissionFromCursor(cursor)); result.add(DownloadMissionSQLiteHelper.getMissionFromCursor(cursor));
@ -47,7 +47,7 @@ public class SQLiteDownloadDataSource implements DownloadDataSource {
@Override @Override
public void addMission(DownloadMission downloadMission) { public void addMission(DownloadMission downloadMission) {
if(downloadMission == null) throw new NullPointerException("downloadMission is null"); if (downloadMission == null) throw new NullPointerException("downloadMission is null");
SQLiteDatabase database = downloadMissionSQLiteHelper.getWritableDatabase(); SQLiteDatabase database = downloadMissionSQLiteHelper.getWritableDatabase();
ContentValues values = DownloadMissionSQLiteHelper.getValuesOfMission(downloadMission); ContentValues values = DownloadMissionSQLiteHelper.getValuesOfMission(downloadMission);
database.insert(MISSIONS_TABLE_NAME, null, values); database.insert(MISSIONS_TABLE_NAME, null, values);
@ -55,21 +55,21 @@ public class SQLiteDownloadDataSource implements DownloadDataSource {
@Override @Override
public void updateMission(DownloadMission downloadMission) { public void updateMission(DownloadMission downloadMission) {
if(downloadMission == null) throw new NullPointerException("downloadMission is null"); if (downloadMission == null) throw new NullPointerException("downloadMission is null");
SQLiteDatabase database = downloadMissionSQLiteHelper.getWritableDatabase(); SQLiteDatabase database = downloadMissionSQLiteHelper.getWritableDatabase();
ContentValues values = DownloadMissionSQLiteHelper.getValuesOfMission(downloadMission); ContentValues values = DownloadMissionSQLiteHelper.getValuesOfMission(downloadMission);
String whereClause = KEY_LOCATION+ " = ? AND " + String whereClause = KEY_LOCATION + " = ? AND " +
KEY_NAME + " = ?"; KEY_NAME + " = ?";
int rowsAffected = database.update(MISSIONS_TABLE_NAME, values, int rowsAffected = database.update(MISSIONS_TABLE_NAME, values,
whereClause, new String[]{downloadMission.location, downloadMission.name}); whereClause, new String[]{downloadMission.location, downloadMission.name});
if(rowsAffected != 1) { if (rowsAffected != 1) {
Log.e(TAG, "Expected 1 row to be affected by update but got " + rowsAffected); Log.e(TAG, "Expected 1 row to be affected by update but got " + rowsAffected);
} }
} }
@Override @Override
public void deleteMission(DownloadMission downloadMission) { public void deleteMission(DownloadMission downloadMission) {
if(downloadMission == null) throw new NullPointerException("downloadMission is null"); if (downloadMission == null) throw new NullPointerException("downloadMission is null");
SQLiteDatabase database = downloadMissionSQLiteHelper.getWritableDatabase(); SQLiteDatabase database = downloadMissionSQLiteHelper.getWritableDatabase();
database.delete(MISSIONS_TABLE_NAME, database.delete(MISSIONS_TABLE_NAME,
KEY_LOCATION + " = ? AND " + KEY_LOCATION + " = ? AND " +

View file

@ -6,7 +6,6 @@ import android.app.PendingIntent;
import android.app.Service; import android.app.Service;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.ServiceConnection;
import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.net.Uri; import android.net.Uri;
@ -16,6 +15,7 @@ import android.os.HandlerThread;
import android.os.IBinder; import android.os.IBinder;
import android.os.Message; import android.os.Message;
import android.support.v4.app.NotificationCompat.Builder; import android.support.v4.app.NotificationCompat.Builder;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.PermissionChecker; import android.support.v4.content.PermissionChecker;
import android.util.Log; import android.util.Log;
import android.widget.Toast; import android.widget.Toast;
@ -34,8 +34,7 @@ import us.shandian.giga.get.sqlite.SQLiteDownloadDataSource;
import static org.schabi.newpipe.BuildConfig.DEBUG; import static org.schabi.newpipe.BuildConfig.DEBUG;
public class DownloadManagerService extends Service public class DownloadManagerService extends Service {
{
private static final String TAG = DownloadManagerService.class.getSimpleName(); private static final String TAG = DownloadManagerService.class.getSimpleName();
@ -58,7 +57,6 @@ public class DownloadManagerService extends Service
private DownloadDataSource mDataSource; private DownloadDataSource mDataSource;
private MissionListener missionListener = new MissionListener(); private MissionListener missionListener = new MissionListener();
@ -77,7 +75,7 @@ public class DownloadManagerService extends Service
} }
mBinder = new DMBinder(); mBinder = new DMBinder();
if(mDataSource == null) { if (mDataSource == null) {
mDataSource = new SQLiteDownloadDataSource(this); mDataSource = new SQLiteDownloadDataSource(this);
} }
if (mManager == null) { if (mManager == null) {
@ -95,7 +93,7 @@ public class DownloadManagerService extends Service
i.setAction(Intent.ACTION_MAIN); i.setAction(Intent.ACTION_MAIN);
i.setClass(this, DownloadActivity.class); i.setClass(this, DownloadActivity.class);
Drawable icon = this.getResources().getDrawable(R.mipmap.ic_launcher); Drawable icon = ContextCompat.getDrawable(this, R.mipmap.ic_launcher);
Builder builder = new Builder(this) Builder builder = new Builder(this)
.setContentIntent(PendingIntent.getActivity(this, 0, i, 0)) .setContentIntent(PendingIntent.getActivity(this, 0, i, 0))
@ -159,7 +157,7 @@ public class DownloadManagerService extends Service
} }
Log.i(TAG, "Got intent: " + intent); Log.i(TAG, "Got intent: " + intent);
String action = intent.getAction(); String action = intent.getAction();
if(action != null && action.equals(Intent.ACTION_RUN)) { if (action != null && action.equals(Intent.ACTION_RUN)) {
String name = intent.getStringExtra(EXTRA_NAME); String name = intent.getStringExtra(EXTRA_NAME);
String location = intent.getStringExtra(EXTRA_LOCATION); String location = intent.getStringExtra(EXTRA_LOCATION);
int threads = intent.getIntExtra(EXTRA_THREADS, 1); int threads = intent.getIntExtra(EXTRA_THREADS, 1);
@ -190,13 +188,13 @@ public class DownloadManagerService extends Service
int permissionCheck; int permissionCheck;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) { if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
permissionCheck = PermissionChecker.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE); permissionCheck = PermissionChecker.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE);
if(permissionCheck == PermissionChecker.PERMISSION_DENIED) { if (permissionCheck == PermissionChecker.PERMISSION_DENIED) {
Toast.makeText(this, "Permission denied (read)", Toast.LENGTH_SHORT).show(); Toast.makeText(this, "Permission denied (read)", Toast.LENGTH_SHORT).show();
} }
} }
permissionCheck = PermissionChecker.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE); permissionCheck = PermissionChecker.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if(permissionCheck == PermissionChecker.PERMISSION_DENIED) { if (permissionCheck == PermissionChecker.PERMISSION_DENIED) {
Toast.makeText(this, "Permission denied (write)", Toast.LENGTH_SHORT).show(); Toast.makeText(this, "Permission denied (write)", Toast.LENGTH_SHORT).show();
} }
@ -227,7 +225,7 @@ public class DownloadManagerService extends Service
} }
class MissionListener implements DownloadMission.MissionListener { private class MissionListener implements DownloadMission.MissionListener {
@Override @Override
public void onProgressUpdate(DownloadMission downloadMission, long done, long total) { public void onProgressUpdate(DownloadMission downloadMission, long done, long total) {
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();

View file

@ -7,6 +7,8 @@ import android.net.Uri;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Build; import android.os.Build;
import android.support.v4.content.FileProvider; import android.support.v4.content.FileProvider;
import android.support.v4.view.ViewCompat;
import android.support.v7.widget.RecyclerView;
import android.util.Log; import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
@ -18,14 +20,13 @@ import android.widget.ImageView;
import android.widget.PopupMenu; import android.widget.PopupMenu;
import android.widget.TextView; import android.widget.TextView;
import android.support.v7.widget.RecyclerView; import org.schabi.newpipe.R;
import java.io.File; import java.io.File;
import java.util.HashMap; import java.util.HashMap;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import org.schabi.newpipe.R;
import us.shandian.giga.get.DownloadManager; import us.shandian.giga.get.DownloadManager;
import us.shandian.giga.get.DownloadMission; import us.shandian.giga.get.DownloadMission;
import us.shandian.giga.service.DownloadManagerService; import us.shandian.giga.service.DownloadManagerService;
@ -35,8 +36,7 @@ import us.shandian.giga.util.Utility;
import static android.content.Intent.FLAG_GRANT_PREFIX_URI_PERMISSION; import static android.content.Intent.FLAG_GRANT_PREFIX_URI_PERMISSION;
import static android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION; import static android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION;
public class MissionAdapter extends RecyclerView.Adapter<MissionAdapter.ViewHolder> public class MissionAdapter extends RecyclerView.Adapter<MissionAdapter.ViewHolder> {
{
private static final Map<Integer, String> ALGORITHMS = new HashMap<>(); private static final Map<Integer, String> ALGORITHMS = new HashMap<>();
private static final String TAG = "MissionAdapter"; private static final String TAG = "MissionAdapter";
@ -108,7 +108,7 @@ public class MissionAdapter extends RecyclerView.Adapter<MissionAdapter.ViewHold
h.size.setText(Utility.formatBytes(ms.length)); h.size.setText(Utility.formatBytes(ms.length));
h.progress = new ProgressDrawable(mContext, Utility.getBackgroundForFileType(type), Utility.getForegroundForFileType(type)); h.progress = new ProgressDrawable(mContext, Utility.getBackgroundForFileType(type), Utility.getForegroundForFileType(type));
h.bkg.setBackgroundDrawable(h.progress); ViewCompat.setBackground(h.bkg, h.progress);
h.observer = new MissionObserver(this, h); h.observer = new MissionObserver(this, h);
ms.addListener(h.observer); ms.addListener(h.observer);
@ -285,33 +285,6 @@ public class MissionAdapter extends RecyclerView.Adapter<MissionAdapter.ViewHold
mContext.startActivity(intent); mContext.startActivity(intent);
} }
private class ChecksumTask extends AsyncTask<String, Void, String> {
ProgressDialog prog;
@Override
protected void onPreExecute() {
super.onPreExecute();
// Create dialog
prog = new ProgressDialog(mContext);
prog.setCancelable(false);
prog.setMessage(mContext.getString(R.string.msg_wait));
prog.show();
}
@Override
protected String doInBackground(String... params) {
return Utility.checksum(params[0], params[1]);
}
@Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
prog.dismiss();
Utility.copyToClipboard(mContext, result);
}
}
static class ViewHolder extends RecyclerView.ViewHolder { static class ViewHolder extends RecyclerView.ViewHolder {
public DownloadMission mission; public DownloadMission mission;
public int position; public int position;
@ -332,12 +305,12 @@ public class MissionAdapter extends RecyclerView.Adapter<MissionAdapter.ViewHold
public ViewHolder(View v) { public ViewHolder(View v) {
super(v); super(v);
status = Utility.findViewById(v, R.id.item_status); status = (TextView) v.findViewById(R.id.item_status);
icon = Utility.findViewById(v, R.id.item_icon); icon = (ImageView) v.findViewById(R.id.item_icon);
name = Utility.findViewById(v, R.id.item_name); name = (TextView) v.findViewById(R.id.item_name);
size = Utility.findViewById(v, R.id.item_size); size = (TextView) v.findViewById(R.id.item_size);
bkg = Utility.findViewById(v, R.id.item_bkg); bkg = v.findViewById(R.id.item_bkg);
menu = Utility.findViewById(v, R.id.item_more); menu = (ImageView) v.findViewById(R.id.item_more);
} }
} }
@ -372,4 +345,31 @@ public class MissionAdapter extends RecyclerView.Adapter<MissionAdapter.ViewHold
} }
} }
private class ChecksumTask extends AsyncTask<String, Void, String> {
ProgressDialog prog;
@Override
protected void onPreExecute() {
super.onPreExecute();
// Create dialog
prog = new ProgressDialog(mContext);
prog.setCancelable(false);
prog.setMessage(mContext.getString(R.string.msg_wait));
prog.show();
}
@Override
protected String doInBackground(String... params) {
return Utility.checksum(params[0], params[1]);
}
@Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
prog.dismiss();
Utility.copyToClipboard(mContext, result);
}
}
} }

View file

@ -6,14 +6,16 @@ import android.graphics.ColorFilter;
import android.graphics.Paint; import android.graphics.Paint;
import android.graphics.PixelFormat; import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.support.annotation.ColorRes;
import android.support.annotation.NonNull;
import android.support.v4.content.ContextCompat;
public class ProgressDrawable extends Drawable public class ProgressDrawable extends Drawable {
{
private float mProgress; private float mProgress;
private int mBackgroundColor, mForegroundColor; private int mBackgroundColor, mForegroundColor;
public ProgressDrawable(Context context, int background, int foreground) { public ProgressDrawable(Context context, @ColorRes int background, @ColorRes int foreground) {
this(context.getResources().getColor(background), context.getResources().getColor(foreground)); this(ContextCompat.getColor(context, background), ContextCompat.getColor(context, foreground));
} }
public ProgressDrawable(int background, int foreground) { public ProgressDrawable(int background, int foreground) {
@ -27,7 +29,7 @@ public class ProgressDrawable extends Drawable
} }
@Override @Override
public void draw(Canvas canvas) { public void draw(@NonNull Canvas canvas) {
int width = canvas.getWidth(); int width = canvas.getWidth();
int height = canvas.getHeight(); int height = canvas.getHeight();

View file

@ -1,15 +1,12 @@
package us.shandian.giga.ui.common; package us.shandian.giga.ui.common;
import android.os.Bundle; import android.os.Bundle;
import android.support.v7.app.ActionBarActivity; import android.support.v7.app.ActionBarActivity;
import android.support.v7.widget.Toolbar; import android.support.v7.widget.Toolbar;
import org.schabi.newpipe.R; import org.schabi.newpipe.R;
import us.shandian.giga.util.Utility;
public abstract class ToolbarActivity extends ActionBarActivity public abstract class ToolbarActivity extends ActionBarActivity {
{
protected Toolbar mToolbar; protected Toolbar mToolbar;
@Override @Override
@ -17,7 +14,7 @@ public abstract class ToolbarActivity extends ActionBarActivity
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(getLayoutResource()); setContentView(getLayoutResource());
mToolbar = Utility.findViewById(this, R.id.toolbar); mToolbar = (Toolbar) this.findViewById(R.id.toolbar);
setSupportActionBar(mToolbar); setSupportActionBar(mToolbar);
} }

View file

@ -3,8 +3,7 @@ package us.shandian.giga.ui.fragment;
import us.shandian.giga.get.DownloadManager; import us.shandian.giga.get.DownloadManager;
import us.shandian.giga.service.DownloadManagerService; import us.shandian.giga.service.DownloadManagerService;
public class AllMissionsFragment extends MissionsFragment public class AllMissionsFragment extends MissionsFragment {
{
@Override @Override
protected DownloadManager setupDownloadManager(DownloadManagerService.DMBinder binder) { protected DownloadManager setupDownloadManager(DownloadManagerService.DMBinder binder) {

View file

@ -23,10 +23,8 @@ import org.schabi.newpipe.R;
import us.shandian.giga.get.DownloadManager; import us.shandian.giga.get.DownloadManager;
import us.shandian.giga.service.DownloadManagerService; import us.shandian.giga.service.DownloadManagerService;
import us.shandian.giga.ui.adapter.MissionAdapter; import us.shandian.giga.ui.adapter.MissionAdapter;
import us.shandian.giga.util.Utility;
public abstract class MissionsFragment extends Fragment public abstract class MissionsFragment extends Fragment {
{
private DownloadManager mManager; private DownloadManager mManager;
private DownloadManagerService.DMBinder mBinder; private DownloadManagerService.DMBinder mBinder;
@ -70,7 +68,7 @@ public abstract class MissionsFragment extends Fragment
getActivity().bindService(i, mConnection, Context.BIND_AUTO_CREATE); getActivity().bindService(i, mConnection, Context.BIND_AUTO_CREATE);
// Views // Views
mList = Utility.findViewById(v, R.id.mission_recycler); mList = (RecyclerView) v.findViewById(R.id.mission_recycler);
// Init // Init
mGridManager = new GridLayoutManager(getActivity(), 2); mGridManager = new GridLayoutManager(getActivity(), 2);
@ -82,7 +80,9 @@ public abstract class MissionsFragment extends Fragment
return v; return v;
} }
/** Added in API level 23. */ /**
* Added in API level 23.
*/
@Override @Override
public void onAttach(Context activity) { public void onAttach(Context activity) {
super.onAttach(activity); super.onAttach(activity);
@ -93,8 +93,10 @@ public abstract class MissionsFragment extends Fragment
mActivity = activity; mActivity = activity;
} }
/** deprecated in API level 23, /**
* but must remain to allow compatibility with api<23 */ * deprecated in API level 23,
* but must remain to allow compatibility with api<23
*/
@Override @Override
public void onAttach(Activity activity) { public void onAttach(Activity activity) {
super.onAttach(activity); super.onAttach(activity);

View file

@ -9,8 +9,7 @@ import java.io.File;
import java.io.PrintWriter; import java.io.PrintWriter;
//todo: replace this by using the internal crash handler of newpipe //todo: replace this by using the internal crash handler of newpipe
public class CrashHandler implements Thread.UncaughtExceptionHandler public class CrashHandler implements Thread.UncaughtExceptionHandler {
{
public static final String CRASH_DIR = Environment.getExternalStorageDirectory().getPath() + "/GigaCrash/"; public static final String CRASH_DIR = Environment.getExternalStorageDirectory().getPath() + "/GigaCrash/";
public static final String CRASH_LOG = CRASH_DIR + "last_crash.log"; public static final String CRASH_LOG = CRASH_DIR + "last_crash.log";
public static final String CRASH_TAG = CRASH_DIR + ".crashed"; public static final String CRASH_TAG = CRASH_DIR + ".crashed";

View file

@ -1,32 +1,27 @@
package us.shandian.giga.util; package us.shandian.giga.util;
import android.app.Activity;
import android.content.ClipboardManager;
import android.content.ClipData; import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.support.annotation.ColorRes;
import android.view.View; import android.support.annotation.DrawableRes;
import android.support.annotation.Nullable;
import android.widget.Toast; import android.widget.Toast;
import org.schabi.newpipe.R;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import org.schabi.newpipe.settings.NewPipeSettings; public class Utility {
import org.schabi.newpipe.R;
import com.nononsenseapps.filepicker.FilePickerActivity; public enum FileType {
import com.nononsenseapps.filepicker.AbstractFilePickerFragment;
public class Utility
{
public static enum FileType {
VIDEO, VIDEO,
MUSIC, MUSIC,
UNKNOWN UNKNOWN
@ -109,30 +104,25 @@ public class Utility
} }
} }
public static <T> T findViewById(View v, int id) { @Nullable
return (T) v.findViewById(id);
}
public static <T> T findViewById(Activity activity, int id) {
return (T) activity.findViewById(id);
}
public static String getFileExt(String url) { public static String getFileExt(String url) {
if (url.indexOf("?")>-1) { int index;
url = url.substring(0,url.indexOf("?")); if ((index = url.indexOf("?")) > -1) {
url = url.substring(0, index);
} }
if (url.lastIndexOf(".") == -1) {
index = url.lastIndexOf(".");
if (index == -1) {
return null; return null;
} else { } else {
String ext = url.substring(url.lastIndexOf(".") ); String ext = url.substring(index);
if (ext.indexOf("%")>-1) { if ((index = ext.indexOf("%")) > -1) {
ext = ext.substring(0,ext.indexOf("%")); ext = ext.substring(0, index);
} }
if (ext.indexOf("/")>-1) { if ((index = ext.indexOf("/")) > -1) {
ext = ext.substring(0,ext.indexOf("/")); ext = ext.substring(0, index);
} }
return ext.toLowerCase(); return ext.toLowerCase();
} }
} }
@ -147,16 +137,7 @@ public class Utility
} }
} }
public static Boolean isMusicFile(String file) @ColorRes
{
return Utility.getFileType(file) == FileType.MUSIC;
}
public static Boolean isVideoFile(String file)
{
return Utility.getFileType(file) == FileType.VIDEO;
}
public static int getBackgroundForFileType(FileType type) { public static int getBackgroundForFileType(FileType type) {
switch (type) { switch (type) {
case MUSIC: case MUSIC:
@ -168,6 +149,7 @@ public class Utility
} }
} }
@ColorRes
public static int getForegroundForFileType(FileType type) { public static int getForegroundForFileType(FileType type) {
switch (type) { switch (type) {
case MUSIC: case MUSIC:
@ -179,8 +161,9 @@ public class Utility
} }
} }
@DrawableRes
public static int getIconForFileType(FileType type) { public static int getIconForFileType(FileType type) {
switch(type) { switch (type) {
case MUSIC: case MUSIC:
return R.drawable.music; return R.drawable.music;
case VIDEO: case VIDEO:
@ -190,24 +173,6 @@ public class Utility
} }
} }
public static boolean isDirectoryAvailble(String path) {
File dir = new File(path);
return dir.exists() && dir.isDirectory();
}
public static boolean isDownloadDirectoryAvailble(Context context) {
return isDirectoryAvailble(NewPipeSettings.getVideoDownloadPath(context));
}
public static void showDirectoryChooser(Activity activity) {
Intent i = new Intent(activity, FilePickerActivity.class);
i.setAction(Intent.ACTION_GET_CONTENT);
i.putExtra(FilePickerActivity.EXTRA_ALLOW_MULTIPLE, false);
i.putExtra(FilePickerActivity.EXTRA_ALLOW_CREATE_DIR, true);
i.putExtra(FilePickerActivity.EXTRA_MODE, AbstractFilePickerFragment.MODE_DIR);
activity.startActivityForResult(i, 233);
}
public static void copyToClipboard(Context context, String str) { public static void copyToClipboard(Context context, String str) {
ClipboardManager cm = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); ClipboardManager cm = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
cm.setPrimaryClip(ClipData.newPlainText("text", str)); cm.setPrimaryClip(ClipData.newPlainText("text", str));

View file

@ -0,0 +1,38 @@
package org.schabi.newpipe.report;
import android.app.Activity;
import org.junit.Test;
import org.schabi.newpipe.MainActivity;
import org.schabi.newpipe.RouterActivity;
import org.schabi.newpipe.fragments.detail.VideoDetailFragment;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
/**
* Unit tests for {@link ErrorActivity}
*/
public class ErrorActivityTest {
@Test
public void getReturnActivity() throws Exception {
Class<? extends Activity> returnActivity;
returnActivity = ErrorActivity.getReturnActivity(MainActivity.class);
assertEquals(MainActivity.class, returnActivity);
returnActivity = ErrorActivity.getReturnActivity(RouterActivity.class);
assertEquals(RouterActivity.class, returnActivity);
returnActivity = ErrorActivity.getReturnActivity(null);
assertNull(returnActivity);
returnActivity = ErrorActivity.getReturnActivity(Integer.class);
assertEquals(MainActivity.class, returnActivity);
returnActivity = ErrorActivity.getReturnActivity(VideoDetailFragment.class);
assertEquals(MainActivity.class, returnActivity);
}
}

View file

@ -31,18 +31,18 @@ import static org.mockito.Mockito.when;
public class DownloadManagerImplTest { public class DownloadManagerImplTest {
private DownloadManagerImpl downloadManager; private DownloadManagerImpl downloadManager;
private DownloadDataSource dowloadDataSource; private DownloadDataSource downloadDataSource;
private ArrayList<DownloadMission> missions; private ArrayList<DownloadMission> missions;
@org.junit.Before @org.junit.Before
public void setUp() throws Exception { public void setUp() throws Exception {
dowloadDataSource = mock(DownloadDataSource.class); downloadDataSource = mock(DownloadDataSource.class);
missions = new ArrayList<>(); missions = new ArrayList<>();
for(int i = 0; i < 50; ++i){ for(int i = 0; i < 50; ++i){
missions.add(generateFinishedDownloadMission()); missions.add(generateFinishedDownloadMission());
} }
when(dowloadDataSource.loadMissions()).thenReturn(new ArrayList<>(missions)); when(downloadDataSource.loadMissions()).thenReturn(new ArrayList<>(missions));
downloadManager = new DownloadManagerImpl(new ArrayList<String>(), dowloadDataSource); downloadManager = new DownloadManagerImpl(new ArrayList<String>(), downloadDataSource);
} }
@Test(expected = NullPointerException.class) @Test(expected = NullPointerException.class)
@ -82,10 +82,10 @@ public class DownloadManagerImplTest {
missions.add(mission); missions.add(mission);
} }
dowloadDataSource = mock(DownloadDataSource.class); downloadDataSource = mock(DownloadDataSource.class);
when(dowloadDataSource.loadMissions()).thenReturn(new ArrayList<>(missions)); when(downloadDataSource.loadMissions()).thenReturn(new ArrayList<>(missions));
downloadManager = new DownloadManagerImpl(new ArrayList<String>(), dowloadDataSource); downloadManager = new DownloadManagerImpl(new ArrayList<String>(), downloadDataSource);
verify(dowloadDataSource, times(1)).loadMissions(); verify(downloadDataSource, times(1)).loadMissions();
assertEquals(50, downloadManager.getCount()); assertEquals(50, downloadManager.getCount());