diff --git a/app/build.gradle b/app/build.gradle index ad3404b9f..354dbaa0e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -49,12 +49,13 @@ ext { icepickLibVersion = '3.2.0' stethoLibVersion = '1.5.0' } + dependencies { androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2') { exclude module: 'support-annotations' } - implementation 'com.github.TeamNewPipe:NewPipeExtractor:1eff8c5708' + implementation 'com.github.TeamNewPipe:NewPipeExtractor:fef71aeccc37' testImplementation 'junit:junit:4.12' testImplementation 'org.mockito:mockito-core:2.8.9' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 33e0651e5..e4d448184 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -76,10 +76,6 @@ android:name=".about.AboutActivity" android:label="@string/title_activity_about"/> - - @@ -122,6 +118,7 @@ + { + NewPipeSettings.resetDownloadFolders(this); + finish(); + }) + .setNegativeButton(R.string.cancel, (DialogInterface dialogInterface, int i) -> { + dialogInterface.dismiss(); + finish(); + }) + .create() + .show(); + } +} diff --git a/app/src/main/java/org/schabi/newpipe/fragments/BaseStateFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/BaseStateFragment.java index af16ff062..589d15bd4 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/BaseStateFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/BaseStateFragment.java @@ -87,12 +87,7 @@ public abstract class BaseStateFragment extends BaseFragment implements ViewC RxView.clicks(errorButtonRetry) .debounce(300, TimeUnit.MILLISECONDS) .observeOn(AndroidSchedulers.mainThread()) - .subscribe(new Consumer() { - @Override - public void accept(Object o) throws Exception { - onRetryButtonClicked(); - } - }); + .subscribe(o -> onRetryButtonClicked()); } protected void onRetryButtonClicked() { diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java index d91502cdd..c726f8cee 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java @@ -1227,10 +1227,10 @@ public class VideoDetailFragment spinnerToolbar.setVisibility(View.GONE); break; default: + if(info.getAudioStreams().isEmpty()) detailControlsBackground.setVisibility(View.GONE); if (!info.getVideoStreams().isEmpty() || !info.getVideoOnlyStreams().isEmpty()) break; - detailControlsBackground.setVisibility(View.GONE); detailControlsPopup.setVisibility(View.GONE); spinnerToolbar.setVisibility(View.GONE); thumbnailPlayButton.setImageResource(R.drawable.ic_headset_white_24dp); diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java index 01922a4f3..4df5982f7 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java @@ -169,38 +169,35 @@ public class ChannelFragment extends BaseListInfoFragment { context.getResources().getString(R.string.share) }; - final DialogInterface.OnClickListener actions = new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - final int index = Math.max(infoListAdapter.getItemsList().indexOf(item), 0); - switch (i) { - case 0: - NavigationHelper.enqueueOnBackgroundPlayer(context, new SinglePlayQueue(item)); - break; - case 1: - NavigationHelper.enqueueOnPopupPlayer(activity, new SinglePlayQueue(item)); - break; - case 2: - NavigationHelper.playOnMainPlayer(context, getPlayQueue(index)); - break; - case 3: - NavigationHelper.playOnBackgroundPlayer(context, getPlayQueue(index)); - break; - case 4: - NavigationHelper.playOnPopupPlayer(activity, getPlayQueue(index)); - break; - case 5: - if (getFragmentManager() != null) { - PlaylistAppendDialog.fromStreamInfoItems(Collections.singletonList(item)) - .show(getFragmentManager(), TAG); - } - break; - case 6: - shareUrl(item.getName(), item.getUrl()); - break; - default: - break; - } + final DialogInterface.OnClickListener actions = (DialogInterface dialogInterface, int i) -> { + final int index = Math.max(infoListAdapter.getItemsList().indexOf(item), 0); + switch (i) { + case 0: + NavigationHelper.enqueueOnBackgroundPlayer(context, new SinglePlayQueue(item)); + break; + case 1: + NavigationHelper.enqueueOnPopupPlayer(activity, new SinglePlayQueue(item)); + break; + case 2: + NavigationHelper.playOnMainPlayer(context, getPlayQueue(index)); + break; + case 3: + NavigationHelper.playOnBackgroundPlayer(context, getPlayQueue(index)); + break; + case 4: + NavigationHelper.playOnPopupPlayer(activity, getPlayQueue(index)); + break; + case 5: + if (getFragmentManager() != null) { + PlaylistAppendDialog.fromStreamInfoItems(Collections.singletonList(item)) + .show(getFragmentManager(), TAG); + } + break; + case 6: + shareUrl(item.getName(), item.getUrl()); + break; + default: + break; } }; @@ -258,12 +255,12 @@ public class ChannelFragment extends BaseListInfoFragment { private static final int BUTTON_DEBOUNCE_INTERVAL = 100; private void monitorSubscription(final ChannelInfo info) { - final Consumer onError = new Consumer() { - @Override - public void accept(Throwable throwable) throws Exception { + final Consumer onError = (Throwable throwable) -> { animateView(headerSubscribeButton, false, 100); - showSnackBarError(throwable, UserAction.SUBSCRIPTION, NewPipe.getNameOfService(currentInfo.getServiceId()), "Get subscription status", 0); - } + showSnackBarError(throwable, UserAction.SUBSCRIPTION, + NewPipe.getNameOfService(currentInfo.getServiceId()), + "Get subscription status", + 0); }; final Observable> observable = subscriptionService.subscriptionTable() @@ -279,50 +276,38 @@ public class ChannelFragment extends BaseListInfoFragment { // so only update the UI for the latest emission ("sync" the subscribe button's state) .debounce(100, TimeUnit.MILLISECONDS) .observeOn(AndroidSchedulers.mainThread()) - .subscribe(new Consumer>() { - @Override - public void accept(List subscriptionEntities) throws Exception { - updateSubscribeButton(!subscriptionEntities.isEmpty()); - } - }, onError)); + .subscribe((List subscriptionEntities) -> + updateSubscribeButton(!subscriptionEntities.isEmpty()) + , onError)); } private Function mapOnSubscribe(final SubscriptionEntity subscription) { - return new Function() { - @Override - public Object apply(@NonNull Object o) throws Exception { - subscriptionService.subscriptionTable().insert(subscription); - return o; - } + return (@NonNull Object o) -> { + subscriptionService.subscriptionTable().insert(subscription); + return o; }; } private Function mapOnUnsubscribe(final SubscriptionEntity subscription) { - return new Function() { - @Override - public Object apply(@NonNull Object o) throws Exception { - subscriptionService.subscriptionTable().delete(subscription); - return o; - } + return (@NonNull Object o) -> { + subscriptionService.subscriptionTable().delete(subscription); + return o; }; } private void updateSubscription(final ChannelInfo info) { if (DEBUG) Log.d(TAG, "updateSubscription() called with: info = [" + info + "]"); - final Action onComplete = new Action() { - @Override - public void run() throws Exception { + final Action onComplete = () -> { if (DEBUG) Log.d(TAG, "Updated subscription: " + info.getUrl()); - } }; - final Consumer onError = new Consumer() { - @Override - public void accept(@NonNull Throwable throwable) throws Exception { - onUnrecoverableError(throwable, UserAction.SUBSCRIPTION, NewPipe.getNameOfService(info.getServiceId()), "Updating Subscription for " + info.getUrl(), R.string.subscription_update_failed); - } - }; + final Consumer onError = (@NonNull Throwable throwable) -> + onUnrecoverableError(throwable, + UserAction.SUBSCRIPTION, + NewPipe.getNameOfService(info.getServiceId()), + "Updating Subscription for " + info.getUrl(), + R.string.subscription_update_failed); disposables.add(subscriptionService.updateChannelInfo(info) .subscribeOn(Schedulers.io()) @@ -331,19 +316,16 @@ public class ChannelFragment extends BaseListInfoFragment { } private Disposable monitorSubscribeButton(final Button subscribeButton, final Function action) { - final Consumer onNext = new Consumer() { - @Override - public void accept(@NonNull Object o) throws Exception { + final Consumer onNext = (@NonNull Object o) -> { if (DEBUG) Log.d(TAG, "Changed subscription status to this channel!"); - } }; - final Consumer onError = new Consumer() { - @Override - public void accept(@NonNull Throwable throwable) throws Exception { - onUnrecoverableError(throwable, UserAction.SUBSCRIPTION, NewPipe.getNameOfService(currentInfo.getServiceId()), "Subscription Change", R.string.subscription_change_failed); - } - }; + final Consumer onError = (@NonNull Throwable throwable) -> + onUnrecoverableError(throwable, + UserAction.SUBSCRIPTION, + NewPipe.getNameOfService(currentInfo.getServiceId()), + "Subscription Change", + R.string.subscription_change_failed); /* Emit clicks from main thread unto io thread */ return RxView.clicks(subscribeButton) @@ -355,25 +337,25 @@ public class ChannelFragment extends BaseListInfoFragment { } private Consumer> getSubscribeUpdateMonitor(final ChannelInfo info) { - return new Consumer>() { - @Override - public void accept(List subscriptionEntities) throws Exception { - if (DEBUG) - Log.d(TAG, "subscriptionService.subscriptionTable.doOnNext() called with: subscriptionEntities = [" + subscriptionEntities + "]"); - if (subscribeButtonMonitor != null) subscribeButtonMonitor.dispose(); + return (List subscriptionEntities) -> { + if (DEBUG) + Log.d(TAG, "subscriptionService.subscriptionTable.doOnNext() called with: subscriptionEntities = [" + subscriptionEntities + "]"); + if (subscribeButtonMonitor != null) subscribeButtonMonitor.dispose(); - if (subscriptionEntities.isEmpty()) { - if (DEBUG) Log.d(TAG, "No subscription to this channel!"); - SubscriptionEntity channel = new SubscriptionEntity(); - channel.setServiceId(info.getServiceId()); - channel.setUrl(info.getUrl()); - channel.setData(info.getName(), info.getAvatarUrl(), info.getDescription(), info.getSubscriberCount()); - subscribeButtonMonitor = monitorSubscribeButton(headerSubscribeButton, mapOnSubscribe(channel)); - } else { - if (DEBUG) Log.d(TAG, "Found subscription to this channel!"); - final SubscriptionEntity subscription = subscriptionEntities.get(0); - subscribeButtonMonitor = monitorSubscribeButton(headerSubscribeButton, mapOnUnsubscribe(subscription)); - } + if (subscriptionEntities.isEmpty()) { + if (DEBUG) Log.d(TAG, "No subscription to this channel!"); + SubscriptionEntity channel = new SubscriptionEntity(); + channel.setServiceId(info.getServiceId()); + channel.setUrl(info.getUrl()); + channel.setData(info.getName(), + info.getAvatarUrl(), + info.getDescription(), + info.getSubscriberCount()); + subscribeButtonMonitor = monitorSubscribeButton(headerSubscribeButton, mapOnSubscribe(channel)); + } else { + if (DEBUG) Log.d(TAG, "Found subscription to this channel!"); + final SubscriptionEntity subscription = subscriptionEntities.get(0); + subscribeButtonMonitor = monitorSubscribeButton(headerSubscribeButton, mapOnUnsubscribe(subscription)); } }; } @@ -491,8 +473,11 @@ public class ChannelFragment extends BaseListInfoFragment { super.handleNextItems(result); if (!result.getErrors().isEmpty()) { - showSnackBarError(result.getErrors(), UserAction.REQUESTED_CHANNEL, NewPipe.getNameOfService(serviceId), - "Get next page of: " + url, R.string.general_error); + showSnackBarError(result.getErrors(), + UserAction.REQUESTED_CHANNEL, + NewPipe.getNameOfService(serviceId), + "Get next page of: " + url, + R.string.general_error); } } diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java index 411379963..a699e28bc 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java @@ -365,7 +365,7 @@ public class SearchFragment int itemId = 0; boolean isFirstItem = true; final Context c = getContext(); - for(String filter : service.getSearchQIHFactory().getAvailableContentFilter()) { + for(String filter : service.getSearchQHFactory().getAvailableContentFilter()) { menuItemToFilterName.put(itemId, filter); MenuItem item = menu.add(1, itemId++, @@ -575,8 +575,7 @@ public class SearchFragment .onNext(searchEditText.getText().toString()), throwable -> showSnackBarError(throwable, UserAction.DELETE_FROM_HISTORY, "none", - "Deleting item failed", R.string.general_error) - ); + "Deleting item failed", R.string.general_error)); disposables.add(onDelete); }) .show(); @@ -837,7 +836,10 @@ public class SearchFragment @Override public void handleResult(@NonNull SearchInfo result) { - if (!result.getErrors().isEmpty()) { + final List exceptions = result.getErrors(); + if (!exceptions.isEmpty() + && !(exceptions.size() == 1 + && exceptions.get(0) instanceof SearchExtractor.NothingFoundException)){ showSnackBarError(result.getErrors(), UserAction.SEARCHED, NewPipe.getNameOfService(serviceId), searchString, 0); } @@ -864,6 +866,7 @@ public class SearchFragment showListFooter(false); currentPageUrl = result.getNextPageUrl(); infoListAdapter.addInfoItemList(result.getItems()); + nextPageUrl = result.getNextPageUrl(); if (!result.getErrors().isEmpty()) { showSnackBarError(result.getErrors(), UserAction.SEARCHED, diff --git a/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java b/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java index 8594ca395..91faa1014 100644 --- a/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java @@ -26,6 +26,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.graphics.Bitmap; +import android.os.Build; import android.os.IBinder; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -343,6 +344,7 @@ public final class BackgroundPlayer extends Service { if (!shouldUpdateOnProgress) return; resetNotification(); + if(Build.VERSION.SDK_INT >= 26 /*Oreo*/) updateNotificationThumbnail(); if (bigNotRemoteView != null) { bigNotRemoteView.setProgressBar(R.id.notificationProgressBar, duration, currentProgress, false); bigNotRemoteView.setTextViewText(R.id.notificationTime, getTimeString(currentProgress) + " / " + getTimeString(duration)); diff --git a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java index 7339dd50f..d87df3666 100644 --- a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java @@ -51,6 +51,7 @@ import com.nostra13.universalimageloader.core.ImageLoader; import com.nostra13.universalimageloader.core.assist.FailReason; import com.nostra13.universalimageloader.core.listener.ImageLoadingListener; +import org.schabi.newpipe.BuildConfig; import org.schabi.newpipe.Downloader; import org.schabi.newpipe.R; import org.schabi.newpipe.extractor.stream.StreamInfo; @@ -69,6 +70,7 @@ import org.schabi.newpipe.player.playqueue.PlayQueue; import org.schabi.newpipe.player.playqueue.PlayQueueAdapter; import org.schabi.newpipe.player.playqueue.PlayQueueItem; import org.schabi.newpipe.player.resolver.MediaSourceTag; +import org.schabi.newpipe.report.ErrorActivity; import org.schabi.newpipe.util.ImageDisplayConstants; import org.schabi.newpipe.util.SerializedCache; @@ -86,6 +88,7 @@ import static com.google.android.exoplayer2.Player.DISCONTINUITY_REASON_INTERNAL import static com.google.android.exoplayer2.Player.DISCONTINUITY_REASON_PERIOD_TRANSITION; import static com.google.android.exoplayer2.Player.DISCONTINUITY_REASON_SEEK; import static com.google.android.exoplayer2.Player.DISCONTINUITY_REASON_SEEK_ADJUSTMENT; +import static org.schabi.newpipe.report.UserAction.PLAY_STREAM; /** * Base for the players, joining the common properties @@ -96,7 +99,7 @@ import static com.google.android.exoplayer2.Player.DISCONTINUITY_REASON_SEEK_ADJ public abstract class BasePlayer implements Player.EventListener, PlaybackListener, ImageLoadingListener { - public static final boolean DEBUG = true; + public static final boolean DEBUG = !BuildConfig.BUILD_TYPE.equals("release"); @NonNull public static final String TAG = "BasePlayer"; @NonNull final protected Context context; @@ -363,7 +366,10 @@ public abstract class BasePlayer implements try { context.unregisterReceiver(broadcastReceiver); } catch (final IllegalArgumentException unregisteredException) { - Log.e(TAG, "Broadcast receiver already unregistered.", unregisteredException); + ErrorActivity.reportError(context, unregisteredException, null, null, + ErrorActivity.ErrorInfo.make(PLAY_STREAM, + "none", + "play stream", R.string.general_error)); } } @@ -1001,6 +1007,8 @@ public abstract class BasePlayer implements try { metadata = (MediaSourceTag) simpleExoPlayer.getCurrentTag(); } catch (IndexOutOfBoundsException | ClassCastException error) { + if(DEBUG) Log.d(TAG, "Could not update metadata: " + error.getMessage()); + if(DEBUG) error.printStackTrace(); return; } @@ -1087,6 +1095,9 @@ public abstract class BasePlayer implements return simpleExoPlayer.isCurrentWindowDynamic(); } catch (@NonNull IndexOutOfBoundsException ignored) { // Why would this even happen =( + // But lets log it anyway. Save is save + if(DEBUG) Log.d(TAG, "Could not update metadata: " + ignored.getMessage()); + if(DEBUG) ignored.printStackTrace(); return false; } } diff --git a/app/src/main/java/org/schabi/newpipe/player/ServicePlayerActivity.java b/app/src/main/java/org/schabi/newpipe/player/ServicePlayerActivity.java index b57a710ed..94305e6c4 100644 --- a/app/src/main/java/org/schabi/newpipe/player/ServicePlayerActivity.java +++ b/app/src/main/java/org/schabi/newpipe/player/ServicePlayerActivity.java @@ -16,6 +16,7 @@ import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; +import android.view.ViewGroup; import android.widget.ImageButton; import android.widget.LinearLayout; import android.widget.PopupMenu; @@ -562,6 +563,12 @@ public abstract class ServicePlayerActivity extends AppCompatActivity if (player != null) { progressLiveSync.setClickable(!player.isLiveEdge()); } + + // this will make shure progressCurrentTime has the same width as progressEndTime + final ViewGroup.LayoutParams endTimeParams = progressEndTime.getLayoutParams(); + final ViewGroup.LayoutParams currentTimeParams = progressCurrentTime.getLayoutParams(); + currentTimeParams.width = progressEndTime.getWidth(); + progressCurrentTime.setLayoutParams(currentTimeParams); } @Override diff --git a/app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueue.java b/app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueue.java index a21560abd..c9e07c96a 100644 --- a/app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueue.java +++ b/app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueue.java @@ -6,6 +6,7 @@ import android.util.Log; import org.reactivestreams.Subscriber; import org.reactivestreams.Subscription; +import org.schabi.newpipe.BuildConfig; import org.schabi.newpipe.player.playqueue.events.AppendEvent; import org.schabi.newpipe.player.playqueue.events.ErrorEvent; import org.schabi.newpipe.player.playqueue.events.InitEvent; @@ -41,7 +42,7 @@ import io.reactivex.subjects.BehaviorSubject; public abstract class PlayQueue implements Serializable { private final String TAG = "PlayQueue@" + Integer.toHexString(hashCode()); - public static final boolean DEBUG = true; + public static final boolean DEBUG = !BuildConfig.BUILD_TYPE.equals("release"); private ArrayList backup; private ArrayList streams; diff --git a/app/src/main/java/org/schabi/newpipe/report/UserAction.java b/app/src/main/java/org/schabi/newpipe/report/UserAction.java index 93a3ce16c..00a25ed8d 100644 --- a/app/src/main/java/org/schabi/newpipe/report/UserAction.java +++ b/app/src/main/java/org/schabi/newpipe/report/UserAction.java @@ -15,7 +15,8 @@ public enum UserAction { REQUESTED_CHANNEL("requested channel"), REQUESTED_PLAYLIST("requested playlist"), REQUESTED_KIOSK("requested kiosk"), - DELETE_FROM_HISTORY("delete from history"); + DELETE_FROM_HISTORY("delete from history"), + PLAY_STREAM("Play stream"); private final String message; diff --git a/app/src/main/java/org/schabi/newpipe/settings/NewPipeSettings.java b/app/src/main/java/org/schabi/newpipe/settings/NewPipeSettings.java index 92f98a9a2..2a0e2645b 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/NewPipeSettings.java +++ b/app/src/main/java/org/schabi/newpipe/settings/NewPipeSettings.java @@ -71,7 +71,7 @@ public class NewPipeSettings { } public static File getVideoDownloadFolder(Context context) { - return getFolder(context, R.string.download_path_key, Environment.DIRECTORY_MOVIES); + return getDir(context, R.string.download_path_key, Environment.DIRECTORY_MOVIES); } public static String getVideoDownloadPath(Context context) { @@ -81,7 +81,7 @@ public class NewPipeSettings { } public static File getAudioDownloadFolder(Context context) { - return getFolder(context, R.string.download_path_audio_key, Environment.DIRECTORY_MUSIC); + return getDir(context, R.string.download_path_audio_key, Environment.DIRECTORY_MUSIC); } public static String getAudioDownloadPath(Context context) { @@ -90,21 +90,37 @@ public class NewPipeSettings { return prefs.getString(key, Environment.DIRECTORY_MUSIC); } - private static File getFolder(Context context, int keyID, String defaultDirectoryName) { + private static File getDir(Context context, int keyID, String defaultDirectoryName) { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); final String key = context.getString(keyID); String downloadPath = prefs.getString(key, null); if ((downloadPath != null) && (!downloadPath.isEmpty())) return new File(downloadPath.trim()); - final File folder = getFolder(defaultDirectoryName); + final File dir = getDir(defaultDirectoryName); SharedPreferences.Editor spEditor = prefs.edit(); - spEditor.putString(key, new File(folder, "NewPipe").getAbsolutePath()); + spEditor.putString(key, getNewPipeChildFolderPathForDir(dir)); spEditor.apply(); - return folder; + return dir; } @NonNull - private static File getFolder(String defaultDirectoryName) { + private static File getDir(String defaultDirectoryName) { return new File(Environment.getExternalStorageDirectory(), defaultDirectoryName); } + + public static void resetDownloadFolders(Context context) { + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); + resetDownloadFolder(prefs, context.getString(R.string.download_path_audio_key), Environment.DIRECTORY_MUSIC); + resetDownloadFolder(prefs, context.getString(R.string.download_path_key), Environment.DIRECTORY_MOVIES); + } + + private static void resetDownloadFolder(SharedPreferences prefs, String key, String defaultDirectoryName) { + SharedPreferences.Editor spEditor = prefs.edit(); + spEditor.putString(key, getNewPipeChildFolderPathForDir(getDir(defaultDirectoryName))); + spEditor.apply(); + } + + private static String getNewPipeChildFolderPathForDir(File dir) { + return new File(dir, "NewPipe").getAbsolutePath(); + } } diff --git a/app/src/main/java/org/schabi/newpipe/util/ExtractorHelper.java b/app/src/main/java/org/schabi/newpipe/util/ExtractorHelper.java index 74e2d4cd5..e445233c3 100644 --- a/app/src/main/java/org/schabi/newpipe/util/ExtractorHelper.java +++ b/app/src/main/java/org/schabi/newpipe/util/ExtractorHelper.java @@ -73,7 +73,7 @@ public final class ExtractorHelper { return Single.fromCallable(() -> SearchInfo.getInfo(NewPipe.getService(serviceId), NewPipe.getService(serviceId) - .getSearchQIHFactory() + .getSearchQHFactory() .fromQuery(searchString, contentFilter, sortFilter), contentCountry)); } @@ -88,7 +88,7 @@ public final class ExtractorHelper { return Single.fromCallable(() -> SearchInfo.getMoreItems(NewPipe.getService(serviceId), NewPipe.getService(serviceId) - .getSearchQIHFactory() + .getSearchQHFactory() .fromQuery(searchString, contentFilter, sortFilter), contentCountry, pageUrl)); diff --git a/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java b/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java index 4556cfd7d..13767125d 100644 --- a/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java +++ b/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java @@ -31,8 +31,6 @@ import org.schabi.newpipe.extractor.stream.AudioStream; import org.schabi.newpipe.extractor.stream.Stream; import org.schabi.newpipe.extractor.stream.StreamInfo; import org.schabi.newpipe.extractor.stream.VideoStream; -import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler; -import org.schabi.newpipe.extractor.linkhandler.SearchQueryHandler; import org.schabi.newpipe.fragments.MainFragment; import org.schabi.newpipe.fragments.detail.VideoDetailFragment; import org.schabi.newpipe.fragments.list.channel.ChannelFragment; diff --git a/app/src/main/java/us/shandian/giga/get/DownloadManagerImpl.java b/app/src/main/java/us/shandian/giga/get/DownloadManagerImpl.java index ecd3ce562..3294f5164 100755 --- a/app/src/main/java/us/shandian/giga/get/DownloadManagerImpl.java +++ b/app/src/main/java/us/shandian/giga/get/DownloadManagerImpl.java @@ -1,10 +1,17 @@ package us.shandian.giga.get; +import android.content.Context; +import android.content.Intent; +import android.os.Handler; +import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.util.Log; +import org.schabi.newpipe.download.ExtSDDownloadFailedActivity; + import java.io.File; import java.io.FilenameFilter; +import java.io.IOException; import java.io.RandomAccessFile; import java.net.HttpURLConnection; import java.net.URL; @@ -23,7 +30,9 @@ public class DownloadManagerImpl implements DownloadManager { private static final String TAG = DownloadManagerImpl.class.getSimpleName(); private final DownloadDataSource mDownloadDataSource; - private final ArrayList mMissions = new ArrayList(); + private final ArrayList mMissions = new ArrayList<>(); + @NonNull + private final Context context; /** * Create a new instance @@ -33,6 +42,13 @@ public class DownloadManagerImpl implements DownloadManager { */ public DownloadManagerImpl(Collection searchLocations, DownloadDataSource downloadDataSource) { mDownloadDataSource = downloadDataSource; + this.context = null; + loadMissions(searchLocations); + } + + public DownloadManagerImpl(Collection searchLocations, DownloadDataSource downloadDataSource, Context context) { + mDownloadDataSource = downloadDataSource; + this.context = context; loadMissions(searchLocations); } @@ -277,10 +293,12 @@ public class DownloadManagerImpl implements DownloadManager { } private class Initializer extends Thread { - private DownloadMission mission; + private final DownloadMission mission; + private final Handler handler; public Initializer(DownloadMission mission) { this.mission = mission; + this.handler = new Handler(); } @Override @@ -335,6 +353,13 @@ public class DownloadManagerImpl implements DownloadManager { af.close(); mission.start(); + } catch (IOException ie) { + if(context == null) throw new RuntimeException(ie); + + if(ie.getMessage().contains("Permission denied")) { + handler.post(() -> + context.startActivity(new Intent(context, ExtSDDownloadFailedActivity.class))); + } else throw new RuntimeException(ie); } catch (Exception e) { // TODO Notify throw new RuntimeException(e); diff --git a/app/src/main/java/us/shandian/giga/service/DownloadManagerService.java b/app/src/main/java/us/shandian/giga/service/DownloadManagerService.java index 50975728f..59f5e2225 100755 --- a/app/src/main/java/us/shandian/giga/service/DownloadManagerService.java +++ b/app/src/main/java/us/shandian/giga/service/DownloadManagerService.java @@ -81,7 +81,7 @@ public class DownloadManagerService extends Service { ArrayList paths = new ArrayList<>(2); paths.add(NewPipeSettings.getVideoDownloadPath(this)); paths.add(NewPipeSettings.getAudioDownloadPath(this)); - mManager = new DownloadManagerImpl(paths, mDataSource); + mManager = new DownloadManagerImpl(paths, mDataSource, this); if (DEBUG) { Log.d(TAG, "mManager == null"); Log.d(TAG, "Download directory: " + paths); diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 344ef2198..eaeeb2685 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -170,6 +170,8 @@ Search history deleted. Error + External storage not available. + Download to external SD Card is not possible yet. Should the download place be reset? Network error Could not load all thumbnails Could not decrypt video URL signature diff --git a/build.gradle b/build.gradle index 0448ed61e..20c8a0dfc 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ buildscript { google() } dependencies { - classpath 'com.android.tools.build:gradle:3.1.3' + classpath 'com.android.tools.build:gradle:3.1.4' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files