Merge pull request #2697 from Redirion/exoplayer2105

Update to ExoPlayer 2.10.5
This commit is contained in:
Tobias Groza 2019-10-10 14:01:05 +02:00 committed by GitHub
commit 28ed9879aa
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 103 additions and 122 deletions

View file

@ -44,10 +44,10 @@ android {
ext { ext {
androidxLibVersion = '1.0.0' androidxLibVersion = '1.0.0'
exoPlayerLibVersion = '2.9.6' //2.10.5 exoPlayerLibVersion = '2.10.5'
roomDbLibVersion = '2.1.0' roomDbLibVersion = '2.1.0'
leakCanaryLibVersion = '1.5.4' //1.6.1 leakCanaryLibVersion = '1.5.4' //1.6.1
okHttpLibVersion = '3.12.1' okHttpLibVersion = '3.12.5' //3.12.6
icepickLibVersion = '3.2.0' icepickLibVersion = '3.2.0'
stethoLibVersion = '1.5.0' stethoLibVersion = '1.5.0'
} }

View file

@ -28,17 +28,7 @@ import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import androidx.annotation.NonNull;
import com.google.android.material.navigation.NavigationView;
import androidx.fragment.app.Fragment;
import androidx.core.view.GravityCompat;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import android.util.Log; import android.util.Log;
import android.view.Gravity;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
@ -49,6 +39,17 @@ import android.widget.Button;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.view.GravityCompat;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.fragment.app.Fragment;
import com.google.android.material.navigation.NavigationView;
import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.StreamingService; import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.exceptions.ExtractionException; import org.schabi.newpipe.extractor.exceptions.ExtractionException;
@ -361,7 +362,7 @@ public class MainActivity extends AppCompatActivity {
// close drawer on return, and don't show animation, so its looks like the drawer isn't open // close drawer on return, and don't show animation, so its looks like the drawer isn't open
// when the user returns to MainActivity // when the user returns to MainActivity
drawer.closeDrawer(Gravity.START, false); drawer.closeDrawer(GravityCompat.START, false);
try { try {
String selectedServiceName = NewPipe.getService( String selectedServiceName = NewPipe.getService(
ServiceHelper.getSelectedServiceId(this)).getServiceInfo().getName(); ServiceHelper.getSelectedServiceId(this)).getServiceInfo().getName();

View file

@ -1,15 +1,6 @@
package org.schabi.newpipe.fragments; package org.schabi.newpipe.fragments;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.material.tabs.TabLayout;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import androidx.viewpager.widget.ViewPager;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import android.util.Log; import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
@ -18,6 +9,17 @@ import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import androidx.viewpager.widget.ViewPager;
import com.google.android.material.tabs.TabLayout;
import org.schabi.newpipe.BaseFragment; import org.schabi.newpipe.BaseFragment;
import org.schabi.newpipe.R; import org.schabi.newpipe.R;
import org.schabi.newpipe.extractor.exceptions.ExtractionException; import org.schabi.newpipe.extractor.exceptions.ExtractionException;
@ -111,8 +113,7 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte
public void onDestroy() { public void onDestroy() {
super.onDestroy(); super.onDestroy();
tabsManager.unsetSavedTabsListener(); tabsManager.unsetSavedTabsListener();
pagerAdapter = null; if (viewPager != null) viewPager.setAdapter(null);
viewPager.setAdapter(pagerAdapter);
} }
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////

View file

@ -1,11 +1,12 @@
package org.schabi.newpipe.fragments.list; package org.schabi.newpipe.fragments.list;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.NonNull;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import android.view.View; import android.view.View;
import androidx.annotation.NonNull;
import org.schabi.newpipe.extractor.ListExtractor; import org.schabi.newpipe.extractor.ListExtractor;
import org.schabi.newpipe.extractor.ListInfo; import org.schabi.newpipe.extractor.ListInfo;
import org.schabi.newpipe.util.Constants; import org.schabi.newpipe.util.Constants;
@ -61,8 +62,10 @@ public abstract class BaseListInfoFragment<I extends ListInfo>
@Override @Override
public void onDestroy() { public void onDestroy() {
super.onDestroy(); super.onDestroy();
if (currentWorker != null) currentWorker.dispose(); if (currentWorker != null) {
currentWorker = null; currentWorker.dispose();
currentWorker = null;
}
} }
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////

View file

@ -28,12 +28,13 @@ import android.graphics.Bitmap;
import android.graphics.BitmapFactory; import android.graphics.BitmapFactory;
import android.media.AudioManager; import android.media.AudioManager;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.util.Log; import android.util.Log;
import android.view.View; import android.view.View;
import android.widget.Toast; import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.DefaultRenderersFactory; import com.google.android.exoplayer2.DefaultRenderersFactory;
import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayerFactory; import com.google.android.exoplayer2.ExoPlayerFactory;
@ -209,7 +210,7 @@ public abstract class BasePlayer implements
this.databaseUpdateReactor = new CompositeDisposable(); this.databaseUpdateReactor = new CompositeDisposable();
final String userAgent = Downloader.USER_AGENT; final String userAgent = Downloader.USER_AGENT;
final DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter(); final DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter.Builder(context).build();
this.dataSource = new PlayerDataSource(context, userAgent, bandwidthMeter); this.dataSource = new PlayerDataSource(context, userAgent, bandwidthMeter);
final TrackSelection.Factory trackSelectionFactory = PlayerHelper.getQualitySelector(context); final TrackSelection.Factory trackSelectionFactory = PlayerHelper.getQualitySelector(context);
@ -1193,10 +1194,7 @@ public abstract class BasePlayer implements
} }
public boolean isPlaying() { public boolean isPlaying() {
if (simpleExoPlayer == null) return false; return simpleExoPlayer != null && simpleExoPlayer.isPlaying();
final int state = simpleExoPlayer.getPlaybackState();
return (state == Player.STATE_READY || state == Player.STATE_BUFFERING)
&& simpleExoPlayer.getPlayWhenReady();
} }
@Player.RepeatMode @Player.RepeatMode

View file

@ -1,9 +1,11 @@
package org.schabi.newpipe.player.helper; package org.schabi.newpipe.player.helper;
import android.content.Context; import android.content.Context;
import androidx.annotation.NonNull;
import android.util.Log; import android.util.Log;
import androidx.annotation.NonNull;
import com.google.android.exoplayer2.database.ExoDatabaseProvider;
import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DefaultDataSource; import com.google.android.exoplayer2.upstream.DefaultDataSource;
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory; import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
@ -54,7 +56,7 @@ import java.io.File;
if (cache == null) { if (cache == null) {
final LeastRecentlyUsedCacheEvictor evictor = new LeastRecentlyUsedCacheEvictor(maxCacheSize); final LeastRecentlyUsedCacheEvictor evictor = new LeastRecentlyUsedCacheEvictor(maxCacheSize);
cache = new SimpleCache(cacheDir, evictor); cache = new SimpleCache(cacheDir, evictor, new ExoDatabaseProvider(context));
} }
} }

View file

@ -2,11 +2,12 @@ package org.schabi.newpipe.player.helper;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.support.v4.media.session.MediaSessionCompat;
import android.view.KeyEvent;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.media.session.MediaButtonReceiver; import androidx.media.session.MediaButtonReceiver;
import android.support.v4.media.session.MediaSessionCompat;
import android.view.KeyEvent;
import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector; import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector;
@ -27,10 +28,10 @@ public class MediaSessionManager {
this.mediaSession = new MediaSessionCompat(context, TAG); this.mediaSession = new MediaSessionCompat(context, TAG);
this.mediaSession.setActive(true); this.mediaSession.setActive(true);
this.sessionConnector = new MediaSessionConnector(mediaSession, this.sessionConnector = new MediaSessionConnector(mediaSession);
new PlayQueuePlaybackController(callback)); this.sessionConnector.setControlDispatcher(new PlayQueuePlaybackController(callback));
this.sessionConnector.setQueueNavigator(new PlayQueueNavigator(mediaSession, callback)); this.sessionConnector.setQueueNavigator(new PlayQueueNavigator(mediaSession, callback));
this.sessionConnector.setPlayer(player, null); this.sessionConnector.setPlayer(player);
} }
@Nullable @Nullable
@ -43,7 +44,7 @@ public class MediaSessionManager {
* Should be called on player destruction to prevent leakage. * Should be called on player destruction to prevent leakage.
* */ * */
public void dispose() { public void dispose() {
this.sessionConnector.setPlayer(null, null); this.sessionConnector.setPlayer(null);
this.sessionConnector.setQueueNavigator(null); this.sessionConnector.setQueueNavigator(null);
this.mediaSession.setActive(false); this.mediaSession.setActive(false);
this.mediaSession.release(); this.mediaSession.release();

View file

@ -1,9 +1,10 @@
package org.schabi.newpipe.player.helper; package org.schabi.newpipe.player.helper;
import android.content.Context; import android.content.Context;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import com.google.android.exoplayer2.source.ExtractorMediaSource; import com.google.android.exoplayer2.source.ProgressiveMediaSource;
import com.google.android.exoplayer2.source.SingleSampleMediaSource; import com.google.android.exoplayer2.source.SingleSampleMediaSource;
import com.google.android.exoplayer2.source.dash.DashMediaSource; import com.google.android.exoplayer2.source.dash.DashMediaSource;
import com.google.android.exoplayer2.source.dash.DefaultDashChunkSource; import com.google.android.exoplayer2.source.dash.DefaultDashChunkSource;
@ -64,12 +65,12 @@ public class PlayerDataSource {
cacheDataSourceFactory), cacheDataSourceFactory); cacheDataSourceFactory), cacheDataSourceFactory);
} }
public ExtractorMediaSource.Factory getExtractorMediaSourceFactory() { public ProgressiveMediaSource.Factory getExtractorMediaSourceFactory() {
return new ExtractorMediaSource.Factory(cacheDataSourceFactory) return new ProgressiveMediaSource.Factory(cacheDataSourceFactory)
.setLoadErrorHandlingPolicy(new DefaultLoadErrorHandlingPolicy(EXTRACTOR_MINIMUM_RETRY)); .setLoadErrorHandlingPolicy(new DefaultLoadErrorHandlingPolicy(EXTRACTOR_MINIMUM_RETRY));
} }
public ExtractorMediaSource.Factory getExtractorMediaSourceFactory(@NonNull final String key) { public ProgressiveMediaSource.Factory getExtractorMediaSourceFactory(@NonNull final String key) {
return getExtractorMediaSourceFactory().setCustomCacheKey(key); return getExtractorMediaSourceFactory().setCustomCacheKey(key);
} }

View file

@ -2,10 +2,12 @@ package org.schabi.newpipe.player.mediasession;
import android.os.Bundle; import android.os.Bundle;
import android.os.ResultReceiver; import android.os.ResultReceiver;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.support.v4.media.session.MediaSessionCompat; import android.support.v4.media.session.MediaSessionCompat;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.ControlDispatcher;
import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector; import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
@ -63,17 +65,17 @@ public class PlayQueueNavigator implements MediaSessionConnector.QueueNavigator
} }
@Override @Override
public void onSkipToPrevious(Player player) { public void onSkipToPrevious(Player player, ControlDispatcher controlDispatcher) {
callback.onSkipToPrevious(); callback.onSkipToPrevious();
} }
@Override @Override
public void onSkipToQueueItem(Player player, long id) { public void onSkipToQueueItem(Player player, ControlDispatcher controlDispatcher, long id) {
callback.onSkipToIndex((int) id); callback.onSkipToIndex((int) id);
} }
@Override @Override
public void onSkipToNext(Player player) { public void onSkipToNext(Player player, ControlDispatcher controlDispatcher) {
callback.onSkipToNext(); callback.onSkipToNext();
} }
@ -100,12 +102,7 @@ public class PlayQueueNavigator implements MediaSessionConnector.QueueNavigator
} }
@Override @Override
public String[] getCommands() { public boolean onCommand(Player player, ControlDispatcher controlDispatcher, String command, Bundle extras, ResultReceiver cb) {
return new String[0]; return false;
}
@Override
public void onCommand(Player player, String command, Bundle extras, ResultReceiver cb) {
} }
} }

View file

@ -1,9 +1,9 @@
package org.schabi.newpipe.player.mediasession; package org.schabi.newpipe.player.mediasession;
import com.google.android.exoplayer2.DefaultControlDispatcher;
import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.ext.mediasession.DefaultPlaybackController;
public class PlayQueuePlaybackController extends DefaultPlaybackController { public class PlayQueuePlaybackController extends DefaultControlDispatcher {
private final MediaSessionCallback callback; private final MediaSessionCallback callback;
public PlayQueuePlaybackController(final MediaSessionCallback callback) { public PlayQueuePlaybackController(final MediaSessionCallback callback) {
@ -12,12 +12,12 @@ public class PlayQueuePlaybackController extends DefaultPlaybackController {
} }
@Override @Override
public void onPlay(Player player) { public boolean dispatchSetPlayWhenReady(Player player, boolean playWhenReady) {
callback.onPlay(); if (playWhenReady) {
} callback.onPlay();
} else {
@Override callback.onPause();
public void onPause(Player player) { }
callback.onPause(); return true;
} }
} }

View file

@ -1,15 +1,17 @@
package org.schabi.newpipe.player.playback; package org.schabi.newpipe.player.playback;
import androidx.annotation.NonNull;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Pair; import android.util.Pair;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.source.TrackGroup; import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector; import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.trackselection.FixedTrackSelection;
import com.google.android.exoplayer2.trackselection.TrackSelection; import com.google.android.exoplayer2.trackselection.TrackSelection;
import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
@ -21,7 +23,6 @@ import com.google.android.exoplayer2.util.Assertions;
* a broader set of languages. * a broader set of languages.
* */ * */
public class CustomTrackSelector extends DefaultTrackSelector { public class CustomTrackSelector extends DefaultTrackSelector {
private static final int WITHIN_RENDERER_CAPABILITIES_BONUS = 1000;
private String preferredTextLanguage; private String preferredTextLanguage;
@ -41,23 +42,22 @@ public class CustomTrackSelector extends DefaultTrackSelector {
} }
} }
/** @see DefaultTrackSelector#formatHasLanguage(Format, String)*/ private static boolean formatHasLanguage(Format format, String language) {
protected static boolean formatHasLanguage(Format format, String language) {
return language != null && TextUtils.equals(language, format.language); return language != null && TextUtils.equals(language, format.language);
} }
/** @see DefaultTrackSelector#formatHasNoLanguage(Format)*/
protected static boolean formatHasNoLanguage(Format format) {
return TextUtils.isEmpty(format.language) || formatHasLanguage(format, C.LANGUAGE_UNDETERMINED);
}
/** @see DefaultTrackSelector#selectTextTrack(TrackGroupArray, int[][], Parameters) */
@Override @Override
protected Pair<TrackSelection, Integer> selectTextTrack(TrackGroupArray groups, int[][] formatSupport, @Nullable
Parameters params) { protected Pair<TrackSelection.Definition, TextTrackScore> selectTextTrack(
TrackGroupArray groups,
int[][] formatSupport,
Parameters params,
@Nullable String selectedAudioLanguage)
throws ExoPlaybackException {
TrackGroup selectedGroup = null; TrackGroup selectedGroup = null;
int selectedTrackIndex = 0; int selectedTrackIndex = C.INDEX_UNSET;
int selectedTrackScore = 0; int newPipeTrackScore = 0;
TextTrackScore selectedTrackScore = null;
for (int groupIndex = 0; groupIndex < groups.length; groupIndex++) { for (int groupIndex = 0; groupIndex < groups.length; groupIndex++) {
TrackGroup trackGroup = groups.get(groupIndex); TrackGroup trackGroup = groups.get(groupIndex);
int[] trackFormatSupport = formatSupport[groupIndex]; int[] trackFormatSupport = formatSupport[groupIndex];
@ -65,41 +65,17 @@ public class CustomTrackSelector extends DefaultTrackSelector {
if (isSupported(trackFormatSupport[trackIndex], if (isSupported(trackFormatSupport[trackIndex],
params.exceedRendererCapabilitiesIfNecessary)) { params.exceedRendererCapabilitiesIfNecessary)) {
Format format = trackGroup.getFormat(trackIndex); Format format = trackGroup.getFormat(trackIndex);
int maskedSelectionFlags = TextTrackScore trackScore =
format.selectionFlags & ~params.disabledTextTrackSelectionFlags; new TextTrackScore(
boolean isDefault = (maskedSelectionFlags & C.SELECTION_FLAG_DEFAULT) != 0; format, params, trackFormatSupport[trackIndex], selectedAudioLanguage);
boolean isForced = (maskedSelectionFlags & C.SELECTION_FLAG_FORCED) != 0; if (formatHasLanguage(format, preferredTextLanguage)) {
int trackScore; selectedGroup = trackGroup;
boolean preferredLanguageFound = formatHasLanguage(format, preferredTextLanguage); selectedTrackIndex = trackIndex;
if (preferredLanguageFound selectedTrackScore = trackScore;
|| (params.selectUndeterminedTextLanguage && formatHasNoLanguage(format))) { // found user selected match (perfect!)
if (isDefault) { break;
trackScore = 8; } else if (trackScore.isWithinConstraints
} else if (!isForced) { && (selectedTrackScore == null || trackScore.compareTo(selectedTrackScore) > 0)) {
// Prefer non-forced to forced if a preferred text language has been specified. Where
// both are provided the non-forced track will usually contain the forced subtitles as
// a subset.
trackScore = 6;
} else {
trackScore = 4;
}
trackScore += preferredLanguageFound ? 1 : 0;
} else if (isDefault) {
trackScore = 3;
} else if (isForced) {
if (formatHasLanguage(format, params.preferredAudioLanguage)) {
trackScore = 2;
} else {
trackScore = 1;
}
} else {
// Track should not be selected.
continue;
}
if (isSupported(trackFormatSupport[trackIndex], false)) {
trackScore += WITHIN_RENDERER_CAPABILITIES_BONUS;
}
if (trackScore > selectedTrackScore) {
selectedGroup = trackGroup; selectedGroup = trackGroup;
selectedTrackIndex = trackIndex; selectedTrackIndex = trackIndex;
selectedTrackScore = trackScore; selectedTrackScore = trackScore;
@ -110,6 +86,7 @@ public class CustomTrackSelector extends DefaultTrackSelector {
return selectedGroup == null return selectedGroup == null
? null ? null
: Pair.create( : Pair.create(
new FixedTrackSelection(selectedGroup, selectedTrackIndex), selectedTrackScore); new TrackSelection.Definition(selectedGroup, selectedTrackIndex),
Assertions.checkNotNull(selectedTrackScore));
} }
} }

View file

@ -6,7 +6,7 @@ buildscript {
google() google()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.2.0' classpath 'com.android.tools.build:gradle:3.4.0'
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files // in the individual module build.gradle files

View file

@ -1,6 +1,6 @@
#Sun Sep 22 10:40:45 CEST 2019 #Mon Oct 07 06:29:33 CEST 2019
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip