diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index f9201f948..e74a5a761 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -15,7 +15,7 @@ Oh no, a bug! It happens. Thanks for reporting an issue with NewPipe. To make it ### Checklist - + - [x] I am using the latest version - x.xx.x - [ ] I checked, but didn't find any duplicates (open OR closed) of this issue in the repo. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index c4d378d14..361c8057f 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -11,7 +11,7 @@ assignees: '' ### Checklist - + - [x] I checked, but didn't find any duplicates (open OR closed) of this issue in the repo. - [ ] I have read the contribution guidelines given at https://github.com/TeamNewPipe/NewPipe/blob/HEAD/.github/CONTRIBUTING.md. diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index e69de29bb..000000000 diff --git a/README.ko.md b/README.ko.md index a86eae8d9..1ca7be1be 100644 --- a/README.ko.md +++ b/README.ko.md @@ -6,7 +6,7 @@

- + @@ -98,7 +98,7 @@ NewPipe 코드의 변경이 있을 때(기능 추가 또는 버그 수정으로 1. 당신의 기록, 구독, 그리고 재생목록을 유지할 수 있도록 Settings > Content > Export Database 를 통해 데이터를 백업하십시오. 2. NewPipe를 삭제하십시오. 3. 새로운 소스에서 APK를 다운로드하고 이것을 설치하십시오. -4. Step 1의 Settings > Content > Export Database 을 통해 데이터를 불러오십시오. +4. Step 1의 Settings > Content > Import Database 을 통해 데이터를 불러오십시오. ## Contribution 당신이 아이디어, 번역, 디자인 변경, 코드 정리, 또는 정말 큰 코드 수정에 대한 의견이 있다면, 도움은 항상 환영합니다. diff --git a/README.md b/README.md index c66bcfa7f..006085a51 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@

- + diff --git a/app/build.gradle b/app/build.gradle index 58b5c25be..9fb9cf85f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -13,8 +13,8 @@ android { resValue "string", "app_name", "NewPipe" minSdkVersion 19 targetSdkVersion 29 - versionCode 960 - versionName "0.20.6" + versionCode 962 + versionName "0.20.8" multiDexEnabled true @@ -179,7 +179,7 @@ dependencies { // NewPipe dependencies // You can use a local version by uncommenting a few lines in settings.gradle - implementation 'com.github.B0pol:NewPipeExtractor:3ae924a7f18d5ee5b4aa0bd13d7179922cc094fa' + implementation 'com.github.TeamNewPipe:NewPipeExtractor:deb9af7bf53b3f8fd9d32322adae02df78d985ea' implementation "com.github.TeamNewPipe:nanojson:1d9e1aea9049fc9f85e68b43ba39fe7be1c1f751" implementation "org.jsoup:jsoup:1.13.1" @@ -203,6 +203,7 @@ dependencies { implementation 'androidx.core:core-ktx:1.3.2' implementation 'androidx.documentfile:documentfile:1.0.1' implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0' + implementation 'androidx.media:media:1.2.1' implementation 'androidx.webkit:webkit:1.4.0' implementation "androidx.lifecycle:lifecycle-livedata:${androidxLifecycleVersion}" diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index f0a38b54f..3509f2d13 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -266,7 +266,7 @@ - + @@ -318,6 +318,8 @@ android:name=".RouterActivity$FetcherService" android:exported="false" /> + + diff --git a/app/src/main/assets/epl1.html b/app/src/main/assets/epl1.html new file mode 100644 index 000000000..7123552dd --- /dev/null +++ b/app/src/main/assets/epl1.html @@ -0,0 +1,245 @@ + + + + + + + Eclipse Public License - Version 1.0 + + + + + +

Eclipse Public License - v 1.0

+ +

THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE + PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR + DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS + AGREEMENT.

+ +

1. DEFINITIONS

+ +

"Contribution" means:

+ +

a) in the case of the initial Contributor, the initial + code and documentation distributed under this Agreement, and

+

b) in the case of each subsequent Contributor:

+

i) changes to the Program, and

+

ii) additions to the Program;

+

where such changes and/or additions to the Program + originate from and are distributed by that particular Contributor. A + Contribution 'originates' from a Contributor if it was added to the + Program by such Contributor itself or anyone acting on such + Contributor's behalf. Contributions do not include additions to the + Program which: (i) are separate modules of software distributed in + conjunction with the Program under their own license agreement, and (ii) + are not derivative works of the Program.

+ +

"Contributor" means any person or entity that distributes + the Program.

+ +

"Licensed Patents" mean patent claims licensable by a + Contributor which are necessarily infringed by the use or sale of its + Contribution alone or when combined with the Program.

+ +

"Program" means the Contributions distributed in accordance + with this Agreement.

+ +

"Recipient" means anyone who receives the Program under + this Agreement, including all Contributors.

+ +

2. GRANT OF RIGHTS

+ +

a) Subject to the terms of this Agreement, each + Contributor hereby grants Recipient a non-exclusive, worldwide, + royalty-free copyright license to reproduce, prepare derivative works + of, publicly display, publicly perform, distribute and sublicense the + Contribution of such Contributor, if any, and such derivative works, in + source code and object code form.

+ +

b) Subject to the terms of this Agreement, each + Contributor hereby grants Recipient a non-exclusive, worldwide, + royalty-free patent license under Licensed Patents to make, use, sell, + offer to sell, import and otherwise transfer the Contribution of such + Contributor, if any, in source code and object code form. This patent + license shall apply to the combination of the Contribution and the + Program if, at the time the Contribution is added by the Contributor, + such addition of the Contribution causes such combination to be covered + by the Licensed Patents. The patent license shall not apply to any other + combinations which include the Contribution. No hardware per se is + licensed hereunder.

+ +

c) Recipient understands that although each Contributor + grants the licenses to its Contributions set forth herein, no assurances + are provided by any Contributor that the Program does not infringe the + patent or other intellectual property rights of any other entity. Each + Contributor disclaims any liability to Recipient for claims brought by + any other entity based on infringement of intellectual property rights + or otherwise. As a condition to exercising the rights and licenses + granted hereunder, each Recipient hereby assumes sole responsibility to + secure any other intellectual property rights needed, if any. For + example, if a third party patent license is required to allow Recipient + to distribute the Program, it is Recipient's responsibility to acquire + that license before distributing the Program.

+ +

d) Each Contributor represents that to its knowledge it + has sufficient copyright rights in its Contribution, if any, to grant + the copyright license set forth in this Agreement.

+ +

3. REQUIREMENTS

+ +

A Contributor may choose to distribute the Program in object code + form under its own license agreement, provided that:

+ +

a) it complies with the terms and conditions of this + Agreement; and

+ +

b) its license agreement:

+ +

i) effectively disclaims on behalf of all Contributors + all warranties and conditions, express and implied, including warranties + or conditions of title and non-infringement, and implied warranties or + conditions of merchantability and fitness for a particular purpose;

+ +

ii) effectively excludes on behalf of all Contributors + all liability for damages, including direct, indirect, special, + incidental and consequential damages, such as lost profits;

+ +

iii) states that any provisions which differ from this + Agreement are offered by that Contributor alone and not by any other + party; and

+ +

iv) states that source code for the Program is available + from such Contributor, and informs licensees how to obtain it in a + reasonable manner on or through a medium customarily used for software + exchange.

+ +

When the Program is made available in source code form:

+ +

a) it must be made available under this Agreement; and

+ +

b) a copy of this Agreement must be included with each + copy of the Program.

+ +

Contributors may not remove or alter any copyright notices contained + within the Program.

+ +

Each Contributor must identify itself as the originator of its + Contribution, if any, in a manner that reasonably allows subsequent + Recipients to identify the originator of the Contribution.

+ +

4. COMMERCIAL DISTRIBUTION

+ +

Commercial distributors of software may accept certain + responsibilities with respect to end users, business partners and the + like. While this license is intended to facilitate the commercial use of + the Program, the Contributor who includes the Program in a commercial + product offering should do so in a manner which does not create + potential liability for other Contributors. Therefore, if a Contributor + includes the Program in a commercial product offering, such Contributor + ("Commercial Contributor") hereby agrees to defend and + indemnify every other Contributor ("Indemnified Contributor") + against any losses, damages and costs (collectively "Losses") + arising from claims, lawsuits and other legal actions brought by a third + party against the Indemnified Contributor to the extent caused by the + acts or omissions of such Commercial Contributor in connection with its + distribution of the Program in a commercial product offering. The + obligations in this section do not apply to any claims or Losses + relating to any actual or alleged intellectual property infringement. In + order to qualify, an Indemnified Contributor must: a) promptly notify + the Commercial Contributor in writing of such claim, and b) allow the + Commercial Contributor to control, and cooperate with the Commercial + Contributor in, the defense and any related settlement negotiations. The + Indemnified Contributor may participate in any such claim at its own + expense.

+ +

For example, a Contributor might include the Program in a commercial + product offering, Product X. That Contributor is then a Commercial + Contributor. If that Commercial Contributor then makes performance + claims, or offers warranties related to Product X, those performance + claims and warranties are such Commercial Contributor's responsibility + alone. Under this section, the Commercial Contributor would have to + defend claims against the other Contributors related to those + performance claims and warranties, and if a court requires any other + Contributor to pay any damages as a result, the Commercial Contributor + must pay those damages.

+ +

5. NO WARRANTY

+ +

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS + PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS + OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, + ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY + OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely + responsible for determining the appropriateness of using and + distributing the Program and assumes all risks associated with its + exercise of rights under this Agreement , including but not limited to + the risks and costs of program errors, compliance with applicable laws, + damage to or loss of data, programs or equipment, and unavailability or + interruption of operations.

+ +

6. DISCLAIMER OF LIABILITY

+ +

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT + NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING + WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR + DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED + HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

+ +

7. GENERAL

+ +

If any provision of this Agreement is invalid or unenforceable under + applicable law, it shall not affect the validity or enforceability of + the remainder of the terms of this Agreement, and without further action + by the parties hereto, such provision shall be reformed to the minimum + extent necessary to make such provision valid and enforceable.

+ +

If Recipient institutes patent litigation against any entity + (including a cross-claim or counterclaim in a lawsuit) alleging that the + Program itself (excluding combinations of the Program with other + software or hardware) infringes such Recipient's patent(s), then such + Recipient's rights granted under Section 2(b) shall terminate as of the + date such litigation is filed.

+ +

All Recipient's rights under this Agreement shall terminate if it + fails to comply with any of the material terms or conditions of this + Agreement and does not cure such failure in a reasonable period of time + after becoming aware of such noncompliance. If all Recipient's rights + under this Agreement terminate, Recipient agrees to cease use and + distribution of the Program as soon as reasonably practicable. However, + Recipient's obligations under this Agreement and any licenses granted by + Recipient relating to the Program shall continue and survive.

+ +

Everyone is permitted to copy and distribute copies of this + Agreement, but in order to avoid inconsistency the Agreement is + copyrighted and may only be modified in the following manner. The + Agreement Steward reserves the right to publish new versions (including + revisions) of this Agreement from time to time. No one other than the + Agreement Steward has the right to modify this Agreement. The Eclipse + Foundation is the initial Agreement Steward. The Eclipse Foundation may + assign the responsibility to serve as the Agreement Steward to a + suitable separate entity. Each new version of the Agreement will be + given a distinguishing version number. The Program (including + Contributions) may always be distributed subject to the version of the + Agreement under which it was received. In addition, after a new version + of the Agreement is published, Contributor may elect to distribute the + Program (including its Contributions) under the new version. Except as + expressly stated in Sections 2(a) and 2(b) above, Recipient receives no + rights or licenses to the intellectual property of any Contributor under + this Agreement, whether expressly, by implication, estoppel or + otherwise. All rights in the Program not expressly granted under this + Agreement are reserved.

+ +

This Agreement is governed by the laws of the State of New York and + the intellectual property laws of the United States of America. No party + to this Agreement will bring a legal action under this Agreement more + than one year after the cause of action arose. Each party waives its + rights to a jury trial in any resulting litigation.

+ + + + \ No newline at end of file diff --git a/app/src/main/java/org/schabi/newpipe/App.java b/app/src/main/java/org/schabi/newpipe/App.java index e6dce4d67..7e3466f67 100644 --- a/app/src/main/java/org/schabi/newpipe/App.java +++ b/app/src/main/java/org/schabi/newpipe/App.java @@ -67,8 +67,10 @@ import io.reactivex.rxjava3.plugins.RxJavaPlugins; public class App extends MultiDexApplication { protected static final String TAG = App.class.toString(); private static App app; + public static final String PACKAGE_NAME = BuildConfig.APPLICATION_ID; - @Nullable private Disposable disposable = null; + @Nullable + private Disposable disposable = null; @NonNull public static App getApp() { diff --git a/app/src/main/java/org/schabi/newpipe/MainActivity.java b/app/src/main/java/org/schabi/newpipe/MainActivity.java index ff078fa2c..0c784e9d5 100644 --- a/app/src/main/java/org/schabi/newpipe/MainActivity.java +++ b/app/src/main/java/org/schabi/newpipe/MainActivity.java @@ -129,7 +129,7 @@ public class MainActivity extends AppCompatActivity { + "savedInstanceState = [" + savedInstanceState + "]"); } - // enable TLS1.1/1.2 for kitkat devices, to fix download and play for mediaCCC sources + // enable TLS1.1/1.2 for kitkat devices, to fix download and play for media.ccc.de sources if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) { TLSSocketFactoryCompat.setAsDefault(); } diff --git a/app/src/main/java/org/schabi/newpipe/about/AboutActivity.java b/app/src/main/java/org/schabi/newpipe/about/AboutActivity.java index 6ff691561..2569f4a94 100644 --- a/app/src/main/java/org/schabi/newpipe/about/AboutActivity.java +++ b/app/src/main/java/org/schabi/newpipe/about/AboutActivity.java @@ -29,37 +29,46 @@ public class AboutActivity extends AppCompatActivity { * List of all software components. */ private static final SoftwareComponent[] SOFTWARE_COMPONENTS = { - new SoftwareComponent("Giga Get", "2014 - 2015", "Peter Cai", + new SoftwareComponent("ACRA", "2013", "Kevin Gaudin", + "https://github.com/ACRA/acra", StandardLicenses.APACHE2), + new SoftwareComponent("AndroidX", "2005 - 2011", "The Android Open Source Project", + "https://developer.android.com/jetpack", StandardLicenses.APACHE2), + new SoftwareComponent("CircleImageView", "2014 - 2020", "Henning Dodenhof", + "https://github.com/hdodenhof/CircleImageView", + StandardLicenses.APACHE2), + new SoftwareComponent("ExoPlayer", "2014 - 2020", "Google, Inc.", + "https://github.com/google/ExoPlayer", StandardLicenses.APACHE2), + new SoftwareComponent("GigaGet", "2014 - 2015", "Peter Cai", "https://github.com/PaperAirplane-Dev-Team/GigaGet", StandardLicenses.GPL3), + new SoftwareComponent("Groupie", "2016", "Lisa Wray", + "https://github.com/lisawray/groupie", StandardLicenses.MIT), + new SoftwareComponent("Icepick", "2015", "Frankie Sardo", + "https://github.com/frankiesardo/icepick", StandardLicenses.EPL1), + new SoftwareComponent("Jsoup", "2009 - 2020", "Jonathan Hedley", + "https://github.com/jhy/jsoup", StandardLicenses.MIT), + new SoftwareComponent("Markwon", "2019", "Dimitry Ivanov", + "https://github.com/noties/Markwon", StandardLicenses.APACHE2), + new SoftwareComponent("Material Components for Android", "2016 - 2020", "Google, Inc.", + "https://github.com/material-components/material-components-android", + StandardLicenses.APACHE2), new SoftwareComponent("NewPipe Extractor", "2017 - 2020", "Christian Schabesberger", "https://github.com/TeamNewPipe/NewPipeExtractor", StandardLicenses.GPL3), - new SoftwareComponent("Jsoup", "2017", "Jonathan Hedley", - "https://github.com/jhy/jsoup", StandardLicenses.MIT), - new SoftwareComponent("Rhino", "2015", "Mozilla", - "https://www.mozilla.org/rhino/", StandardLicenses.MPL2), - new SoftwareComponent("ACRA", "2013", "Kevin Gaudin", - "http://www.acra.ch", StandardLicenses.APACHE2), + new SoftwareComponent("NoNonsense-FilePicker", "2016", "Jonas Kalderstam", + "https://github.com/spacecowboy/NoNonsense-FilePicker", + StandardLicenses.MPL2), + new SoftwareComponent("OkHttp", "2019", "Square, Inc.", + "https://square.github.io/okhttp/", StandardLicenses.APACHE2), + new SoftwareComponent("PrettyTime", "2012 - 2020", "Lincoln Baxter, III", + "https://github.com/ocpsoft/prettytime", StandardLicenses.APACHE2), + new SoftwareComponent("RxAndroid", "2015", "The RxAndroid authors", + "https://github.com/ReactiveX/RxAndroid", StandardLicenses.APACHE2), + new SoftwareComponent("RxBinding", "2015", "Jake Wharton", + "https://github.com/JakeWharton/RxBinding", StandardLicenses.APACHE2), + new SoftwareComponent("RxJava", "2016 - 2020", "RxJava Contributors", + "https://github.com/ReactiveX/RxJava", StandardLicenses.APACHE2), new SoftwareComponent("Universal Image Loader", "2011 - 2015", "Sergey Tarasevich", "https://github.com/nostra13/Android-Universal-Image-Loader", StandardLicenses.APACHE2), - new SoftwareComponent("CircleImageView", "2014 - 2020", "Henning Dodenhof", - "https://github.com/hdodenhof/CircleImageView", StandardLicenses.APACHE2), - new SoftwareComponent("NoNonsense-FilePicker", "2016", "Jonas Kalderstam", - "https://github.com/spacecowboy/NoNonsense-FilePicker", StandardLicenses.MPL2), - new SoftwareComponent("ExoPlayer", "2014 - 2020", "Google Inc", - "https://github.com/google/ExoPlayer", StandardLicenses.APACHE2), - new SoftwareComponent("RxAndroid", "2015 - 2018", "The RxAndroid authors", - "https://github.com/ReactiveX/RxAndroid", StandardLicenses.APACHE2), - new SoftwareComponent("RxJava", "2016 - 2020", "RxJava Contributors", - "https://github.com/ReactiveX/RxJava", StandardLicenses.APACHE2), - new SoftwareComponent("RxBinding", "2015 - 2018", "Jake Wharton", - "https://github.com/JakeWharton/RxBinding", StandardLicenses.APACHE2), - new SoftwareComponent("PrettyTime", "2012 - 2020", "Lincoln Baxter, III", - "https://github.com/ocpsoft/prettytime", StandardLicenses.APACHE2), - new SoftwareComponent("Markwon", "2017 - 2020", "Noties", - "https://github.com/noties/Markwon", StandardLicenses.APACHE2), - new SoftwareComponent("Groupie", "2016", "Lisa Wray", - "https://github.com/lisawray/groupie", StandardLicenses.MIT) }; private static final int POS_ABOUT = 0; @@ -115,7 +124,8 @@ public class AboutActivity extends AppCompatActivity { * A placeholder fragment containing a simple view. */ public static class AboutFragment extends Fragment { - public AboutFragment() { } + public AboutFragment() { + } /** * Created a new instance of this fragment for the given section number. diff --git a/app/src/main/java/org/schabi/newpipe/about/LicenseFragment.java b/app/src/main/java/org/schabi/newpipe/about/LicenseFragment.java index 8367a75dc..6e48a0e14 100644 --- a/app/src/main/java/org/schabi/newpipe/about/LicenseFragment.java +++ b/app/src/main/java/org/schabi/newpipe/about/LicenseFragment.java @@ -19,6 +19,7 @@ import org.schabi.newpipe.util.ShareUtils; import java.io.Serializable; import java.util.Arrays; import java.util.Comparator; +import java.util.Objects; import io.reactivex.rxjava3.disposables.CompositeDisposable; @@ -35,12 +36,9 @@ public class LicenseFragment extends Fragment { private final CompositeDisposable compositeDisposable = new CompositeDisposable(); public static LicenseFragment newInstance(final SoftwareComponent[] softwareComponents) { - if (softwareComponents == null) { - throw new NullPointerException("softwareComponents is null"); - } - final LicenseFragment fragment = new LicenseFragment(); final Bundle bundle = new Bundle(); - bundle.putParcelableArray(ARG_COMPONENTS, softwareComponents); + bundle.putParcelableArray(ARG_COMPONENTS, Objects.requireNonNull(softwareComponents)); + final LicenseFragment fragment = new LicenseFragment(); fragment.setArguments(bundle); return fragment; } diff --git a/app/src/main/java/org/schabi/newpipe/about/StandardLicenses.java b/app/src/main/java/org/schabi/newpipe/about/StandardLicenses.java index 50ee5ebc3..60b1e168c 100644 --- a/app/src/main/java/org/schabi/newpipe/about/StandardLicenses.java +++ b/app/src/main/java/org/schabi/newpipe/about/StandardLicenses.java @@ -12,6 +12,8 @@ public final class StandardLicenses { = new License("Mozilla Public License, Version 2.0", "MPL 2.0", "mpl2.html"); public static final License MIT = new License("MIT License", "MIT", "mit.html"); + public static final License EPL1 + = new License("Eclipse Public License, Version 1.0", "EPL 1.0", "epl1.html"); private StandardLicenses() { } } 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 6560ab404..aeb51f63a 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 @@ -146,15 +146,15 @@ public final class VideoDetailFragment private static final float MAX_PLAYER_HEIGHT = 0.7f; public static final String ACTION_SHOW_MAIN_PLAYER = - "org.schabi.newpipe.VideoDetailFragment.ACTION_SHOW_MAIN_PLAYER"; + App.PACKAGE_NAME + ".VideoDetailFragment.ACTION_SHOW_MAIN_PLAYER"; public static final String ACTION_HIDE_MAIN_PLAYER = - "org.schabi.newpipe.VideoDetailFragment.ACTION_HIDE_MAIN_PLAYER"; + App.PACKAGE_NAME + ".VideoDetailFragment.ACTION_HIDE_MAIN_PLAYER"; public static final String ACTION_PLAYER_STARTED = - "org.schabi.newpipe.VideoDetailFragment.ACTION_PLAYER_STARTED"; + App.PACKAGE_NAME + ".VideoDetailFragment.ACTION_PLAYER_STARTED"; public static final String ACTION_VIDEO_FRAGMENT_RESUMED = - "org.schabi.newpipe.VideoDetailFragment.ACTION_VIDEO_FRAGMENT_RESUMED"; + App.PACKAGE_NAME + ".VideoDetailFragment.ACTION_VIDEO_FRAGMENT_RESUMED"; public static final String ACTION_VIDEO_FRAGMENT_STOPPED = - "org.schabi.newpipe.VideoDetailFragment.ACTION_VIDEO_FRAGMENT_STOPPED"; + App.PACKAGE_NAME + ".VideoDetailFragment.ACTION_VIDEO_FRAGMENT_STOPPED"; private static final String COMMENTS_TAB_TAG = "COMMENTS"; private static final String RELATED_TAB_TAG = "NEXT VIDEO"; @@ -498,10 +498,10 @@ public final class VideoDetailFragment final PlaylistAppendDialog d = PlaylistAppendDialog.fromStreamInfo(currentInfo); disposables.add( - PlaylistAppendDialog.onPlaylistFound(getContext(), - () -> d.show(getFM(), TAG), - () -> PlaylistCreationDialog.newInstance(d).show(getFM(), TAG) - ) + PlaylistAppendDialog.onPlaylistFound(getContext(), + () -> d.show(getFM(), TAG), + () -> PlaylistCreationDialog.newInstance(d).show(getFM(), TAG) + ) ); } break; @@ -1891,8 +1891,10 @@ public final class VideoDetailFragment if (fullscreen) { hideSystemUiIfNeeded(); + viewPager.setVisibility(View.GONE); } else { showSystemUi(); + viewPager.setVisibility(View.VISIBLE); } if (relatedStreamsLayout != null) { @@ -2048,6 +2050,10 @@ public final class VideoDetailFragment // Apply system brightness when the player is not in fullscreen restoreDefaultBrightness(); } else { + // Do not restore if user has disabled brightness gesture + if (!PlayerHelper.isBrightnessGestureEnabled(activity)) { + return; + } // Restore already saved brightness level final float brightnessLevel = PlayerHelper.getScreenBrightness(activity); if (brightnessLevel == lp.screenBrightness) { diff --git a/app/src/main/java/org/schabi/newpipe/info_list/holder/StreamMiniInfoItemHolder.java b/app/src/main/java/org/schabi/newpipe/info_list/holder/StreamMiniInfoItemHolder.java index c0096ed10..12eab4734 100644 --- a/app/src/main/java/org/schabi/newpipe/info_list/holder/StreamMiniInfoItemHolder.java +++ b/app/src/main/java/org/schabi/newpipe/info_list/holder/StreamMiniInfoItemHolder.java @@ -70,7 +70,8 @@ public class StreamMiniInfoItemHolder extends InfoItemHolder { } else { itemProgressView.setVisibility(View.GONE); } - } else if (item.getStreamType() == StreamType.LIVE_STREAM) { + } else if (item.getStreamType() == StreamType.LIVE_STREAM + || item.getStreamType() == StreamType.AUDIO_LIVE_STREAM) { itemDurationView.setText(R.string.duration_live); itemDurationView.setBackgroundColor(ContextCompat.getColor(itemBuilder.getContext(), R.color.live_duration_background_color)); diff --git a/app/src/main/java/org/schabi/newpipe/local/feed/service/FeedLoadService.kt b/app/src/main/java/org/schabi/newpipe/local/feed/service/FeedLoadService.kt index 2a0aa1c90..45e8855e7 100644 --- a/app/src/main/java/org/schabi/newpipe/local/feed/service/FeedLoadService.kt +++ b/app/src/main/java/org/schabi/newpipe/local/feed/service/FeedLoadService.kt @@ -43,6 +43,7 @@ import io.reactivex.rxjava3.processors.PublishProcessor import io.reactivex.rxjava3.schedulers.Schedulers import org.reactivestreams.Subscriber import org.reactivestreams.Subscription +import org.schabi.newpipe.App import org.schabi.newpipe.MainActivity.DEBUG import org.schabi.newpipe.R import org.schabi.newpipe.database.feed.model.FeedGroupEntity @@ -68,7 +69,7 @@ class FeedLoadService : Service() { companion object { private val TAG = FeedLoadService::class.java.simpleName private const val NOTIFICATION_ID = 7293450 - private const val ACTION_CANCEL = "org.schabi.newpipe.local.feed.service.FeedLoadService.CANCEL" + private const val ACTION_CANCEL = App.PACKAGE_NAME + ".local.feed.service.FeedLoadService.CANCEL" /** * How often the notification will be updated. diff --git a/app/src/main/java/org/schabi/newpipe/local/subscription/services/SubscriptionsExportService.java b/app/src/main/java/org/schabi/newpipe/local/subscription/services/SubscriptionsExportService.java index 982701d1f..5dfb1bfe5 100644 --- a/app/src/main/java/org/schabi/newpipe/local/subscription/services/SubscriptionsExportService.java +++ b/app/src/main/java/org/schabi/newpipe/local/subscription/services/SubscriptionsExportService.java @@ -27,6 +27,7 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager; import org.reactivestreams.Subscriber; import org.reactivestreams.Subscription; +import org.schabi.newpipe.App; import org.schabi.newpipe.R; import org.schabi.newpipe.database.subscription.SubscriptionEntity; import org.schabi.newpipe.extractor.subscription.SubscriptionItem; @@ -50,7 +51,7 @@ public class SubscriptionsExportService extends BaseImportExportService { * A {@link LocalBroadcastManager local broadcast} will be made with this action * when the export is successfully completed. */ - public static final String EXPORT_COMPLETE_ACTION = "org.schabi.newpipe.local.subscription" + public static final String EXPORT_COMPLETE_ACTION = App.PACKAGE_NAME + ".local.subscription" + ".services.SubscriptionsExportService.EXPORT_COMPLETE"; private Subscription subscription; diff --git a/app/src/main/java/org/schabi/newpipe/local/subscription/services/SubscriptionsImportService.java b/app/src/main/java/org/schabi/newpipe/local/subscription/services/SubscriptionsImportService.java index b1c67719c..90d0afe37 100644 --- a/app/src/main/java/org/schabi/newpipe/local/subscription/services/SubscriptionsImportService.java +++ b/app/src/main/java/org/schabi/newpipe/local/subscription/services/SubscriptionsImportService.java @@ -29,6 +29,7 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager; import org.reactivestreams.Subscriber; import org.reactivestreams.Subscription; +import org.schabi.newpipe.App; import org.schabi.newpipe.R; import org.schabi.newpipe.database.subscription.SubscriptionEntity; import org.schabi.newpipe.extractor.NewPipe; @@ -66,7 +67,7 @@ public class SubscriptionsImportService extends BaseImportExportService { * A {@link LocalBroadcastManager local broadcast} will be made with this action * when the import is successfully completed. */ - public static final String IMPORT_COMPLETE_ACTION = "org.schabi.newpipe.local.subscription" + public static final String IMPORT_COMPLETE_ACTION = App.PACKAGE_NAME + ".local.subscription" + ".services.SubscriptionsImportService.IMPORT_COMPLETE"; /** 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 d5ad9cb6f..8eae33de6 100644 --- a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java @@ -19,6 +19,12 @@ package org.schabi.newpipe.player; +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 java.util.concurrent.TimeUnit.MILLISECONDS; + import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -30,11 +36,9 @@ import android.media.AudioManager; import android.util.Log; import android.view.View; import android.widget.Toast; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.preference.PreferenceManager; - import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.DefaultRenderersFactory; import com.google.android.exoplayer2.ExoPlaybackException; @@ -53,7 +57,12 @@ import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter; import com.nostra13.universalimageloader.core.ImageLoader; import com.nostra13.universalimageloader.core.assist.FailReason; import com.nostra13.universalimageloader.core.listener.ImageLoadingListener; - +import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; +import io.reactivex.rxjava3.core.Observable; +import io.reactivex.rxjava3.disposables.CompositeDisposable; +import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.disposables.SerialDisposable; +import java.io.IOException; import org.schabi.newpipe.DownloaderImpl; import org.schabi.newpipe.MainActivity; import org.schabi.newpipe.R; @@ -75,20 +84,6 @@ import org.schabi.newpipe.player.resolver.MediaSourceTag; import org.schabi.newpipe.util.ImageDisplayConstants; import org.schabi.newpipe.util.SerializedCache; -import java.io.IOException; - -import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; -import io.reactivex.rxjava3.core.Observable; -import io.reactivex.rxjava3.disposables.CompositeDisposable; -import io.reactivex.rxjava3.disposables.Disposable; -import io.reactivex.rxjava3.disposables.SerialDisposable; - -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 java.util.concurrent.TimeUnit.MILLISECONDS; - /** * Base for the players, joining the common properties. * @@ -342,37 +337,36 @@ public abstract class BasePlayer implements simpleExoPlayer.setPlayWhenReady(playWhenReady); } else if (intent.getBooleanExtra(RESUME_PLAYBACK, false) - && isPlaybackResumeEnabled() - && !samePlayQueue) { - final PlayQueueItem item = queue.getItem(); - if (item != null && item.getRecoveryPosition() == PlayQueueItem.RECOVERY_UNSET) { - stateLoader = recordManager.loadStreamState(item) - .observeOn(AndroidSchedulers.mainThread()) - // Do not place initPlayback() in doFinally() because - // it restarts playback after destroy() - //.doFinally() - .subscribe( - state -> { - queue.setRecovery(queue.getIndex(), state.getProgressTime()); - initPlayback(queue, repeatMode, playbackSpeed, playbackPitch, - playbackSkipSilence, playWhenReady, isMuted); - }, - error -> { - if (DEBUG) { - error.printStackTrace(); - } - // In case any error we can start playback without history - initPlayback(queue, repeatMode, playbackSpeed, playbackPitch, - playbackSkipSilence, playWhenReady, isMuted); - }, - () -> { - // Completed but not found in history + && isPlaybackResumeEnabled() + && !samePlayQueue + && !queue.isEmpty() + && queue.getItem().getRecoveryPosition() == PlayQueueItem.RECOVERY_UNSET) { + stateLoader = recordManager.loadStreamState(queue.getItem()) + .observeOn(AndroidSchedulers.mainThread()) + // Do not place initPlayback() in doFinally() because + // it restarts playback after destroy() + //.doFinally() + .subscribe( + state -> { + queue.setRecovery(queue.getIndex(), state.getProgressTime()); + initPlayback(queue, repeatMode, playbackSpeed, playbackPitch, + playbackSkipSilence, playWhenReady, isMuted); + }, + error -> { + if (DEBUG) { + error.printStackTrace(); + } + // In case any error we can start playback without history + initPlayback(queue, repeatMode, playbackSpeed, playbackPitch, + playbackSkipSilence, playWhenReady, isMuted); + }, + () -> { + // Completed but not found in history initPlayback(queue, repeatMode, playbackSpeed, playbackPitch, playbackSkipSilence, playWhenReady, isMuted); } ); databaseUpdateReactor.add(stateLoader); - } } else { // Good to go... // In a case of equal PlayQueues we can re-init old one but only when it is disposed diff --git a/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java b/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java index 63f6a400e..49c836346 100644 --- a/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java @@ -33,6 +33,7 @@ import android.view.WindowManager; import androidx.annotation.Nullable; import androidx.core.content.ContextCompat; +import org.schabi.newpipe.App; import org.schabi.newpipe.R; import org.schabi.newpipe.util.ThemeHelper; @@ -64,25 +65,25 @@ public final class MainPlayer extends Service { //////////////////////////////////////////////////////////////////////////*/ static final String ACTION_CLOSE - = "org.schabi.newpipe.player.MainPlayer.CLOSE"; + = App.PACKAGE_NAME + ".player.MainPlayer.CLOSE"; static final String ACTION_PLAY_PAUSE - = "org.schabi.newpipe.player.MainPlayer.PLAY_PAUSE"; + = App.PACKAGE_NAME + ".player.MainPlayer.PLAY_PAUSE"; static final String ACTION_OPEN_CONTROLS - = "org.schabi.newpipe.player.MainPlayer.OPEN_CONTROLS"; + = App.PACKAGE_NAME + ".player.MainPlayer.OPEN_CONTROLS"; static final String ACTION_REPEAT - = "org.schabi.newpipe.player.MainPlayer.REPEAT"; + = App.PACKAGE_NAME + ".player.MainPlayer.REPEAT"; static final String ACTION_PLAY_NEXT - = "org.schabi.newpipe.player.MainPlayer.ACTION_PLAY_NEXT"; + = App.PACKAGE_NAME + ".player.MainPlayer.ACTION_PLAY_NEXT"; static final String ACTION_PLAY_PREVIOUS - = "org.schabi.newpipe.player.MainPlayer.ACTION_PLAY_PREVIOUS"; + = App.PACKAGE_NAME + ".player.MainPlayer.ACTION_PLAY_PREVIOUS"; static final String ACTION_FAST_REWIND - = "org.schabi.newpipe.player.MainPlayer.ACTION_FAST_REWIND"; + = App.PACKAGE_NAME + ".player.MainPlayer.ACTION_FAST_REWIND"; static final String ACTION_FAST_FORWARD - = "org.schabi.newpipe.player.MainPlayer.ACTION_FAST_FORWARD"; + = App.PACKAGE_NAME + ".player.MainPlayer.ACTION_FAST_FORWARD"; static final String ACTION_SHUFFLE - = "org.schabi.newpipe.player.MainPlayer.ACTION_SHUFFLE"; + = App.PACKAGE_NAME + ".player.MainPlayer.ACTION_SHUFFLE"; public static final String ACTION_RECREATE_NOTIFICATION - = "org.schabi.newpipe.player.MainPlayer.ACTION_RECREATE_NOTIFICATION"; + = App.PACKAGE_NAME + ".player.MainPlayer.ACTION_RECREATE_NOTIFICATION"; /*////////////////////////////////////////////////////////////////////////// // Service's LifeCycle 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 41d66dc90..fd20fd175 100644 --- a/app/src/main/java/org/schabi/newpipe/player/ServicePlayerActivity.java +++ b/app/src/main/java/org/schabi/newpipe/player/ServicePlayerActivity.java @@ -638,12 +638,12 @@ public abstract class ServicePlayerActivity extends AppCompatActivity case BasePlayer.STATE_COMPLETED: queueControlBinding.controlPlayPause.setClickable(true); queueControlBinding.controlPlayPause.setVisibility(View.VISIBLE); - queueControlBinding.progressBar.setVisibility(View.GONE); + queueControlBinding.controlProgressBar.setVisibility(View.GONE); break; default: queueControlBinding.controlPlayPause.setClickable(false); queueControlBinding.controlPlayPause.setVisibility(View.INVISIBLE); - queueControlBinding.progressBar.setVisibility(View.VISIBLE); + queueControlBinding.controlProgressBar.setVisibility(View.VISIBLE); break; } } diff --git a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java index a304b4430..10887790b 100644 --- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java +++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java @@ -505,6 +505,11 @@ public class VideoPlayerImpl extends VideoPlayer switch (keyCode) { default: break; + case KeyEvent.KEYCODE_SPACE: + if (isFullscreen) { + onPlayPause(); + } + break; case KeyEvent.KEYCODE_BACK: if (DeviceUtils.isTv(service) && isControlsVisible()) { hideControls(0, 0); @@ -1071,11 +1076,25 @@ public class VideoPlayerImpl extends VideoPlayer private void animatePlayButtons(final boolean show, final int duration) { animateView(playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, show, duration); - if (playQueue.getIndex() > 0 || !show) { - animateView(playPreviousButton, AnimationUtils.Type.SCALE_AND_ALPHA, show, duration); + + boolean showQueueButtons = show; + if (playQueue == null) { + showQueueButtons = false; } - if (playQueue.getIndex() + 1 < playQueue.getStreams().size() || !show) { - animateView(playNextButton, AnimationUtils.Type.SCALE_AND_ALPHA, show, duration); + + if (!showQueueButtons || playQueue.getIndex() > 0) { + animateView( + playPreviousButton, + AnimationUtils.Type.SCALE_AND_ALPHA, + showQueueButtons, + duration); + } + if (!showQueueButtons || playQueue.getIndex() + 1 < playQueue.getStreams().size()) { + animateView( + playNextButton, + AnimationUtils.Type.SCALE_AND_ALPHA, + showQueueButtons, + duration); } } diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/AudioReactor.java b/app/src/main/java/org/schabi/newpipe/player/helper/AudioReactor.java index ffe19599d..13ee24e16 100644 --- a/app/src/main/java/org/schabi/newpipe/player/helper/AudioReactor.java +++ b/app/src/main/java/org/schabi/newpipe/player/helper/AudioReactor.java @@ -5,14 +5,14 @@ import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.content.Context; import android.content.Intent; -import android.media.AudioFocusRequest; import android.media.AudioManager; import android.media.audiofx.AudioEffect; -import android.os.Build; import android.util.Log; import androidx.annotation.NonNull; import androidx.core.content.ContextCompat; +import androidx.media.AudioFocusRequestCompat; +import androidx.media.AudioManagerCompat; import com.google.android.exoplayer2.SimpleExoPlayer; import com.google.android.exoplayer2.analytics.AnalyticsListener; @@ -21,20 +21,17 @@ public class AudioReactor implements AudioManager.OnAudioFocusChangeListener, An private static final String TAG = "AudioFocusReactor"; - private static final boolean SHOULD_BUILD_FOCUS_REQUEST = - Build.VERSION.SDK_INT >= Build.VERSION_CODES.O; - private static final int DUCK_DURATION = 1500; private static final float DUCK_AUDIO_TO = .2f; - private static final int FOCUS_GAIN_TYPE = AudioManager.AUDIOFOCUS_GAIN; + private static final int FOCUS_GAIN_TYPE = AudioManagerCompat.AUDIOFOCUS_GAIN; private static final int STREAM_TYPE = AudioManager.STREAM_MUSIC; private final SimpleExoPlayer player; private final Context context; private final AudioManager audioManager; - private final AudioFocusRequest request; + private final AudioFocusRequestCompat request; public AudioReactor(@NonNull final Context context, @NonNull final SimpleExoPlayer player) { @@ -43,15 +40,11 @@ public class AudioReactor implements AudioManager.OnAudioFocusChangeListener, An this.audioManager = ContextCompat.getSystemService(context, AudioManager.class); player.addAnalyticsListener(this); - if (SHOULD_BUILD_FOCUS_REQUEST) { - request = new AudioFocusRequest.Builder(FOCUS_GAIN_TYPE) - .setAcceptsDelayedFocusGain(true) - .setWillPauseWhenDucked(true) - .setOnAudioFocusChangeListener(this) - .build(); - } else { - request = null; - } + request = new AudioFocusRequestCompat.Builder(FOCUS_GAIN_TYPE) + //.setAcceptsDelayedFocusGain(true) + .setWillPauseWhenDucked(true) + .setOnAudioFocusChangeListener(this) + .build(); } public void dispose() { @@ -64,19 +57,11 @@ public class AudioReactor implements AudioManager.OnAudioFocusChangeListener, An //////////////////////////////////////////////////////////////////////////*/ public void requestAudioFocus() { - if (SHOULD_BUILD_FOCUS_REQUEST) { - audioManager.requestAudioFocus(request); - } else { - audioManager.requestAudioFocus(this, STREAM_TYPE, FOCUS_GAIN_TYPE); - } + AudioManagerCompat.requestAudioFocus(audioManager, request); } public void abandonAudioFocus() { - if (SHOULD_BUILD_FOCUS_REQUEST) { - audioManager.abandonAudioFocusRequest(request); - } else { - audioManager.abandonAudioFocus(this); - } + AudioManagerCompat.abandonAudioFocusRequest(audioManager, request); } public int getVolume() { @@ -88,7 +73,7 @@ public class AudioReactor implements AudioManager.OnAudioFocusChangeListener, An } public int getMaxVolume() { - return audioManager.getStreamMaxVolume(STREAM_TYPE); + return AudioManagerCompat.getStreamMaxVolume(audioManager, STREAM_TYPE); } /*////////////////////////////////////////////////////////////////////////// diff --git a/app/src/main/java/org/schabi/newpipe/settings/DownloadSettingsFragment.java b/app/src/main/java/org/schabi/newpipe/settings/DownloadSettingsFragment.java index a4b29fc49..8742f0937 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/DownloadSettingsFragment.java +++ b/app/src/main/java/org/schabi/newpipe/settings/DownloadSettingsFragment.java @@ -246,10 +246,7 @@ public class DownloadSettingsFragment extends BasePreferenceFragment { // revoke permissions on the old save path (required for SAF only) - final Context context = getContext(); - if (context == null) { - throw new NullPointerException("getContext()"); - } + final Context context = requireContext(); forgetSAFTree(context, defaultPreferences.getString(key, "")); diff --git a/app/src/main/java/org/schabi/newpipe/util/KioskTranslator.java b/app/src/main/java/org/schabi/newpipe/util/KioskTranslator.java index ccd4d13fc..d2daaf6cc 100644 --- a/app/src/main/java/org/schabi/newpipe/util/KioskTranslator.java +++ b/app/src/main/java/org/schabi/newpipe/util/KioskTranslator.java @@ -44,6 +44,10 @@ public final class KioskTranslator { return c.getString(R.string.most_liked); case "conferences": return c.getString(R.string.conferences); + case "recent": + return c.getString(R.string.recent); + case "live": + return c.getString(R.string.duration_live); default: return kioskId; } @@ -59,9 +63,12 @@ public final class KioskTranslator { case "Local": return ThemeHelper.resolveResourceIdFromAttr(c, R.attr.ic_kiosk_local); case "Recently added": + case "recent": return ThemeHelper.resolveResourceIdFromAttr(c, R.attr.ic_kiosk_recent); case "Most liked": return ThemeHelper.resolveResourceIdFromAttr(c, R.attr.ic_thumb_up); + case "live": + return ThemeHelper.resolveResourceIdFromAttr(c, R.attr.ic_live_tv); default: return 0; } diff --git a/app/src/main/java/us/shandian/giga/get/DownloadMission.java b/app/src/main/java/us/shandian/giga/get/DownloadMission.java index d7c586083..2b3faa3e0 100644 --- a/app/src/main/java/us/shandian/giga/get/DownloadMission.java +++ b/app/src/main/java/us/shandian/giga/get/DownloadMission.java @@ -22,6 +22,7 @@ import java.net.SocketTimeoutException; import java.net.URL; import java.net.UnknownHostException; import java.nio.channels.ClosedByInterruptException; +import java.util.Objects; import javax.net.ssl.SSLException; @@ -154,8 +155,8 @@ public class DownloadMission extends Mission { public transient Thread init = null; public DownloadMission(String[] urls, StoredFileHelper storage, char kind, Postprocessing psInstance) { - if (urls == null) throw new NullPointerException("urls is null"); - if (urls.length < 1) throw new IllegalArgumentException("urls is empty"); + if (Objects.requireNonNull(urls).length < 1) + throw new IllegalArgumentException("urls array is empty"); this.urls = urls; this.kind = kind; this.offsets = new long[urls.length]; diff --git a/app/src/main/java/us/shandian/giga/get/DownloadRunnable.java b/app/src/main/java/us/shandian/giga/get/DownloadRunnable.java index 7fb12d088..6f504cea3 100644 --- a/app/src/main/java/us/shandian/giga/get/DownloadRunnable.java +++ b/app/src/main/java/us/shandian/giga/get/DownloadRunnable.java @@ -8,6 +8,7 @@ import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.nio.channels.ClosedByInterruptException; +import java.util.Objects; import us.shandian.giga.get.DownloadMission.Block; import us.shandian.giga.get.DownloadMission.HttpError; @@ -29,8 +30,7 @@ public class DownloadRunnable extends Thread { private HttpURLConnection mConn; DownloadRunnable(DownloadMission mission, int id) { - if (mission == null) throw new NullPointerException("mission is null"); - mMission = mission; + mMission = Objects.requireNonNull(mission); mId = id; } diff --git a/app/src/main/java/us/shandian/giga/get/sqlite/FinishedMissionStore.java b/app/src/main/java/us/shandian/giga/get/sqlite/FinishedMissionStore.java index 1d1dca0df..15c45c6fd 100644 --- a/app/src/main/java/us/shandian/giga/get/sqlite/FinishedMissionStore.java +++ b/app/src/main/java/us/shandian/giga/get/sqlite/FinishedMissionStore.java @@ -12,6 +12,7 @@ import androidx.annotation.NonNull; import java.io.File; import java.util.ArrayList; +import java.util.Objects; import us.shandian.giga.get.DownloadMission; import us.shandian.giga.get.FinishedMission; @@ -140,9 +141,7 @@ public class FinishedMissionStore extends SQLiteOpenHelper { } private FinishedMission getMissionFromCursor(Cursor cursor) { - if (cursor == null) throw new NullPointerException("cursor is null"); - - String kind = cursor.getString(cursor.getColumnIndex(KEY_KIND)); + String kind = Objects.requireNonNull(cursor).getString(cursor.getColumnIndex(KEY_KIND)); if (kind == null || kind.isEmpty()) kind = "?"; String path = cursor.getString(cursor.getColumnIndexOrThrow(KEY_PATH)); @@ -186,15 +185,13 @@ public class FinishedMissionStore extends SQLiteOpenHelper { } public void addFinishedMission(DownloadMission downloadMission) { - if (downloadMission == null) throw new NullPointerException("downloadMission is null"); + ContentValues values = getValuesOfMission(Objects.requireNonNull(downloadMission)); SQLiteDatabase database = getWritableDatabase(); - ContentValues values = getValuesOfMission(downloadMission); database.insert(FINISHED_TABLE_NAME, null, values); } public void deleteMission(Mission mission) { - if (mission == null) throw new NullPointerException("mission is null"); - String ts = String.valueOf(mission.timestamp); + String ts = String.valueOf(Objects.requireNonNull(mission).timestamp); SQLiteDatabase database = getWritableDatabase(); @@ -212,9 +209,8 @@ public class FinishedMissionStore extends SQLiteOpenHelper { } public void updateMission(Mission mission) { - if (mission == null) throw new NullPointerException("mission is null"); + ContentValues values = getValuesOfMission(Objects.requireNonNull(mission)); SQLiteDatabase database = getWritableDatabase(); - ContentValues values = getValuesOfMission(mission); String ts = String.valueOf(mission.timestamp); int rowsAffected; diff --git a/app/src/main/java/us/shandian/giga/io/CircularFileWriter.java b/app/src/main/java/us/shandian/giga/io/CircularFileWriter.java index 4d62ab200..dbceeb091 100644 --- a/app/src/main/java/us/shandian/giga/io/CircularFileWriter.java +++ b/app/src/main/java/us/shandian/giga/io/CircularFileWriter.java @@ -7,6 +7,7 @@ import org.schabi.newpipe.streams.io.SharpStream; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; +import java.util.Objects; public class CircularFileWriter extends SharpStream { @@ -27,9 +28,7 @@ public class CircularFileWriter extends SharpStream { private BufferedFile aux; public CircularFileWriter(SharpStream target, File temp, OffsetChecker checker) throws IOException { - if (checker == null) { - throw new NullPointerException("checker is null"); - } + Objects.requireNonNull(checker); if (!temp.exists()) { if (!temp.createNewFile()) { diff --git a/app/src/main/res/drawable/ic_live_tv_black_24dp.xml b/app/src/main/res/drawable/ic_live_tv_black_24dp.xml new file mode 100644 index 000000000..1f7957c4a --- /dev/null +++ b/app/src/main/res/drawable/ic_live_tv_black_24dp.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_live_tv_white_24dp.xml b/app/src/main/res/drawable/ic_live_tv_white_24dp.xml new file mode 100644 index 000000000..303858f9d --- /dev/null +++ b/app/src/main/res/drawable/ic_live_tv_white_24dp.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/values-v21/styles_services.xml b/app/src/main/res/values-v21/styles_services.xml index e5b675ef8..c495a9a31 100644 --- a/app/src/main/res/values-v21/styles_services.xml +++ b/app/src/main/res/values-v21/styles_services.xml @@ -12,6 +12,7 @@ + - - - - - - - -