diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4f97a7201..dab6fb2ec 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -185,7 +185,7 @@ android:name=".RouterPopupActivity" android:label="@string/popup_mode_share_menu_title" android:taskAffinity="" - android:theme="@android:style/Theme.NoDisplay"> + android:theme="@style/PopupPermissionsTheme"> diff --git a/app/src/main/java/org/schabi/newpipe/RouterPopupActivity.java b/app/src/main/java/org/schabi/newpipe/RouterPopupActivity.java index 1cff0ca76..2e7089300 100644 --- a/app/src/main/java/org/schabi/newpipe/RouterPopupActivity.java +++ b/app/src/main/java/org/schabi/newpipe/RouterPopupActivity.java @@ -21,6 +21,7 @@ public class RouterPopupActivity extends RouterActivity { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !PermissionHelper.checkSystemAlertWindowPermission(this)) { Toast.makeText(this, R.string.msg_popup_permission, Toast.LENGTH_LONG).show(); + finish(); return; } StreamingService service; 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 a4ee01ccc..d0460c347 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 @@ -485,6 +485,8 @@ public class VideoDetailFragment extends BaseStateFragment implement private void showStreamDialog(final StreamInfoItem item) { final Context context = getContext(); + if (context == null || context.getResources() == null || getActivity() == null) return; + final String[] commands = new String[]{ context.getResources().getString(R.string.enqueue_on_background), context.getResources().getString(R.string.enqueue_on_popup) diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java index fd1e9ea63..ae17dafff 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java @@ -192,6 +192,8 @@ public abstract class BaseListFragment extends BaseStateFragment implem protected void showStreamDialog(final StreamInfoItem item) { final Context context = getContext(); + if (context == null || context.getResources() == null || getActivity() == null) return; + final String[] commands = new String[]{ context.getResources().getString(R.string.enqueue_on_background), context.getResources().getString(R.string.enqueue_on_popup) 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 348495079..857fb81e0 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 @@ -154,6 +154,8 @@ public class ChannelFragment extends BaseListInfoFragment { @Override protected void showStreamDialog(final StreamInfoItem item) { final Context context = getContext(); + if (context == null || context.getResources() == null || getActivity() == null) return; + final String[] commands = new String[]{ context.getResources().getString(R.string.enqueue_on_background), context.getResources().getString(R.string.enqueue_on_popup), diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java index 878dbf385..e7f7e9968 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java @@ -15,7 +15,6 @@ import android.view.MenuInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; -import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; @@ -109,6 +108,8 @@ public class PlaylistFragment extends BaseListInfoFragment { @Override protected void showStreamDialog(final StreamInfoItem item) { final Context context = getContext(); + if (context == null || context.getResources() == null || getActivity() == null) return; + final String[] commands = new String[]{ context.getResources().getString(R.string.enqueue_on_background), context.getResources().getString(R.string.enqueue_on_popup), 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 fae97bb7b..fb54a15c3 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 @@ -165,7 +165,7 @@ public class SearchFragment extends BaseListFragment items = new ArrayList<>(); private final Context context; private OnSuggestionItemSelected listener; - private boolean showSugestinHistory = true; + private boolean showSuggestionHistory = true; public interface OnSuggestionItemSelected { void onSuggestionItemSelected(SuggestionItem item); + void onSuggestionItemInserted(SuggestionItem item); void onSuggestionItemLongClick(SuggestionItem item); } @@ -32,7 +33,7 @@ public class SuggestionListAdapter extends RecyclerView.Adapter items) { this.items.clear(); - if (showSugestinHistory) { + if (showSuggestionHistory) { this.items.addAll(items); } else { // remove history items if history is disabled @@ -49,8 +50,8 @@ public class SuggestionListAdapter extends RecyclerView.Adapter
+ * In the event that this error is produced during a valid stream playback, we save the + * current position so the playback may be recovered and resumed manually by the user. This + * happens only if the playback is {@link #RECOVERY_SKIP_THRESHOLD} milliseconds until complete. + *

* * {@link ExoPlaybackException#TYPE_UNEXPECTED TYPE_UNEXPECTED}:

* If a runtime error occurred, then we can try to recover it by restarting the playback - * after setting the timestamp recovery. + * after setting the timestamp recovery.

* * {@link ExoPlaybackException#TYPE_RENDERER TYPE_RENDERER}:

* If the renderer failed, treat the error as unrecoverable. @@ -568,6 +577,10 @@ public abstract class BasePlayer implements Player.EventListener, PlaybackListen switch (error.type) { case ExoPlaybackException.TYPE_SOURCE: + if (simpleExoPlayer.getCurrentPosition() < + simpleExoPlayer.getDuration() - RECOVERY_SKIP_THRESHOLD) { + setRecovery(); + } playQueue.error(isCurrentWindowValid()); showStreamError(error); break; diff --git a/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java index a3fd0f7a7..5f8b36449 100644 --- a/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java @@ -842,6 +842,8 @@ public final class PopupVideoPlayer extends Service { } savePositionAndSize(); } + + v.performClick(); return true; } @@ -880,23 +882,25 @@ public final class PopupVideoPlayer extends Service { private final Context context; private final Handler mainHandler; - FetcherHandler(Context context, int serviceId, String url) { + private FetcherHandler(Context context, int serviceId, String url) { this.mainHandler = new Handler(PopupVideoPlayer.this.getMainLooper()); this.context = context; this.url = url; this.serviceId = serviceId; } - /*package-private*/ void onReceive(final StreamInfo info) { + private void onReceive(final StreamInfo info) { mainHandler.post(new Runnable() { @Override public void run() { - playerImpl.initPlayback(new SinglePlayQueue(info)); + final Intent intent = NavigationHelper.getPlayerIntent(getApplicationContext(), + PopupVideoPlayer.class, new SinglePlayQueue(info)); + playerImpl.handleIntent(intent); } }); } - protected void onError(final Throwable exception) { + private void onError(final Throwable exception) { if (DEBUG) Log.d(TAG, "onError() called with: exception = [" + exception + "]"); exception.printStackTrace(); mainHandler.post(new Runnable() { @@ -922,7 +926,7 @@ public final class PopupVideoPlayer extends Service { stopSelf(); } - /*package-private*/ void onReCaptchaException() { + private void onReCaptchaException() { Toast.makeText(context, R.string.recaptcha_request_toast, Toast.LENGTH_LONG).show(); // Starting ReCaptcha Challenge Activity Intent intent = new Intent(context, ReCaptchaActivity.class); diff --git a/app/src/main/java/org/schabi/newpipe/util/InfoCache.java b/app/src/main/java/org/schabi/newpipe/util/InfoCache.java index 5b22af86a..794c3dd78 100644 --- a/app/src/main/java/org/schabi/newpipe/util/InfoCache.java +++ b/app/src/main/java/org/schabi/newpipe/util/InfoCache.java @@ -26,6 +26,9 @@ import android.util.Log; import org.schabi.newpipe.MainActivity; import org.schabi.newpipe.extractor.Info; +import java.util.Map; +import java.util.concurrent.TimeUnit; + public final class InfoCache { private static final boolean DEBUG = MainActivity.DEBUG; @@ -37,9 +40,9 @@ public final class InfoCache { * Trim the cache to this size */ private static final int TRIM_CACHE_TO = 30; + private static final int DEFAULT_TIMEOUT_HOURS = 4; - // TODO: Replace to one with timeout (like the one from guava) - private static final LruCache lruCache = new LruCache<>(MAX_ITEMS_ON_CACHE); + private static final LruCache lruCache = new LruCache<>(MAX_ITEMS_ON_CACHE); private InfoCache() { //no instance @@ -52,28 +55,29 @@ public final class InfoCache { public Info getFromKey(int serviceId, @NonNull String url) { if (DEBUG) Log.d(TAG, "getFromKey() called with: serviceId = [" + serviceId + "], url = [" + url + "]"); synchronized (lruCache) { - return lruCache.get(serviceId + url); + return getInfo(lruCache, keyOf(serviceId, url)); } } public void putInfo(@NonNull Info info) { if (DEBUG) Log.d(TAG, "putInfo() called with: info = [" + info + "]"); synchronized (lruCache) { - lruCache.put(info.service_id + info.url, info); + final CacheData data = new CacheData(info, DEFAULT_TIMEOUT_HOURS, TimeUnit.HOURS); + lruCache.put(keyOf(info), data); } } public void removeInfo(@NonNull Info info) { if (DEBUG) Log.d(TAG, "removeInfo() called with: info = [" + info + "]"); synchronized (lruCache) { - lruCache.remove(info.service_id + info.url); + lruCache.remove(keyOf(info)); } } public void removeInfo(int serviceId, @NonNull String url) { if (DEBUG) Log.d(TAG, "removeInfo() called with: serviceId = [" + serviceId + "], url = [" + url + "]"); synchronized (lruCache) { - lruCache.remove(serviceId + url); + lruCache.remove(keyOf(serviceId, url)); } } @@ -87,6 +91,7 @@ public final class InfoCache { public void trimCache() { if (DEBUG) Log.d(TAG, "trimCache() called"); synchronized (lruCache) { + removeStaleCache(lruCache); lruCache.trimToSize(TRIM_CACHE_TO); } } @@ -97,4 +102,51 @@ public final class InfoCache { } } + private static String keyOf(@NonNull final Info info) { + return keyOf(info.service_id, info.url); + } + + private static String keyOf(final int serviceId, @NonNull final String url) { + return serviceId + url; + } + + private static void removeStaleCache(@NonNull final LruCache cache) { + for (Map.Entry entry : cache.snapshot().entrySet()) { + final CacheData data = entry.getValue(); + if (data != null && data.isExpired()) { + cache.remove(entry.getKey()); + } + } + } + + private static Info getInfo(@NonNull final LruCache cache, + @NonNull final String key) { + final CacheData data = cache.get(key); + if (data == null) return null; + + if (data.isExpired()) { + cache.remove(key); + return null; + } + + return data.info; + } + + final private static class CacheData { + final private long expireTimestamp; + final private Info info; + + private CacheData(@NonNull final Info info, + final long timeout, + @NonNull final TimeUnit timeUnit) { + this.expireTimestamp = System.currentTimeMillis() + + TimeUnit.MILLISECONDS.convert(timeout, timeUnit); + + this.info = info; + } + + private boolean isExpired() { + return System.currentTimeMillis() > expireTimestamp; + } + } } diff --git a/app/src/main/res/drawable-hdpi/ic_arrow_top_left_black_24dp.png b/app/src/main/res/drawable-hdpi/ic_arrow_top_left_black_24dp.png new file mode 100644 index 000000000..da5605741 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_arrow_top_left_black_24dp.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_arrow_top_left_white_24dp.png b/app/src/main/res/drawable-hdpi/ic_arrow_top_left_white_24dp.png new file mode 100644 index 000000000..24376b637 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_arrow_top_left_white_24dp.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_arrow_top_left_black_24dp.png b/app/src/main/res/drawable-mdpi/ic_arrow_top_left_black_24dp.png new file mode 100644 index 000000000..056a0ff28 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_arrow_top_left_black_24dp.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_arrow_top_left_white_24dp.png b/app/src/main/res/drawable-mdpi/ic_arrow_top_left_white_24dp.png new file mode 100644 index 000000000..a2e73369c Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_arrow_top_left_white_24dp.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_arrow_top_left_black_24dp.png b/app/src/main/res/drawable-xhdpi/ic_arrow_top_left_black_24dp.png new file mode 100644 index 000000000..e4255a18a Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_arrow_top_left_black_24dp.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_arrow_top_left_white_24dp.png b/app/src/main/res/drawable-xhdpi/ic_arrow_top_left_white_24dp.png new file mode 100644 index 000000000..db578cab9 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_arrow_top_left_white_24dp.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_arrow_top_left_black_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_arrow_top_left_black_24dp.png new file mode 100644 index 000000000..566b5c5d3 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_arrow_top_left_black_24dp.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_arrow_top_left_white_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_arrow_top_left_white_24dp.png new file mode 100644 index 000000000..89d726f6c Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_arrow_top_left_white_24dp.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_arrow_top_left_black_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_arrow_top_left_black_24dp.png new file mode 100644 index 000000000..d536127b5 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_arrow_top_left_black_24dp.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_arrow_top_left_white_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_arrow_top_left_white_24dp.png new file mode 100644 index 000000000..0ddd5a8fa Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_arrow_top_left_white_24dp.png differ diff --git a/app/src/main/res/layout/dialog_title.xml b/app/src/main/res/layout/dialog_title.xml index dc76a4f20..fa7e155d2 100644 --- a/app/src/main/res/layout/dialog_title.xml +++ b/app/src/main/res/layout/dialog_title.xml @@ -6,7 +6,9 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:clickable="false" - android:padding="@dimen/video_item_search_padding"> + android:paddingLeft="@dimen/video_item_search_padding" + android:paddingRight="@dimen/video_item_search_padding" + android:paddingTop="@dimen/video_item_search_padding"> \ No newline at end of file diff --git a/app/src/main/res/layout/item_search_suggestion.xml b/app/src/main/res/layout/item_search_suggestion.xml index b230f6da0..bffc3ce89 100644 --- a/app/src/main/res/layout/item_search_suggestion.xml +++ b/app/src/main/res/layout/item_search_suggestion.xml @@ -1,36 +1,71 @@ - + android:orientation="horizontal"> - - - - \ No newline at end of file + android:background="?attr/selectableItemBackground" + android:clickable="true" + android:focusable="true" + android:layout_alignParentLeft="true" + android:layout_alignParentStart="true" + android:layout_toLeftOf="@id/suggestion_insert" + android:layout_toStartOf="@id/suggestion_insert" + android:layout_centerVertical="true" + android:paddingBottom="8dp" + android:paddingTop="8dp"> + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/player_notification.xml b/app/src/main/res/layout/player_notification.xml index 157615bb7..2a3e7aff3 100644 --- a/app/src/main/res/layout/player_notification.xml +++ b/app/src/main/res/layout/player_notification.xml @@ -34,22 +34,22 @@ diff --git a/app/src/main/res/layout/player_notification_expanded.xml b/app/src/main/res/layout/player_notification_expanded.xml index d37087312..7d59720e0 100644 --- a/app/src/main/res/layout/player_notification_expanded.xml +++ b/app/src/main/res/layout/player_notification_expanded.xml @@ -46,22 +46,22 @@ @@ -80,7 +80,6 @@ diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml index abf7c7b09..e51ab9ffd 100644 --- a/app/src/main/res/values/attrs.xml +++ b/app/src/main/res/values/attrs.xml @@ -20,6 +20,7 @@ + diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 3750bdb78..b77a2d229 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -39,7 +39,10 @@ #EEFFFFFF #ffffff #66000000 + #323232 + #ffffff + #999999 #e53935 #fff diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 8f0bb02cd..d41b3fe31 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -27,6 +27,7 @@ @drawable/ic_history_black_24dp @drawable/ic_drag_handle_black_24dp @drawable/ic_fiber_manual_record_black_24dp + @drawable/ic_arrow_top_left_black_24dp @color/light_separator_color @color/light_contrast_background_color @@ -65,6 +66,7 @@ @drawable/ic_history_white_24dp @drawable/ic_drag_handle_white_24dp @drawable/ic_fiber_manual_record_white_24dp + @drawable/ic_arrow_top_left_white_24dp @color/dark_separator_color @color/dark_contrast_background_color @@ -160,4 +162,12 @@ @color/dark_youtube_primary_color +