Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
SDK
/
exoplayer
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
675b81e5
authored
Mar 15, 2021
by
olly
Committed by
Ian Baker
Mar 24, 2021
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
DataSource: Tighten contract to return -1 on premature end-of-input
PiperOrigin-RevId: 363001266
parent
6c9f9f9d
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
1340 additions
and
99 deletions
extensions/okhttp/src/main/java/com/google/android/exoplayer2/ext/okhttp/OkHttpDataSource.java
library/common/src/main/java/com/google/android/exoplayer2/upstream/DefaultHttpDataSource.java
library/core/src/main/java/com/google/android/exoplayer2/offline/ProgressiveDownloader.java
library/core/src/main/java/com/google/android/exoplayer2/offline/SegmentDownloader.java
library/core/src/main/java/com/google/android/exoplayer2/upstream/AssetDataSource.java
library/core/src/main/java/com/google/android/exoplayer2/upstream/ContentDataSource.java
library/core/src/main/java/com/google/android/exoplayer2/upstream/ExperimentalBandwidthMeter.java
library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheWriter.java
library/core/src/test/java/com/google/android/exoplayer2/upstream/ExperimentalBandwidthMeterTest.java
library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/CacheDataSourceTest.java
library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/CacheWriterTest.java
testutils/src/main/java/com/google/android/exoplayer2/testutil/DataSourceContractTest.java
extensions/okhttp/src/main/java/com/google/android/exoplayer2/ext/okhttp/OkHttpDataSource.java
View file @
675b81e5
...
...
@@ -33,7 +33,6 @@ import com.google.android.exoplayer2.util.Assertions;
import
com.google.android.exoplayer2.util.Util
;
import
com.google.common.base.Predicate
;
import
com.google.common.net.HttpHeaders
;
import
java.io.EOFException
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.io.InterruptedIOException
;
...
...
@@ -478,10 +477,6 @@ public class OkHttpDataSource extends BaseDataSource implements HttpDataSource {
int
read
=
castNonNull
(
responseByteStream
).
read
(
buffer
,
offset
,
readLength
);
if
(
read
==
-
1
)
{
if
(
bytesToRead
!=
C
.
LENGTH_UNSET
)
{
// End of stream reached having not read sufficient data.
throw
new
EOFException
();
}
return
C
.
RESULT_END_OF_INPUT
;
}
...
...
library/common/src/main/java/com/google/android/exoplayer2/upstream/DefaultHttpDataSource.java
View file @
675b81e5
...
...
@@ -29,7 +29,6 @@ import com.google.android.exoplayer2.util.Log;
import
com.google.android.exoplayer2.util.Util
;
import
com.google.common.base.Predicate
;
import
com.google.common.net.HttpHeaders
;
import
java.io.EOFException
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.io.InterruptedIOException
;
...
...
@@ -692,10 +691,6 @@ public class DefaultHttpDataSource extends BaseDataSource implements HttpDataSou
int
read
=
castNonNull
(
inputStream
).
read
(
buffer
,
offset
,
readLength
);
if
(
read
==
-
1
)
{
if
(
bytesToRead
!=
C
.
LENGTH_UNSET
)
{
// End of stream reached having not read sufficient data.
throw
new
EOFException
();
}
return
C
.
RESULT_END_OF_INPUT
;
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/offline/ProgressiveDownloader.java
View file @
675b81e5
...
...
@@ -108,7 +108,6 @@ public final class ProgressiveDownloader implements Downloader {
new
CacheWriter
(
dataSource
,
dataSpec
,
/* allowShortContent= */
false
,
/* temporaryBuffer= */
null
,
progressListener
);
priorityTaskManager
=
cacheDataSourceFactory
.
getUpstreamPriorityTaskManager
();
...
...
library/core/src/main/java/com/google/android/exoplayer2/offline/SegmentDownloader.java
View file @
675b81e5
...
...
@@ -472,7 +472,6 @@ public abstract class SegmentDownloader<M extends FilterableManifest<M>> impleme
new
CacheWriter
(
dataSource
,
segment
.
dataSpec
,
/* allowShortContent= */
false
,
temporaryBuffer
,
progressNotifier
);
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/upstream/AssetDataSource.java
View file @
675b81e5
...
...
@@ -24,7 +24,6 @@ import android.net.Uri;
import
androidx.annotation.Nullable
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.util.Assertions
;
import
java.io.EOFException
;
import
java.io.IOException
;
import
java.io.InputStream
;
...
...
@@ -111,10 +110,6 @@ public final class AssetDataSource extends BaseDataSource {
}
if
(
bytesRead
==
-
1
)
{
if
(
bytesRemaining
!=
C
.
LENGTH_UNSET
)
{
// End of stream reached having not read sufficient data.
throw
new
AssetDataSourceException
(
new
EOFException
());
}
return
C
.
RESULT_END_OF_INPUT
;
}
if
(
bytesRemaining
!=
C
.
LENGTH_UNSET
)
{
...
...
library/core/src/main/java/com/google/android/exoplayer2/upstream/ContentDataSource.java
View file @
675b81e5
...
...
@@ -24,7 +24,6 @@ import android.content.res.AssetFileDescriptor;
import
android.net.Uri
;
import
androidx.annotation.Nullable
;
import
com.google.android.exoplayer2.C
;
import
java.io.EOFException
;
import
java.io.FileInputStream
;
import
java.io.FileNotFoundException
;
import
java.io.IOException
;
...
...
@@ -147,10 +146,6 @@ public final class ContentDataSource extends BaseDataSource {
}
if
(
bytesRead
==
-
1
)
{
if
(
bytesRemaining
!=
C
.
LENGTH_UNSET
)
{
// End of stream reached having not read sufficient data.
throw
new
ContentDataSourceException
(
new
EOFException
());
}
return
C
.
RESULT_END_OF_INPUT
;
}
if
(
bytesRemaining
!=
C
.
LENGTH_UNSET
)
{
...
...
library/core/src/main/java/com/google/android/exoplayer2/upstream/ExperimentalBandwidthMeter.java
0 → 100644
View file @
675b81e5
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
com
.
google
.
android
.
exoplayer2
.
upstream
;
import
android.content.BroadcastReceiver
;
import
android.content.Context
;
import
android.content.Intent
;
import
android.content.IntentFilter
;
import
android.net.ConnectivityManager
;
import
android.os.Handler
;
import
android.os.Looper
;
import
androidx.annotation.Nullable
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.upstream.BandwidthMeter.EventListener.EventDispatcher
;
import
com.google.android.exoplayer2.util.Assertions
;
import
com.google.android.exoplayer2.util.Clock
;
import
com.google.android.exoplayer2.util.Util
;
import
com.google.common.collect.ImmutableList
;
import
com.google.common.collect.ImmutableListMultimap
;
import
com.google.common.collect.ImmutableMap
;
import
java.lang.ref.WeakReference
;
import
java.util.ArrayList
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
import
org.checkerframework.checker.nullness.qual.MonotonicNonNull
;
/**
* An experimental {@link BandwidthMeter} that estimates bandwidth by listening to data transfers.
*
* <p>The initial estimate is based on the current operator's network country code or the locale of
* the user, as well as the network connection type. This can be configured in the {@link Builder}.
*/
public
final
class
ExperimentalBandwidthMeter
implements
BandwidthMeter
,
TransferListener
{
/**
* Country groups used to determine the default initial bitrate estimate. The group assignment for
* each country is a list for [Wifi, 2G, 3G, 4G, 5G_NSA].
*/
public
static
final
ImmutableListMultimap
<
String
,
Integer
>
DEFAULT_INITIAL_BITRATE_COUNTRY_GROUPS
=
createInitialBitrateCountryGroupAssignment
();
/** Default initial Wifi bitrate estimate in bits per second. */
public
static
final
ImmutableList
<
Long
>
DEFAULT_INITIAL_BITRATE_ESTIMATES_WIFI
=
ImmutableList
.
of
(
6_100_000L
,
3_900_000L
,
2_300_000L
,
1_300_000L
,
600_000L
);
/** Default initial 2G bitrate estimates in bits per second. */
public
static
final
ImmutableList
<
Long
>
DEFAULT_INITIAL_BITRATE_ESTIMATES_2G
=
ImmutableList
.
of
(
230_000L
,
159_000L
,
142_000L
,
127_000L
,
112_000L
);
/** Default initial 3G bitrate estimates in bits per second. */
public
static
final
ImmutableList
<
Long
>
DEFAULT_INITIAL_BITRATE_ESTIMATES_3G
=
ImmutableList
.
of
(
2_200_000L
,
1_300_000L
,
940_000L
,
760_000L
,
520_000L
);
/** Default initial 4G bitrate estimates in bits per second. */
public
static
final
ImmutableList
<
Long
>
DEFAULT_INITIAL_BITRATE_ESTIMATES_4G
=
ImmutableList
.
of
(
4_400_000L
,
2_300_000L
,
1_500_000L
,
1_100_000L
,
660_000L
);
/** Default initial 5G-NSA bitrate estimates in bits per second. */
public
static
final
ImmutableList
<
Long
>
DEFAULT_INITIAL_BITRATE_ESTIMATES_5G_NSA
=
ImmutableList
.
of
(
13_000_000L
,
9_100_000L
,
6_300_000L
,
4_000_000L
,
2_000_000L
);
@Nullable
private
static
ExperimentalBandwidthMeter
singletonInstance
;
/**
* Default initial bitrate estimate used when the device is offline or the network type cannot be
* determined, in bits per second.
*/
public
static
final
long
DEFAULT_INITIAL_BITRATE_ESTIMATE
=
1_000_000
;
/** Index for the Wifi group index in {@link #DEFAULT_INITIAL_BITRATE_COUNTRY_GROUPS}. */
private
static
final
int
COUNTRY_GROUP_INDEX_WIFI
=
0
;
/** Index for the 2G group index in {@link #DEFAULT_INITIAL_BITRATE_COUNTRY_GROUPS}. */
private
static
final
int
COUNTRY_GROUP_INDEX_2G
=
1
;
/** Index for the 3G group index in {@link #DEFAULT_INITIAL_BITRATE_COUNTRY_GROUPS}. */
private
static
final
int
COUNTRY_GROUP_INDEX_3G
=
2
;
/** Index for the 4G group index in {@link #DEFAULT_INITIAL_BITRATE_COUNTRY_GROUPS}. */
private
static
final
int
COUNTRY_GROUP_INDEX_4G
=
3
;
/** Index for the 5G-NSA group index in {@link #DEFAULT_INITIAL_BITRATE_COUNTRY_GROUPS}. */
private
static
final
int
COUNTRY_GROUP_INDEX_5G_NSA
=
4
;
/** Builder for a bandwidth meter. */
public
static
final
class
Builder
{
@Nullable
private
final
Context
context
;
private
Map
<
Integer
,
Long
>
initialBitrateEstimates
;
private
Clock
clock
;
private
boolean
resetOnNetworkTypeChange
;
/**
* Creates a builder with default parameters and without listener.
*
* @param context A context.
*/
public
Builder
(
Context
context
)
{
// Handling of null is for backward compatibility only.
this
.
context
=
context
==
null
?
null
:
context
.
getApplicationContext
();
initialBitrateEstimates
=
getInitialBitrateEstimatesForCountry
(
Util
.
getCountryCode
(
context
));
clock
=
Clock
.
DEFAULT
;
resetOnNetworkTypeChange
=
true
;
}
/**
* Sets the initial bitrate estimate in bits per second that should be assumed when a bandwidth
* estimate is unavailable.
*
* @param initialBitrateEstimate The initial bitrate estimate in bits per second.
* @return This builder.
*/
public
Builder
setInitialBitrateEstimate
(
long
initialBitrateEstimate
)
{
for
(
Integer
networkType
:
initialBitrateEstimates
.
keySet
())
{
setInitialBitrateEstimate
(
networkType
,
initialBitrateEstimate
);
}
return
this
;
}
/**
* Sets the initial bitrate estimate in bits per second that should be assumed when a bandwidth
* estimate is unavailable and the current network connection is of the specified type.
*
* @param networkType The {@link C.NetworkType} this initial estimate is for.
* @param initialBitrateEstimate The initial bitrate estimate in bits per second.
* @return This builder.
*/
public
Builder
setInitialBitrateEstimate
(
@C
.
NetworkType
int
networkType
,
long
initialBitrateEstimate
)
{
initialBitrateEstimates
.
put
(
networkType
,
initialBitrateEstimate
);
return
this
;
}
/**
* Sets the initial bitrate estimates to the default values of the specified country. The
* initial estimates are used when a bandwidth estimate is unavailable.
*
* @param countryCode The ISO 3166-1 alpha-2 country code of the country whose default bitrate
* estimates should be used.
* @return This builder.
*/
public
Builder
setInitialBitrateEstimate
(
String
countryCode
)
{
initialBitrateEstimates
=
getInitialBitrateEstimatesForCountry
(
Util
.
toUpperInvariant
(
countryCode
));
return
this
;
}
/**
* Sets the clock used to estimate bandwidth from data transfers. Should only be set for testing
* purposes.
*
* @param clock The clock used to estimate bandwidth from data transfers.
* @return This builder.
*/
public
Builder
setClock
(
Clock
clock
)
{
this
.
clock
=
clock
;
return
this
;
}
/**
* Sets whether to reset if the network type changes. The default value is {@code true}.
*
* @param resetOnNetworkTypeChange Whether to reset if the network type changes.
* @return This builder.
*/
public
Builder
setResetOnNetworkTypeChange
(
boolean
resetOnNetworkTypeChange
)
{
this
.
resetOnNetworkTypeChange
=
resetOnNetworkTypeChange
;
return
this
;
}
/**
* Builds the bandwidth meter.
*
* @return A bandwidth meter with the configured properties.
*/
public
ExperimentalBandwidthMeter
build
()
{
return
new
ExperimentalBandwidthMeter
(
context
,
initialBitrateEstimates
,
clock
,
resetOnNetworkTypeChange
);
}
private
static
Map
<
Integer
,
Long
>
getInitialBitrateEstimatesForCountry
(
String
countryCode
)
{
List
<
Integer
>
groupIndices
=
getCountryGroupIndices
(
countryCode
);
Map
<
Integer
,
Long
>
result
=
new
HashMap
<>(
/* initialCapacity= */
6
);
result
.
put
(
C
.
NETWORK_TYPE_UNKNOWN
,
DEFAULT_INITIAL_BITRATE_ESTIMATE
);
result
.
put
(
C
.
NETWORK_TYPE_WIFI
,
DEFAULT_INITIAL_BITRATE_ESTIMATES_WIFI
.
get
(
groupIndices
.
get
(
COUNTRY_GROUP_INDEX_WIFI
)));
result
.
put
(
C
.
NETWORK_TYPE_2G
,
DEFAULT_INITIAL_BITRATE_ESTIMATES_2G
.
get
(
groupIndices
.
get
(
COUNTRY_GROUP_INDEX_2G
)));
result
.
put
(
C
.
NETWORK_TYPE_3G
,
DEFAULT_INITIAL_BITRATE_ESTIMATES_3G
.
get
(
groupIndices
.
get
(
COUNTRY_GROUP_INDEX_3G
)));
result
.
put
(
C
.
NETWORK_TYPE_4G
,
DEFAULT_INITIAL_BITRATE_ESTIMATES_4G
.
get
(
groupIndices
.
get
(
COUNTRY_GROUP_INDEX_4G
)));
result
.
put
(
C
.
NETWORK_TYPE_5G
,
DEFAULT_INITIAL_BITRATE_ESTIMATES_5G_NSA
.
get
(
groupIndices
.
get
(
COUNTRY_GROUP_INDEX_5G_NSA
)));
// Assume default Wifi speed for Ethernet to prevent using the slower fallback.
result
.
put
(
C
.
NETWORK_TYPE_ETHERNET
,
DEFAULT_INITIAL_BITRATE_ESTIMATES_WIFI
.
get
(
groupIndices
.
get
(
COUNTRY_GROUP_INDEX_WIFI
)));
return
result
;
}
private
static
ImmutableList
<
Integer
>
getCountryGroupIndices
(
String
countryCode
)
{
ImmutableList
<
Integer
>
groupIndices
=
DEFAULT_INITIAL_BITRATE_COUNTRY_GROUPS
.
get
(
countryCode
);
// Assume median group if not found.
return
groupIndices
.
isEmpty
()
?
ImmutableList
.
of
(
2
,
2
,
2
,
2
,
2
)
:
groupIndices
;
}
}
/**
* Returns a singleton instance of an {@link ExperimentalBandwidthMeter} with default
* configuration.
*
* @param context A {@link Context}.
* @return The singleton instance.
*/
public
static
synchronized
ExperimentalBandwidthMeter
getSingletonInstance
(
Context
context
)
{
if
(
singletonInstance
==
null
)
{
singletonInstance
=
new
Builder
(
context
).
build
();
}
return
singletonInstance
;
}
@Nullable
private
final
Context
context
;
private
final
ImmutableMap
<
Integer
,
Long
>
initialBitrateEstimates
;
private
final
EventDispatcher
eventDispatcher
;
private
final
Clock
clock
;
private
int
streamCount
;
private
long
sampleStartTimeMs
;
private
long
sampleBytesTransferred
;
@C
.
NetworkType
private
int
networkType
;
private
long
bitrateEstimate
;
private
long
lastReportedBitrateEstimate
;
private
boolean
networkTypeOverrideSet
;
@C
.
NetworkType
private
int
networkTypeOverride
;
private
ExperimentalBandwidthMeter
(
@Nullable
Context
context
,
Map
<
Integer
,
Long
>
initialBitrateEstimates
,
Clock
clock
,
boolean
resetOnNetworkTypeChange
)
{
this
.
context
=
context
==
null
?
null
:
context
.
getApplicationContext
();
this
.
initialBitrateEstimates
=
ImmutableMap
.
copyOf
(
initialBitrateEstimates
);
this
.
eventDispatcher
=
new
EventDispatcher
();
this
.
clock
=
clock
;
// Set the initial network type and bitrate estimate
networkType
=
context
==
null
?
C
.
NETWORK_TYPE_UNKNOWN
:
Util
.
getNetworkType
(
context
);
bitrateEstimate
=
getInitialBitrateEstimateForNetworkType
(
networkType
);
// Register to receive connectivity actions if possible.
if
(
context
!=
null
&&
resetOnNetworkTypeChange
)
{
ConnectivityActionReceiver
connectivityActionReceiver
=
ConnectivityActionReceiver
.
getInstance
(
context
);
connectivityActionReceiver
.
register
(
/* bandwidthMeter= */
this
);
}
}
/**
* Overrides the network type. Handled in the same way as if the meter had detected a change from
* the current network type to the specified network type internally.
*
* <p>Applications should not normally call this method. It is intended for testing purposes.
*
* @param networkType The overriding network type.
*/
public
synchronized
void
setNetworkTypeOverride
(
@C
.
NetworkType
int
networkType
)
{
networkTypeOverride
=
networkType
;
networkTypeOverrideSet
=
true
;
onConnectivityAction
();
}
@Override
public
synchronized
long
getBitrateEstimate
()
{
return
bitrateEstimate
;
}
@Override
public
TransferListener
getTransferListener
()
{
return
this
;
}
@Override
public
void
addEventListener
(
Handler
eventHandler
,
EventListener
eventListener
)
{
Assertions
.
checkNotNull
(
eventHandler
);
Assertions
.
checkNotNull
(
eventListener
);
eventDispatcher
.
addListener
(
eventHandler
,
eventListener
);
}
@Override
public
void
removeEventListener
(
EventListener
eventListener
)
{
eventDispatcher
.
removeListener
(
eventListener
);
}
@Override
public
void
onTransferInitializing
(
DataSource
source
,
DataSpec
dataSpec
,
boolean
isNetwork
)
{
// TODO: Track time for time-to-response estimation.
}
@Override
public
synchronized
void
onTransferStart
(
DataSource
source
,
DataSpec
dataSpec
,
boolean
isNetwork
)
{
if
(!
isTransferAtFullNetworkSpeed
(
dataSpec
,
isNetwork
))
{
return
;
}
if
(
streamCount
==
0
)
{
sampleStartTimeMs
=
clock
.
elapsedRealtime
();
}
streamCount
++;
// TODO: Track time for time-to-response estimation.
}
@Override
public
synchronized
void
onBytesTransferred
(
DataSource
source
,
DataSpec
dataSpec
,
boolean
isNetwork
,
int
bytes
)
{
if
(!
isTransferAtFullNetworkSpeed
(
dataSpec
,
isNetwork
))
{
return
;
}
sampleBytesTransferred
+=
bytes
;
}
@Override
public
synchronized
void
onTransferEnd
(
DataSource
source
,
DataSpec
dataSpec
,
boolean
isNetwork
)
{
if
(!
isTransferAtFullNetworkSpeed
(
dataSpec
,
isNetwork
))
{
return
;
}
Assertions
.
checkState
(
streamCount
>
0
);
long
nowMs
=
clock
.
elapsedRealtime
();
int
sampleElapsedTimeMs
=
(
int
)
(
nowMs
-
sampleStartTimeMs
);
if
(
sampleElapsedTimeMs
>
0
)
{
// TODO: Add heuristic for bandwidth estimation.
bitrateEstimate
=
(
long
)
(
sampleBytesTransferred
*
8000
f
)
/
sampleElapsedTimeMs
;
maybeNotifyBandwidthSample
(
sampleElapsedTimeMs
,
sampleBytesTransferred
,
bitrateEstimate
);
sampleStartTimeMs
=
nowMs
;
sampleBytesTransferred
=
0
;
}
// Else any sample bytes transferred will be carried forward into the next sample.
streamCount
--;
}
private
synchronized
void
onConnectivityAction
()
{
int
networkType
=
networkTypeOverrideSet
?
networkTypeOverride
:
(
context
==
null
?
C
.
NETWORK_TYPE_UNKNOWN
:
Util
.
getNetworkType
(
context
));
if
(
this
.
networkType
==
networkType
)
{
return
;
}
this
.
networkType
=
networkType
;
if
(
networkType
==
C
.
NETWORK_TYPE_OFFLINE
||
networkType
==
C
.
NETWORK_TYPE_UNKNOWN
||
networkType
==
C
.
NETWORK_TYPE_OTHER
)
{
// It's better not to reset the bandwidth meter for these network types.
return
;
}
// Reset the bitrate estimate and report it, along with any bytes transferred.
this
.
bitrateEstimate
=
getInitialBitrateEstimateForNetworkType
(
networkType
);
long
nowMs
=
clock
.
elapsedRealtime
();
int
sampleElapsedTimeMs
=
streamCount
>
0
?
(
int
)
(
nowMs
-
sampleStartTimeMs
)
:
0
;
maybeNotifyBandwidthSample
(
sampleElapsedTimeMs
,
sampleBytesTransferred
,
bitrateEstimate
);
// Reset the remainder of the state.
sampleStartTimeMs
=
nowMs
;
sampleBytesTransferred
=
0
;
}
private
void
maybeNotifyBandwidthSample
(
int
elapsedMs
,
long
bytesTransferred
,
long
bitrateEstimate
)
{
if
(
elapsedMs
==
0
&&
bytesTransferred
==
0
&&
bitrateEstimate
==
lastReportedBitrateEstimate
)
{
return
;
}
lastReportedBitrateEstimate
=
bitrateEstimate
;
eventDispatcher
.
bandwidthSample
(
elapsedMs
,
bytesTransferred
,
bitrateEstimate
);
}
private
long
getInitialBitrateEstimateForNetworkType
(
@C
.
NetworkType
int
networkType
)
{
Long
initialBitrateEstimate
=
initialBitrateEstimates
.
get
(
networkType
);
if
(
initialBitrateEstimate
==
null
)
{
initialBitrateEstimate
=
initialBitrateEstimates
.
get
(
C
.
NETWORK_TYPE_UNKNOWN
);
}
if
(
initialBitrateEstimate
==
null
)
{
initialBitrateEstimate
=
DEFAULT_INITIAL_BITRATE_ESTIMATE
;
}
return
initialBitrateEstimate
;
}
private
static
boolean
isTransferAtFullNetworkSpeed
(
DataSpec
dataSpec
,
boolean
isNetwork
)
{
return
isNetwork
&&
!
dataSpec
.
isFlagSet
(
DataSpec
.
FLAG_MIGHT_NOT_USE_FULL_NETWORK_SPEED
);
}
/*
* Note: This class only holds a weak reference to bandwidth meter instances. It should not
* be made non-static, since doing so adds a strong reference (i.e.,
* ExperimentalBandwidthMeter.this).
*/
private
static
class
ConnectivityActionReceiver
extends
BroadcastReceiver
{
private
static
@MonotonicNonNull
ConnectivityActionReceiver
staticInstance
;
private
final
Handler
mainHandler
;
private
final
ArrayList
<
WeakReference
<
ExperimentalBandwidthMeter
>>
bandwidthMeters
;
public
static
synchronized
ConnectivityActionReceiver
getInstance
(
Context
context
)
{
if
(
staticInstance
==
null
)
{
staticInstance
=
new
ConnectivityActionReceiver
();
IntentFilter
filter
=
new
IntentFilter
();
filter
.
addAction
(
ConnectivityManager
.
CONNECTIVITY_ACTION
);
context
.
registerReceiver
(
staticInstance
,
filter
);
}
return
staticInstance
;
}
private
ConnectivityActionReceiver
()
{
mainHandler
=
new
Handler
(
Looper
.
getMainLooper
());
bandwidthMeters
=
new
ArrayList
<>();
}
public
synchronized
void
register
(
ExperimentalBandwidthMeter
bandwidthMeter
)
{
removeClearedReferences
();
bandwidthMeters
.
add
(
new
WeakReference
<>(
bandwidthMeter
));
// Simulate an initial update on the main thread (like the sticky broadcast we'd receive if
// we were to register a separate broadcast receiver for each bandwidth meter).
mainHandler
.
post
(()
->
updateBandwidthMeter
(
bandwidthMeter
));
}
@Override
public
synchronized
void
onReceive
(
Context
context
,
Intent
intent
)
{
if
(
isInitialStickyBroadcast
())
{
return
;
}
removeClearedReferences
();
for
(
int
i
=
0
;
i
<
bandwidthMeters
.
size
();
i
++)
{
WeakReference
<
ExperimentalBandwidthMeter
>
bandwidthMeterReference
=
bandwidthMeters
.
get
(
i
);
ExperimentalBandwidthMeter
bandwidthMeter
=
bandwidthMeterReference
.
get
();
if
(
bandwidthMeter
!=
null
)
{
updateBandwidthMeter
(
bandwidthMeter
);
}
}
}
private
void
updateBandwidthMeter
(
ExperimentalBandwidthMeter
bandwidthMeter
)
{
bandwidthMeter
.
onConnectivityAction
();
}
private
void
removeClearedReferences
()
{
for
(
int
i
=
bandwidthMeters
.
size
()
-
1
;
i
>=
0
;
i
--)
{
WeakReference
<
ExperimentalBandwidthMeter
>
bandwidthMeterReference
=
bandwidthMeters
.
get
(
i
);
ExperimentalBandwidthMeter
bandwidthMeter
=
bandwidthMeterReference
.
get
();
if
(
bandwidthMeter
==
null
)
{
bandwidthMeters
.
remove
(
i
);
}
}
}
}
private
static
ImmutableListMultimap
<
String
,
Integer
>
createInitialBitrateCountryGroupAssignment
()
{
ImmutableListMultimap
.
Builder
<
String
,
Integer
>
countryGroupAssignment
=
ImmutableListMultimap
.
builder
();
countryGroupAssignment
.
putAll
(
"AD"
,
1
,
2
,
0
,
0
,
2
);
countryGroupAssignment
.
putAll
(
"AE"
,
1
,
4
,
4
,
4
,
2
);
countryGroupAssignment
.
putAll
(
"AF"
,
4
,
4
,
4
,
4
,
2
);
countryGroupAssignment
.
putAll
(
"AG"
,
4
,
2
,
1
,
4
,
2
);
countryGroupAssignment
.
putAll
(
"AI"
,
1
,
2
,
2
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"AL"
,
1
,
1
,
1
,
1
,
2
);
countryGroupAssignment
.
putAll
(
"AM"
,
2
,
2
,
1
,
3
,
2
);
countryGroupAssignment
.
putAll
(
"AO"
,
3
,
4
,
3
,
1
,
2
);
countryGroupAssignment
.
putAll
(
"AR"
,
2
,
4
,
2
,
1
,
2
);
countryGroupAssignment
.
putAll
(
"AS"
,
2
,
2
,
3
,
3
,
2
);
countryGroupAssignment
.
putAll
(
"AT"
,
0
,
2
,
0
,
0
,
0
);
countryGroupAssignment
.
putAll
(
"AU"
,
0
,
2
,
0
,
1
,
1
);
countryGroupAssignment
.
putAll
(
"AW"
,
1
,
2
,
0
,
4
,
2
);
countryGroupAssignment
.
putAll
(
"AX"
,
0
,
2
,
2
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"AZ"
,
3
,
3
,
3
,
4
,
2
);
countryGroupAssignment
.
putAll
(
"BA"
,
1
,
1
,
0
,
1
,
2
);
countryGroupAssignment
.
putAll
(
"BB"
,
0
,
2
,
0
,
0
,
2
);
countryGroupAssignment
.
putAll
(
"BD"
,
2
,
0
,
3
,
3
,
2
);
countryGroupAssignment
.
putAll
(
"BE"
,
0
,
0
,
2
,
3
,
2
);
countryGroupAssignment
.
putAll
(
"BF"
,
4
,
4
,
4
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"BG"
,
0
,
1
,
0
,
0
,
2
);
countryGroupAssignment
.
putAll
(
"BH"
,
1
,
0
,
2
,
4
,
3
);
countryGroupAssignment
.
putAll
(
"BI"
,
4
,
4
,
4
,
4
,
2
);
countryGroupAssignment
.
putAll
(
"BJ"
,
4
,
4
,
4
,
4
,
2
);
countryGroupAssignment
.
putAll
(
"BL"
,
1
,
2
,
2
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"BM"
,
0
,
2
,
0
,
0
,
2
);
countryGroupAssignment
.
putAll
(
"BN"
,
3
,
2
,
1
,
0
,
2
);
countryGroupAssignment
.
putAll
(
"BO"
,
1
,
2
,
4
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"BQ"
,
1
,
2
,
1
,
3
,
2
);
countryGroupAssignment
.
putAll
(
"BR"
,
2
,
4
,
2
,
2
,
3
);
countryGroupAssignment
.
putAll
(
"BS"
,
2
,
2
,
1
,
3
,
2
);
countryGroupAssignment
.
putAll
(
"BT"
,
3
,
0
,
3
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"BW"
,
3
,
4
,
1
,
1
,
2
);
countryGroupAssignment
.
putAll
(
"BY"
,
1
,
1
,
1
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"BZ"
,
2
,
2
,
2
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"CA"
,
0
,
3
,
1
,
2
,
4
);
countryGroupAssignment
.
putAll
(
"CD"
,
4
,
3
,
2
,
1
,
2
);
countryGroupAssignment
.
putAll
(
"CF"
,
4
,
2
,
3
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"CG"
,
3
,
4
,
2
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"CH"
,
0
,
0
,
0
,
0
,
2
);
countryGroupAssignment
.
putAll
(
"CI"
,
3
,
3
,
3
,
3
,
2
);
countryGroupAssignment
.
putAll
(
"CK"
,
2
,
2
,
3
,
0
,
2
);
countryGroupAssignment
.
putAll
(
"CL"
,
1
,
1
,
2
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"CM"
,
3
,
4
,
3
,
3
,
2
);
countryGroupAssignment
.
putAll
(
"CN"
,
2
,
2
,
2
,
1
,
4
);
countryGroupAssignment
.
putAll
(
"CO"
,
2
,
3
,
4
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"CR"
,
2
,
3
,
4
,
4
,
2
);
countryGroupAssignment
.
putAll
(
"CU"
,
4
,
4
,
2
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"CV"
,
2
,
3
,
1
,
0
,
2
);
countryGroupAssignment
.
putAll
(
"CW"
,
1
,
2
,
0
,
0
,
2
);
countryGroupAssignment
.
putAll
(
"CY"
,
1
,
1
,
0
,
0
,
2
);
countryGroupAssignment
.
putAll
(
"CZ"
,
0
,
1
,
0
,
0
,
1
);
countryGroupAssignment
.
putAll
(
"DE"
,
0
,
0
,
1
,
1
,
0
);
countryGroupAssignment
.
putAll
(
"DJ"
,
4
,
0
,
4
,
4
,
2
);
countryGroupAssignment
.
putAll
(
"DK"
,
0
,
0
,
1
,
0
,
0
);
countryGroupAssignment
.
putAll
(
"DM"
,
1
,
2
,
2
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"DO"
,
3
,
4
,
4
,
4
,
2
);
countryGroupAssignment
.
putAll
(
"DZ"
,
3
,
3
,
4
,
4
,
2
);
countryGroupAssignment
.
putAll
(
"EC"
,
2
,
4
,
3
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"EE"
,
0
,
1
,
0
,
0
,
2
);
countryGroupAssignment
.
putAll
(
"EG"
,
3
,
4
,
3
,
3
,
2
);
countryGroupAssignment
.
putAll
(
"EH"
,
2
,
2
,
2
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"ER"
,
4
,
2
,
2
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"ES"
,
0
,
1
,
1
,
1
,
2
);
countryGroupAssignment
.
putAll
(
"ET"
,
4
,
4
,
4
,
1
,
2
);
countryGroupAssignment
.
putAll
(
"FI"
,
0
,
0
,
0
,
0
,
0
);
countryGroupAssignment
.
putAll
(
"FJ"
,
3
,
0
,
2
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"FK"
,
4
,
2
,
2
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"FM"
,
3
,
2
,
4
,
4
,
2
);
countryGroupAssignment
.
putAll
(
"FO"
,
1
,
2
,
0
,
1
,
2
);
countryGroupAssignment
.
putAll
(
"FR"
,
1
,
1
,
2
,
0
,
1
);
countryGroupAssignment
.
putAll
(
"GA"
,
3
,
4
,
1
,
1
,
2
);
countryGroupAssignment
.
putAll
(
"GB"
,
0
,
0
,
1
,
1
,
1
);
countryGroupAssignment
.
putAll
(
"GD"
,
1
,
2
,
2
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"GE"
,
1
,
1
,
1
,
3
,
2
);
countryGroupAssignment
.
putAll
(
"GF"
,
2
,
2
,
2
,
3
,
2
);
countryGroupAssignment
.
putAll
(
"GG"
,
1
,
2
,
0
,
0
,
2
);
countryGroupAssignment
.
putAll
(
"GH"
,
3
,
1
,
3
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"GI"
,
0
,
2
,
2
,
0
,
2
);
countryGroupAssignment
.
putAll
(
"GL"
,
1
,
2
,
0
,
0
,
2
);
countryGroupAssignment
.
putAll
(
"GM"
,
4
,
3
,
2
,
4
,
2
);
countryGroupAssignment
.
putAll
(
"GN"
,
3
,
3
,
4
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"GP"
,
2
,
1
,
2
,
3
,
2
);
countryGroupAssignment
.
putAll
(
"GQ"
,
4
,
2
,
2
,
4
,
2
);
countryGroupAssignment
.
putAll
(
"GR"
,
1
,
2
,
0
,
1
,
2
);
countryGroupAssignment
.
putAll
(
"GT"
,
3
,
2
,
2
,
1
,
2
);
countryGroupAssignment
.
putAll
(
"GU"
,
1
,
2
,
3
,
4
,
2
);
countryGroupAssignment
.
putAll
(
"GW"
,
4
,
4
,
4
,
4
,
2
);
countryGroupAssignment
.
putAll
(
"GY"
,
3
,
3
,
3
,
4
,
2
);
countryGroupAssignment
.
putAll
(
"HK"
,
0
,
1
,
2
,
3
,
2
);
countryGroupAssignment
.
putAll
(
"HN"
,
3
,
1
,
3
,
3
,
2
);
countryGroupAssignment
.
putAll
(
"HR"
,
1
,
1
,
0
,
0
,
3
);
countryGroupAssignment
.
putAll
(
"HT"
,
4
,
4
,
4
,
4
,
2
);
countryGroupAssignment
.
putAll
(
"HU"
,
0
,
0
,
0
,
0
,
1
);
countryGroupAssignment
.
putAll
(
"ID"
,
3
,
2
,
3
,
3
,
2
);
countryGroupAssignment
.
putAll
(
"IE"
,
0
,
0
,
1
,
1
,
3
);
countryGroupAssignment
.
putAll
(
"IL"
,
1
,
0
,
2
,
3
,
4
);
countryGroupAssignment
.
putAll
(
"IM"
,
0
,
2
,
0
,
1
,
2
);
countryGroupAssignment
.
putAll
(
"IN"
,
2
,
1
,
3
,
3
,
2
);
countryGroupAssignment
.
putAll
(
"IO"
,
4
,
2
,
2
,
4
,
2
);
countryGroupAssignment
.
putAll
(
"IQ"
,
3
,
3
,
4
,
4
,
2
);
countryGroupAssignment
.
putAll
(
"IR"
,
3
,
2
,
3
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"IS"
,
0
,
2
,
0
,
0
,
2
);
countryGroupAssignment
.
putAll
(
"IT"
,
0
,
4
,
1
,
1
,
2
);
countryGroupAssignment
.
putAll
(
"JE"
,
2
,
2
,
1
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"JM"
,
3
,
3
,
4
,
4
,
2
);
countryGroupAssignment
.
putAll
(
"JO"
,
2
,
2
,
1
,
1
,
2
);
countryGroupAssignment
.
putAll
(
"JP"
,
0
,
0
,
0
,
0
,
3
);
countryGroupAssignment
.
putAll
(
"KE"
,
3
,
4
,
2
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"KG"
,
2
,
0
,
1
,
1
,
2
);
countryGroupAssignment
.
putAll
(
"KH"
,
1
,
0
,
4
,
3
,
2
);
countryGroupAssignment
.
putAll
(
"KI"
,
4
,
2
,
4
,
3
,
2
);
countryGroupAssignment
.
putAll
(
"KM"
,
4
,
3
,
3
,
3
,
2
);
countryGroupAssignment
.
putAll
(
"KN"
,
1
,
2
,
2
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"KP"
,
4
,
2
,
2
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"KR"
,
0
,
0
,
1
,
3
,
1
);
countryGroupAssignment
.
putAll
(
"KW"
,
1
,
3
,
0
,
0
,
0
);
countryGroupAssignment
.
putAll
(
"KY"
,
1
,
2
,
0
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"KZ"
,
2
,
2
,
2
,
3
,
2
);
countryGroupAssignment
.
putAll
(
"LA"
,
2
,
2
,
1
,
1
,
2
);
countryGroupAssignment
.
putAll
(
"LB"
,
3
,
2
,
0
,
0
,
2
);
countryGroupAssignment
.
putAll
(
"LC"
,
1
,
2
,
0
,
1
,
2
);
countryGroupAssignment
.
putAll
(
"LI"
,
0
,
2
,
2
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"LK"
,
2
,
0
,
2
,
3
,
2
);
countryGroupAssignment
.
putAll
(
"LR"
,
3
,
4
,
4
,
3
,
2
);
countryGroupAssignment
.
putAll
(
"LS"
,
3
,
3
,
2
,
3
,
2
);
countryGroupAssignment
.
putAll
(
"LT"
,
0
,
0
,
0
,
0
,
2
);
countryGroupAssignment
.
putAll
(
"LU"
,
1
,
0
,
1
,
1
,
2
);
countryGroupAssignment
.
putAll
(
"LV"
,
0
,
0
,
0
,
0
,
2
);
countryGroupAssignment
.
putAll
(
"LY"
,
4
,
2
,
4
,
4
,
2
);
countryGroupAssignment
.
putAll
(
"MA"
,
3
,
2
,
2
,
1
,
2
);
countryGroupAssignment
.
putAll
(
"MC"
,
0
,
2
,
0
,
0
,
2
);
countryGroupAssignment
.
putAll
(
"MD"
,
1
,
2
,
0
,
0
,
2
);
countryGroupAssignment
.
putAll
(
"ME"
,
1
,
2
,
0
,
1
,
2
);
countryGroupAssignment
.
putAll
(
"MF"
,
1
,
2
,
1
,
1
,
2
);
countryGroupAssignment
.
putAll
(
"MG"
,
3
,
4
,
2
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"MH"
,
4
,
2
,
2
,
4
,
2
);
countryGroupAssignment
.
putAll
(
"MK"
,
1
,
1
,
0
,
0
,
2
);
countryGroupAssignment
.
putAll
(
"ML"
,
4
,
4
,
2
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"MM"
,
2
,
3
,
3
,
3
,
2
);
countryGroupAssignment
.
putAll
(
"MN"
,
2
,
4
,
1
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"MO"
,
0
,
2
,
4
,
4
,
2
);
countryGroupAssignment
.
putAll
(
"MP"
,
0
,
2
,
2
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"MQ"
,
2
,
2
,
2
,
3
,
2
);
countryGroupAssignment
.
putAll
(
"MR"
,
3
,
0
,
4
,
3
,
2
);
countryGroupAssignment
.
putAll
(
"MS"
,
1
,
2
,
2
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"MT"
,
0
,
2
,
0
,
0
,
2
);
countryGroupAssignment
.
putAll
(
"MU"
,
3
,
1
,
1
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"MV"
,
4
,
3
,
3
,
4
,
2
);
countryGroupAssignment
.
putAll
(
"MW"
,
4
,
2
,
1
,
0
,
2
);
countryGroupAssignment
.
putAll
(
"MX"
,
2
,
4
,
3
,
4
,
2
);
countryGroupAssignment
.
putAll
(
"MY"
,
1
,
0
,
3
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"MZ"
,
3
,
3
,
2
,
1
,
2
);
countryGroupAssignment
.
putAll
(
"NA"
,
4
,
3
,
3
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"NC"
,
2
,
0
,
3
,
4
,
2
);
countryGroupAssignment
.
putAll
(
"NE"
,
4
,
4
,
4
,
4
,
2
);
countryGroupAssignment
.
putAll
(
"NF"
,
2
,
2
,
2
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"NG"
,
3
,
3
,
2
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"NI"
,
2
,
1
,
4
,
4
,
2
);
countryGroupAssignment
.
putAll
(
"NL"
,
0
,
2
,
3
,
2
,
0
);
countryGroupAssignment
.
putAll
(
"NO"
,
0
,
1
,
2
,
0
,
0
);
countryGroupAssignment
.
putAll
(
"NP"
,
2
,
0
,
4
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"NR"
,
3
,
2
,
2
,
1
,
2
);
countryGroupAssignment
.
putAll
(
"NU"
,
4
,
2
,
2
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"NZ"
,
0
,
2
,
1
,
2
,
4
);
countryGroupAssignment
.
putAll
(
"OM"
,
2
,
2
,
1
,
3
,
2
);
countryGroupAssignment
.
putAll
(
"PA"
,
1
,
3
,
3
,
3
,
2
);
countryGroupAssignment
.
putAll
(
"PE"
,
2
,
3
,
4
,
4
,
2
);
countryGroupAssignment
.
putAll
(
"PF"
,
2
,
2
,
2
,
1
,
2
);
countryGroupAssignment
.
putAll
(
"PG"
,
4
,
4
,
3
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"PH"
,
2
,
1
,
3
,
3
,
4
);
countryGroupAssignment
.
putAll
(
"PK"
,
3
,
2
,
3
,
3
,
2
);
countryGroupAssignment
.
putAll
(
"PL"
,
1
,
0
,
1
,
2
,
3
);
countryGroupAssignment
.
putAll
(
"PM"
,
0
,
2
,
2
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"PR"
,
2
,
1
,
2
,
2
,
4
);
countryGroupAssignment
.
putAll
(
"PS"
,
3
,
3
,
2
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"PT"
,
0
,
1
,
1
,
0
,
2
);
countryGroupAssignment
.
putAll
(
"PW"
,
1
,
2
,
4
,
0
,
2
);
countryGroupAssignment
.
putAll
(
"PY"
,
2
,
0
,
3
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"QA"
,
2
,
3
,
1
,
2
,
3
);
countryGroupAssignment
.
putAll
(
"RE"
,
1
,
0
,
2
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"RO"
,
0
,
1
,
0
,
1
,
1
);
countryGroupAssignment
.
putAll
(
"RS"
,
1
,
2
,
0
,
0
,
2
);
countryGroupAssignment
.
putAll
(
"RU"
,
0
,
1
,
0
,
1
,
2
);
countryGroupAssignment
.
putAll
(
"RW"
,
3
,
3
,
4
,
1
,
2
);
countryGroupAssignment
.
putAll
(
"SA"
,
2
,
2
,
2
,
1
,
2
);
countryGroupAssignment
.
putAll
(
"SB"
,
4
,
2
,
3
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"SC"
,
4
,
1
,
1
,
3
,
2
);
countryGroupAssignment
.
putAll
(
"SD"
,
4
,
4
,
4
,
4
,
2
);
countryGroupAssignment
.
putAll
(
"SE"
,
0
,
0
,
0
,
0
,
0
);
countryGroupAssignment
.
putAll
(
"SG"
,
1
,
0
,
1
,
2
,
3
);
countryGroupAssignment
.
putAll
(
"SH"
,
4
,
2
,
2
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"SI"
,
0
,
0
,
0
,
0
,
2
);
countryGroupAssignment
.
putAll
(
"SJ"
,
2
,
2
,
2
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"SK"
,
0
,
1
,
0
,
0
,
2
);
countryGroupAssignment
.
putAll
(
"SL"
,
4
,
3
,
4
,
0
,
2
);
countryGroupAssignment
.
putAll
(
"SM"
,
0
,
2
,
2
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"SN"
,
4
,
4
,
4
,
4
,
2
);
countryGroupAssignment
.
putAll
(
"SO"
,
3
,
3
,
3
,
4
,
2
);
countryGroupAssignment
.
putAll
(
"SR"
,
3
,
2
,
2
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"SS"
,
4
,
4
,
3
,
3
,
2
);
countryGroupAssignment
.
putAll
(
"ST"
,
2
,
2
,
1
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"SV"
,
2
,
1
,
4
,
3
,
2
);
countryGroupAssignment
.
putAll
(
"SX"
,
2
,
2
,
1
,
0
,
2
);
countryGroupAssignment
.
putAll
(
"SY"
,
4
,
3
,
3
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"SZ"
,
4
,
3
,
2
,
4
,
2
);
countryGroupAssignment
.
putAll
(
"TC"
,
2
,
2
,
2
,
0
,
2
);
countryGroupAssignment
.
putAll
(
"TD"
,
4
,
3
,
4
,
4
,
2
);
countryGroupAssignment
.
putAll
(
"TG"
,
3
,
2
,
2
,
4
,
2
);
countryGroupAssignment
.
putAll
(
"TH"
,
0
,
3
,
2
,
3
,
2
);
countryGroupAssignment
.
putAll
(
"TJ"
,
4
,
4
,
4
,
4
,
2
);
countryGroupAssignment
.
putAll
(
"TL"
,
4
,
0
,
4
,
4
,
2
);
countryGroupAssignment
.
putAll
(
"TM"
,
4
,
2
,
4
,
3
,
2
);
countryGroupAssignment
.
putAll
(
"TN"
,
2
,
2
,
1
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"TO"
,
3
,
2
,
4
,
3
,
2
);
countryGroupAssignment
.
putAll
(
"TR"
,
1
,
2
,
0
,
1
,
2
);
countryGroupAssignment
.
putAll
(
"TT"
,
1
,
4
,
0
,
1
,
2
);
countryGroupAssignment
.
putAll
(
"TV"
,
3
,
2
,
2
,
4
,
2
);
countryGroupAssignment
.
putAll
(
"TW"
,
0
,
0
,
0
,
0
,
1
);
countryGroupAssignment
.
putAll
(
"TZ"
,
3
,
3
,
3
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"UA"
,
0
,
3
,
1
,
1
,
2
);
countryGroupAssignment
.
putAll
(
"UG"
,
3
,
2
,
3
,
3
,
2
);
countryGroupAssignment
.
putAll
(
"US"
,
1
,
1
,
2
,
2
,
4
);
countryGroupAssignment
.
putAll
(
"UY"
,
2
,
1
,
1
,
1
,
2
);
countryGroupAssignment
.
putAll
(
"UZ"
,
2
,
1
,
3
,
4
,
2
);
countryGroupAssignment
.
putAll
(
"VC"
,
1
,
2
,
2
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"VE"
,
4
,
4
,
4
,
4
,
2
);
countryGroupAssignment
.
putAll
(
"VG"
,
2
,
2
,
1
,
1
,
2
);
countryGroupAssignment
.
putAll
(
"VI"
,
1
,
2
,
1
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"VN"
,
0
,
1
,
3
,
4
,
2
);
countryGroupAssignment
.
putAll
(
"VU"
,
4
,
0
,
3
,
1
,
2
);
countryGroupAssignment
.
putAll
(
"WF"
,
4
,
2
,
2
,
2
,
2
);
countryGroupAssignment
.
putAll
(
"WS"
,
3
,
1
,
3
,
1
,
2
);
countryGroupAssignment
.
putAll
(
"XK"
,
0
,
1
,
1
,
1
,
2
);
countryGroupAssignment
.
putAll
(
"YE"
,
4
,
4
,
4
,
3
,
2
);
countryGroupAssignment
.
putAll
(
"YT"
,
4
,
2
,
2
,
3
,
2
);
countryGroupAssignment
.
putAll
(
"ZA"
,
3
,
3
,
2
,
1
,
2
);
countryGroupAssignment
.
putAll
(
"ZM"
,
3
,
2
,
3
,
3
,
2
);
countryGroupAssignment
.
putAll
(
"ZW"
,
3
,
2
,
4
,
3
,
2
);
return
countryGroupAssignment
.
build
();
}
}
library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheWriter.java
View file @
675b81e5
...
...
@@ -23,7 +23,6 @@ import com.google.android.exoplayer2.upstream.DataSpec;
import
com.google.android.exoplayer2.util.PriorityTaskManager
;
import
com.google.android.exoplayer2.util.PriorityTaskManager.PriorityTooLowException
;
import
com.google.android.exoplayer2.util.Util
;
import
java.io.EOFException
;
import
java.io.IOException
;
import
java.io.InterruptedIOException
;
...
...
@@ -51,7 +50,6 @@ public final class CacheWriter {
private
final
CacheDataSource
dataSource
;
private
final
Cache
cache
;
private
final
DataSpec
dataSpec
;
private
final
boolean
allowShortContent
;
private
final
String
cacheKey
;
private
final
byte
[]
temporaryBuffer
;
@Nullable
private
final
ProgressListener
progressListener
;
...
...
@@ -65,10 +63,6 @@ public final class CacheWriter {
/**
* @param dataSource A {@link CacheDataSource} that writes to the target cache.
* @param dataSpec Defines the data to be written.
* @param allowShortContent Whether it's allowed for the content to end before the request as
* defined by the {@link DataSpec}. If {@code true} and the request exceeds the length of the
* content, then the content will be cached to the end. If {@code false} and the request
* exceeds the length of the content, {@link #cache} will throw an {@link IOException}.
* @param temporaryBuffer A temporary buffer to be used during caching, or {@code null} if the
* writer should instantiate its own internal temporary buffer.
* @param progressListener An optional progress listener.
...
...
@@ -76,13 +70,11 @@ public final class CacheWriter {
public
CacheWriter
(
CacheDataSource
dataSource
,
DataSpec
dataSpec
,
boolean
allowShortContent
,
@Nullable
byte
[]
temporaryBuffer
,
@Nullable
ProgressListener
progressListener
)
{
this
.
dataSource
=
dataSource
;
this
.
cache
=
dataSource
.
getCache
();
this
.
dataSpec
=
dataSpec
;
this
.
allowShortContent
=
allowShortContent
;
this
.
temporaryBuffer
=
temporaryBuffer
==
null
?
new
byte
[
DEFAULT_BUFFER_SIZE_BYTES
]
:
temporaryBuffer
;
this
.
progressListener
=
progressListener
;
...
...
@@ -143,14 +135,6 @@ public final class CacheWriter {
nextPosition
+=
readBlockToCache
(
nextPosition
,
nextRequestLength
);
}
}
// TODO: Remove allowShortContent parameter, this code block, and return the number of bytes
// cached. The caller can then check whether fewer bytes were cached than were requested.
if
(!
allowShortContent
&&
dataSpec
.
length
!=
C
.
LENGTH_UNSET
&&
nextPosition
!=
dataSpec
.
position
+
dataSpec
.
length
)
{
throw
new
EOFException
();
}
}
/**
...
...
@@ -176,9 +160,11 @@ public final class CacheWriter {
isDataSourceOpen
=
true
;
}
catch
(
IOException
e
)
{
Util
.
closeQuietly
(
dataSource
);
if
(
allowShortContent
&&
isLastBlock
&&
DataSourceException
.
isCausedByPositionOutOfRange
(
e
))
{
// TODO: This exception handling may be required for interop with current HttpDataSource
// implementations that (incorrectly) throw a position-out-of-range when opened exactly one
// byte beyond the end of the resource. It should be removed when the HttpDataSource
// implementations are fixed.
if
(
isLastBlock
&&
DataSourceException
.
isCausedByPositionOutOfRange
(
e
))
{
// The length of the request exceeds the length of the content. If we allow shorter
// content and are reading the last block, fall through and try again with an unbounded
// request to read up to the end of the content.
...
...
library/core/src/test/java/com/google/android/exoplayer2/upstream/ExperimentalBandwidthMeterTest.java
0 → 100644
View file @
675b81e5
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
com
.
google
.
android
.
exoplayer2
.
upstream
;
import
static
android
.
net
.
NetworkInfo
.
State
.
CONNECTED
;
import
static
android
.
net
.
NetworkInfo
.
State
.
DISCONNECTED
;
import
static
com
.
google
.
common
.
truth
.
Truth
.
assertThat
;
import
android.content.Context
;
import
android.net.ConnectivityManager
;
import
android.net.NetworkInfo
;
import
android.net.NetworkInfo.DetailedState
;
import
android.net.Uri
;
import
android.telephony.TelephonyManager
;
import
androidx.test.core.app.ApplicationProvider
;
import
androidx.test.ext.junit.runners.AndroidJUnit4
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.testutil.FakeClock
;
import
com.google.android.exoplayer2.testutil.FakeDataSource
;
import
java.util.Random
;
import
org.junit.Before
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
import
org.robolectric.Shadows
;
import
org.robolectric.shadows.ShadowNetworkInfo
;
/** Unit test for {@link ExperimentalBandwidthMeter}. */
@RunWith
(
AndroidJUnit4
.
class
)
public
final
class
ExperimentalBandwidthMeterTest
{
private
static
final
int
SIMULATED_TRANSFER_COUNT
=
100
;
private
static
final
String
FAST_COUNTRY_ISO
=
"EE"
;
private
static
final
String
SLOW_COUNTRY_ISO
=
"PG"
;
private
TelephonyManager
telephonyManager
;
private
ConnectivityManager
connectivityManager
;
private
NetworkInfo
networkInfoOffline
;
private
NetworkInfo
networkInfoWifi
;
private
NetworkInfo
networkInfo2g
;
private
NetworkInfo
networkInfo3g
;
private
NetworkInfo
networkInfo4g
;
private
NetworkInfo
networkInfoEthernet
;
@Before
public
void
setUp
()
{
connectivityManager
=
(
ConnectivityManager
)
ApplicationProvider
.
getApplicationContext
()
.
getSystemService
(
Context
.
CONNECTIVITY_SERVICE
);
telephonyManager
=
(
TelephonyManager
)
ApplicationProvider
.
getApplicationContext
().
getSystemService
(
Context
.
TELEPHONY_SERVICE
);
Shadows
.
shadowOf
(
telephonyManager
).
setNetworkCountryIso
(
FAST_COUNTRY_ISO
);
networkInfoOffline
=
ShadowNetworkInfo
.
newInstance
(
DetailedState
.
DISCONNECTED
,
ConnectivityManager
.
TYPE_WIFI
,
/* subType= */
0
,
/* isAvailable= */
false
,
DISCONNECTED
);
networkInfoWifi
=
ShadowNetworkInfo
.
newInstance
(
DetailedState
.
CONNECTED
,
ConnectivityManager
.
TYPE_WIFI
,
/* subType= */
0
,
/* isAvailable= */
true
,
CONNECTED
);
networkInfo2g
=
ShadowNetworkInfo
.
newInstance
(
DetailedState
.
CONNECTED
,
ConnectivityManager
.
TYPE_MOBILE
,
TelephonyManager
.
NETWORK_TYPE_GPRS
,
/* isAvailable= */
true
,
CONNECTED
);
networkInfo3g
=
ShadowNetworkInfo
.
newInstance
(
DetailedState
.
CONNECTED
,
ConnectivityManager
.
TYPE_MOBILE
,
TelephonyManager
.
NETWORK_TYPE_HSDPA
,
/* isAvailable= */
true
,
CONNECTED
);
networkInfo4g
=
ShadowNetworkInfo
.
newInstance
(
DetailedState
.
CONNECTED
,
ConnectivityManager
.
TYPE_MOBILE
,
TelephonyManager
.
NETWORK_TYPE_LTE
,
/* isAvailable= */
true
,
CONNECTED
);
networkInfoEthernet
=
ShadowNetworkInfo
.
newInstance
(
DetailedState
.
CONNECTED
,
ConnectivityManager
.
TYPE_ETHERNET
,
/* subType= */
0
,
/* isAvailable= */
true
,
CONNECTED
);
}
@Test
public
void
defaultInitialBitrateEstimate_forWifi_isGreaterThanEstimateFor2G
()
{
setActiveNetworkInfo
(
networkInfoWifi
);
ExperimentalBandwidthMeter
bandwidthMeterWifi
=
new
ExperimentalBandwidthMeter
.
Builder
(
ApplicationProvider
.
getApplicationContext
()).
build
();
long
initialEstimateWifi
=
bandwidthMeterWifi
.
getBitrateEstimate
();
setActiveNetworkInfo
(
networkInfo2g
);
ExperimentalBandwidthMeter
bandwidthMeter2g
=
new
ExperimentalBandwidthMeter
.
Builder
(
ApplicationProvider
.
getApplicationContext
()).
build
();
long
initialEstimate2g
=
bandwidthMeter2g
.
getBitrateEstimate
();
assertThat
(
initialEstimateWifi
).
isGreaterThan
(
initialEstimate2g
);
}
@Test
public
void
defaultInitialBitrateEstimate_forWifi_isGreaterThanEstimateFor3G
()
{
setActiveNetworkInfo
(
networkInfoWifi
);
ExperimentalBandwidthMeter
bandwidthMeterWifi
=
new
ExperimentalBandwidthMeter
.
Builder
(
ApplicationProvider
.
getApplicationContext
()).
build
();
long
initialEstimateWifi
=
bandwidthMeterWifi
.
getBitrateEstimate
();
setActiveNetworkInfo
(
networkInfo3g
);
ExperimentalBandwidthMeter
bandwidthMeter3g
=
new
ExperimentalBandwidthMeter
.
Builder
(
ApplicationProvider
.
getApplicationContext
()).
build
();
long
initialEstimate3g
=
bandwidthMeter3g
.
getBitrateEstimate
();
assertThat
(
initialEstimateWifi
).
isGreaterThan
(
initialEstimate3g
);
}
@Test
public
void
defaultInitialBitrateEstimate_forEthernet_isGreaterThanEstimateFor2G
()
{
setActiveNetworkInfo
(
networkInfoEthernet
);
ExperimentalBandwidthMeter
bandwidthMeterEthernet
=
new
ExperimentalBandwidthMeter
.
Builder
(
ApplicationProvider
.
getApplicationContext
()).
build
();
long
initialEstimateEthernet
=
bandwidthMeterEthernet
.
getBitrateEstimate
();
setActiveNetworkInfo
(
networkInfo2g
);
ExperimentalBandwidthMeter
bandwidthMeter2g
=
new
ExperimentalBandwidthMeter
.
Builder
(
ApplicationProvider
.
getApplicationContext
()).
build
();
long
initialEstimate2g
=
bandwidthMeter2g
.
getBitrateEstimate
();
assertThat
(
initialEstimateEthernet
).
isGreaterThan
(
initialEstimate2g
);
}
@Test
public
void
defaultInitialBitrateEstimate_forEthernet_isGreaterThanEstimateFor3G
()
{
setActiveNetworkInfo
(
networkInfoEthernet
);
ExperimentalBandwidthMeter
bandwidthMeterEthernet
=
new
ExperimentalBandwidthMeter
.
Builder
(
ApplicationProvider
.
getApplicationContext
()).
build
();
long
initialEstimateEthernet
=
bandwidthMeterEthernet
.
getBitrateEstimate
();
setActiveNetworkInfo
(
networkInfo3g
);
ExperimentalBandwidthMeter
bandwidthMeter3g
=
new
ExperimentalBandwidthMeter
.
Builder
(
ApplicationProvider
.
getApplicationContext
()).
build
();
long
initialEstimate3g
=
bandwidthMeter3g
.
getBitrateEstimate
();
assertThat
(
initialEstimateEthernet
).
isGreaterThan
(
initialEstimate3g
);
}
@Test
public
void
defaultInitialBitrateEstimate_for4G_isGreaterThanEstimateFor2G
()
{
setActiveNetworkInfo
(
networkInfo4g
);
ExperimentalBandwidthMeter
bandwidthMeter4g
=
new
ExperimentalBandwidthMeter
.
Builder
(
ApplicationProvider
.
getApplicationContext
()).
build
();
long
initialEstimate4g
=
bandwidthMeter4g
.
getBitrateEstimate
();
setActiveNetworkInfo
(
networkInfo2g
);
ExperimentalBandwidthMeter
bandwidthMeter2g
=
new
ExperimentalBandwidthMeter
.
Builder
(
ApplicationProvider
.
getApplicationContext
()).
build
();
long
initialEstimate2g
=
bandwidthMeter2g
.
getBitrateEstimate
();
assertThat
(
initialEstimate4g
).
isGreaterThan
(
initialEstimate2g
);
}
@Test
public
void
defaultInitialBitrateEstimate_for4G_isGreaterThanEstimateFor3G
()
{
setActiveNetworkInfo
(
networkInfo4g
);
ExperimentalBandwidthMeter
bandwidthMeter4g
=
new
ExperimentalBandwidthMeter
.
Builder
(
ApplicationProvider
.
getApplicationContext
()).
build
();
long
initialEstimate4g
=
bandwidthMeter4g
.
getBitrateEstimate
();
setActiveNetworkInfo
(
networkInfo3g
);
ExperimentalBandwidthMeter
bandwidthMeter3g
=
new
ExperimentalBandwidthMeter
.
Builder
(
ApplicationProvider
.
getApplicationContext
()).
build
();
long
initialEstimate3g
=
bandwidthMeter3g
.
getBitrateEstimate
();
assertThat
(
initialEstimate4g
).
isGreaterThan
(
initialEstimate3g
);
}
@Test
public
void
defaultInitialBitrateEstimate_for3G_isGreaterThanEstimateFor2G
()
{
setActiveNetworkInfo
(
networkInfo3g
);
ExperimentalBandwidthMeter
bandwidthMeter3g
=
new
ExperimentalBandwidthMeter
.
Builder
(
ApplicationProvider
.
getApplicationContext
()).
build
();
long
initialEstimate3g
=
bandwidthMeter3g
.
getBitrateEstimate
();
setActiveNetworkInfo
(
networkInfo2g
);
ExperimentalBandwidthMeter
bandwidthMeter2g
=
new
ExperimentalBandwidthMeter
.
Builder
(
ApplicationProvider
.
getApplicationContext
()).
build
();
long
initialEstimate2g
=
bandwidthMeter2g
.
getBitrateEstimate
();
assertThat
(
initialEstimate3g
).
isGreaterThan
(
initialEstimate2g
);
}
@Test
public
void
defaultInitialBitrateEstimate_forOffline_isReasonable
()
{
setActiveNetworkInfo
(
networkInfoOffline
);
ExperimentalBandwidthMeter
bandwidthMeter
=
new
ExperimentalBandwidthMeter
.
Builder
(
ApplicationProvider
.
getApplicationContext
()).
build
();
long
initialEstimate
=
bandwidthMeter
.
getBitrateEstimate
();
assertThat
(
initialEstimate
).
isGreaterThan
(
100_000L
);
assertThat
(
initialEstimate
).
isLessThan
(
50_000_000L
);
}
@Test
public
void
defaultInitialBitrateEstimate_forWifi_forFastCountry_isGreaterThanEstimateForSlowCountry
()
{
setActiveNetworkInfo
(
networkInfoWifi
);
setNetworkCountryIso
(
FAST_COUNTRY_ISO
);
ExperimentalBandwidthMeter
bandwidthMeterFast
=
new
ExperimentalBandwidthMeter
.
Builder
(
ApplicationProvider
.
getApplicationContext
()).
build
();
long
initialEstimateFast
=
bandwidthMeterFast
.
getBitrateEstimate
();
setNetworkCountryIso
(
SLOW_COUNTRY_ISO
);
ExperimentalBandwidthMeter
bandwidthMeterSlow
=
new
ExperimentalBandwidthMeter
.
Builder
(
ApplicationProvider
.
getApplicationContext
()).
build
();
long
initialEstimateSlow
=
bandwidthMeterSlow
.
getBitrateEstimate
();
assertThat
(
initialEstimateFast
).
isGreaterThan
(
initialEstimateSlow
);
}
@Test
public
void
defaultInitialBitrateEstimate_forEthernet_forFastCountry_isGreaterThanEstimateForSlowCountry
()
{
setActiveNetworkInfo
(
networkInfoEthernet
);
setNetworkCountryIso
(
FAST_COUNTRY_ISO
);
ExperimentalBandwidthMeter
bandwidthMeterFast
=
new
ExperimentalBandwidthMeter
.
Builder
(
ApplicationProvider
.
getApplicationContext
()).
build
();
long
initialEstimateFast
=
bandwidthMeterFast
.
getBitrateEstimate
();
setNetworkCountryIso
(
SLOW_COUNTRY_ISO
);
ExperimentalBandwidthMeter
bandwidthMeterSlow
=
new
ExperimentalBandwidthMeter
.
Builder
(
ApplicationProvider
.
getApplicationContext
()).
build
();
long
initialEstimateSlow
=
bandwidthMeterSlow
.
getBitrateEstimate
();
assertThat
(
initialEstimateFast
).
isGreaterThan
(
initialEstimateSlow
);
}
@Test
public
void
defaultInitialBitrateEstimate_for2G_forFastCountry_isGreaterThanEstimateForSlowCountry
()
{
setActiveNetworkInfo
(
networkInfo2g
);
setNetworkCountryIso
(
FAST_COUNTRY_ISO
);
ExperimentalBandwidthMeter
bandwidthMeterFast
=
new
ExperimentalBandwidthMeter
.
Builder
(
ApplicationProvider
.
getApplicationContext
()).
build
();
long
initialEstimateFast
=
bandwidthMeterFast
.
getBitrateEstimate
();
setNetworkCountryIso
(
SLOW_COUNTRY_ISO
);
ExperimentalBandwidthMeter
bandwidthMeterSlow
=
new
ExperimentalBandwidthMeter
.
Builder
(
ApplicationProvider
.
getApplicationContext
()).
build
();
long
initialEstimateSlow
=
bandwidthMeterSlow
.
getBitrateEstimate
();
assertThat
(
initialEstimateFast
).
isGreaterThan
(
initialEstimateSlow
);
}
@Test
public
void
defaultInitialBitrateEstimate_for3G_forFastCountry_isGreaterThanEstimateForSlowCountry
()
{
setActiveNetworkInfo
(
networkInfo3g
);
setNetworkCountryIso
(
FAST_COUNTRY_ISO
);
ExperimentalBandwidthMeter
bandwidthMeterFast
=
new
ExperimentalBandwidthMeter
.
Builder
(
ApplicationProvider
.
getApplicationContext
()).
build
();
long
initialEstimateFast
=
bandwidthMeterFast
.
getBitrateEstimate
();
setNetworkCountryIso
(
SLOW_COUNTRY_ISO
);
ExperimentalBandwidthMeter
bandwidthMeterSlow
=
new
ExperimentalBandwidthMeter
.
Builder
(
ApplicationProvider
.
getApplicationContext
()).
build
();
long
initialEstimateSlow
=
bandwidthMeterSlow
.
getBitrateEstimate
();
assertThat
(
initialEstimateFast
).
isGreaterThan
(
initialEstimateSlow
);
}
@Test
public
void
defaultInitialBitrateEstimate_for4g_forFastCountry_isGreaterThanEstimateForSlowCountry
()
{
setActiveNetworkInfo
(
networkInfo4g
);
setNetworkCountryIso
(
FAST_COUNTRY_ISO
);
ExperimentalBandwidthMeter
bandwidthMeterFast
=
new
ExperimentalBandwidthMeter
.
Builder
(
ApplicationProvider
.
getApplicationContext
()).
build
();
long
initialEstimateFast
=
bandwidthMeterFast
.
getBitrateEstimate
();
setNetworkCountryIso
(
SLOW_COUNTRY_ISO
);
ExperimentalBandwidthMeter
bandwidthMeterSlow
=
new
ExperimentalBandwidthMeter
.
Builder
(
ApplicationProvider
.
getApplicationContext
()).
build
();
long
initialEstimateSlow
=
bandwidthMeterSlow
.
getBitrateEstimate
();
assertThat
(
initialEstimateFast
).
isGreaterThan
(
initialEstimateSlow
);
}
@Test
public
void
initialBitrateEstimateOverwrite_whileConnectedToNetwork_setsInitialEstimate
()
{
setActiveNetworkInfo
(
networkInfoWifi
);
ExperimentalBandwidthMeter
bandwidthMeter
=
new
ExperimentalBandwidthMeter
.
Builder
(
ApplicationProvider
.
getApplicationContext
())
.
setInitialBitrateEstimate
(
123456789
)
.
build
();
long
initialEstimate
=
bandwidthMeter
.
getBitrateEstimate
();
assertThat
(
initialEstimate
).
isEqualTo
(
123456789
);
}
@Test
public
void
initialBitrateEstimateOverwrite_whileOffline_setsInitialEstimate
()
{
setActiveNetworkInfo
(
networkInfoOffline
);
ExperimentalBandwidthMeter
bandwidthMeter
=
new
ExperimentalBandwidthMeter
.
Builder
(
ApplicationProvider
.
getApplicationContext
())
.
setInitialBitrateEstimate
(
123456789
)
.
build
();
long
initialEstimate
=
bandwidthMeter
.
getBitrateEstimate
();
assertThat
(
initialEstimate
).
isEqualTo
(
123456789
);
}
@Test
public
void
initialBitrateEstimateOverwrite_forWifi_whileConnectedToWifi_setsInitialEstimate
()
{
setActiveNetworkInfo
(
networkInfoWifi
);
ExperimentalBandwidthMeter
bandwidthMeter
=
new
ExperimentalBandwidthMeter
.
Builder
(
ApplicationProvider
.
getApplicationContext
())
.
setInitialBitrateEstimate
(
C
.
NETWORK_TYPE_WIFI
,
123456789
)
.
build
();
long
initialEstimate
=
bandwidthMeter
.
getBitrateEstimate
();
assertThat
(
initialEstimate
).
isEqualTo
(
123456789
);
}
@Test
public
void
initialBitrateEstimateOverwrite_forWifi_whileConnectedToOtherNetwork_doesNotSetInitialEstimate
()
{
setActiveNetworkInfo
(
networkInfo2g
);
ExperimentalBandwidthMeter
bandwidthMeter
=
new
ExperimentalBandwidthMeter
.
Builder
(
ApplicationProvider
.
getApplicationContext
())
.
setInitialBitrateEstimate
(
C
.
NETWORK_TYPE_WIFI
,
123456789
)
.
build
();
long
initialEstimate
=
bandwidthMeter
.
getBitrateEstimate
();
assertThat
(
initialEstimate
).
isNotEqualTo
(
123456789
);
}
@Test
public
void
initialBitrateEstimateOverwrite_forEthernet_whileConnectedToEthernet_setsInitialEstimate
()
{
setActiveNetworkInfo
(
networkInfoEthernet
);
ExperimentalBandwidthMeter
bandwidthMeter
=
new
ExperimentalBandwidthMeter
.
Builder
(
ApplicationProvider
.
getApplicationContext
())
.
setInitialBitrateEstimate
(
C
.
NETWORK_TYPE_ETHERNET
,
123456789
)
.
build
();
long
initialEstimate
=
bandwidthMeter
.
getBitrateEstimate
();
assertThat
(
initialEstimate
).
isEqualTo
(
123456789
);
}
@Test
public
void
initialBitrateEstimateOverwrite_forEthernet_whileConnectedToOtherNetwork_doesNotSetInitialEstimate
()
{
setActiveNetworkInfo
(
networkInfo2g
);
ExperimentalBandwidthMeter
bandwidthMeter
=
new
ExperimentalBandwidthMeter
.
Builder
(
ApplicationProvider
.
getApplicationContext
())
.
setInitialBitrateEstimate
(
C
.
NETWORK_TYPE_WIFI
,
123456789
)
.
build
();
long
initialEstimate
=
bandwidthMeter
.
getBitrateEstimate
();
assertThat
(
initialEstimate
).
isNotEqualTo
(
123456789
);
}
@Test
public
void
initialBitrateEstimateOverwrite_for2G_whileConnectedTo2G_setsInitialEstimate
()
{
setActiveNetworkInfo
(
networkInfo2g
);
ExperimentalBandwidthMeter
bandwidthMeter
=
new
ExperimentalBandwidthMeter
.
Builder
(
ApplicationProvider
.
getApplicationContext
())
.
setInitialBitrateEstimate
(
C
.
NETWORK_TYPE_2G
,
123456789
)
.
build
();
long
initialEstimate
=
bandwidthMeter
.
getBitrateEstimate
();
assertThat
(
initialEstimate
).
isEqualTo
(
123456789
);
}
@Test
public
void
initialBitrateEstimateOverwrite_for2G_whileConnectedToOtherNetwork_doesNotSetInitialEstimate
()
{
setActiveNetworkInfo
(
networkInfoWifi
);
ExperimentalBandwidthMeter
bandwidthMeter
=
new
ExperimentalBandwidthMeter
.
Builder
(
ApplicationProvider
.
getApplicationContext
())
.
setInitialBitrateEstimate
(
C
.
NETWORK_TYPE_2G
,
123456789
)
.
build
();
long
initialEstimate
=
bandwidthMeter
.
getBitrateEstimate
();
assertThat
(
initialEstimate
).
isNotEqualTo
(
123456789
);
}
@Test
public
void
initialBitrateEstimateOverwrite_for3G_whileConnectedTo3G_setsInitialEstimate
()
{
setActiveNetworkInfo
(
networkInfo3g
);
ExperimentalBandwidthMeter
bandwidthMeter
=
new
ExperimentalBandwidthMeter
.
Builder
(
ApplicationProvider
.
getApplicationContext
())
.
setInitialBitrateEstimate
(
C
.
NETWORK_TYPE_3G
,
123456789
)
.
build
();
long
initialEstimate
=
bandwidthMeter
.
getBitrateEstimate
();
assertThat
(
initialEstimate
).
isEqualTo
(
123456789
);
}
@Test
public
void
initialBitrateEstimateOverwrite_for3G_whileConnectedToOtherNetwork_doesNotSetInitialEstimate
()
{
setActiveNetworkInfo
(
networkInfoWifi
);
ExperimentalBandwidthMeter
bandwidthMeter
=
new
ExperimentalBandwidthMeter
.
Builder
(
ApplicationProvider
.
getApplicationContext
())
.
setInitialBitrateEstimate
(
C
.
NETWORK_TYPE_3G
,
123456789
)
.
build
();
long
initialEstimate
=
bandwidthMeter
.
getBitrateEstimate
();
assertThat
(
initialEstimate
).
isNotEqualTo
(
123456789
);
}
@Test
public
void
initialBitrateEstimateOverwrite_for4G_whileConnectedTo4G_setsInitialEstimate
()
{
setActiveNetworkInfo
(
networkInfo4g
);
ExperimentalBandwidthMeter
bandwidthMeter
=
new
ExperimentalBandwidthMeter
.
Builder
(
ApplicationProvider
.
getApplicationContext
())
.
setInitialBitrateEstimate
(
C
.
NETWORK_TYPE_4G
,
123456789
)
.
build
();
long
initialEstimate
=
bandwidthMeter
.
getBitrateEstimate
();
assertThat
(
initialEstimate
).
isEqualTo
(
123456789
);
}
@Test
public
void
initialBitrateEstimateOverwrite_for4G_whileConnectedToOtherNetwork_doesNotSetInitialEstimate
()
{
setActiveNetworkInfo
(
networkInfoWifi
);
ExperimentalBandwidthMeter
bandwidthMeter
=
new
ExperimentalBandwidthMeter
.
Builder
(
ApplicationProvider
.
getApplicationContext
())
.
setInitialBitrateEstimate
(
C
.
NETWORK_TYPE_4G
,
123456789
)
.
build
();
long
initialEstimate
=
bandwidthMeter
.
getBitrateEstimate
();
assertThat
(
initialEstimate
).
isNotEqualTo
(
123456789
);
}
@Test
public
void
initialBitrateEstimateOverwrite_forOffline_whileOffline_setsInitialEstimate
()
{
setActiveNetworkInfo
(
networkInfoOffline
);
ExperimentalBandwidthMeter
bandwidthMeter
=
new
ExperimentalBandwidthMeter
.
Builder
(
ApplicationProvider
.
getApplicationContext
())
.
setInitialBitrateEstimate
(
C
.
NETWORK_TYPE_OFFLINE
,
123456789
)
.
build
();
long
initialEstimate
=
bandwidthMeter
.
getBitrateEstimate
();
assertThat
(
initialEstimate
).
isEqualTo
(
123456789
);
}
@Test
public
void
initialBitrateEstimateOverwrite_forOffline_whileConnectedToNetwork_doesNotSetInitialEstimate
()
{
setActiveNetworkInfo
(
networkInfoWifi
);
ExperimentalBandwidthMeter
bandwidthMeter
=
new
ExperimentalBandwidthMeter
.
Builder
(
ApplicationProvider
.
getApplicationContext
())
.
setInitialBitrateEstimate
(
C
.
NETWORK_TYPE_OFFLINE
,
123456789
)
.
build
();
long
initialEstimate
=
bandwidthMeter
.
getBitrateEstimate
();
assertThat
(
initialEstimate
).
isNotEqualTo
(
123456789
);
}
@Test
public
void
initialBitrateEstimateOverwrite_forCountry_usesDefaultValuesForCountry
()
{
setNetworkCountryIso
(
SLOW_COUNTRY_ISO
);
ExperimentalBandwidthMeter
bandwidthMeterSlow
=
new
ExperimentalBandwidthMeter
.
Builder
(
ApplicationProvider
.
getApplicationContext
()).
build
();
long
initialEstimateSlow
=
bandwidthMeterSlow
.
getBitrateEstimate
();
setNetworkCountryIso
(
FAST_COUNTRY_ISO
);
ExperimentalBandwidthMeter
bandwidthMeterFastWithSlowOverwrite
=
new
ExperimentalBandwidthMeter
.
Builder
(
ApplicationProvider
.
getApplicationContext
())
.
setInitialBitrateEstimate
(
SLOW_COUNTRY_ISO
)
.
build
();
long
initialEstimateFastWithSlowOverwrite
=
bandwidthMeterFastWithSlowOverwrite
.
getBitrateEstimate
();
assertThat
(
initialEstimateFastWithSlowOverwrite
).
isEqualTo
(
initialEstimateSlow
);
}
@Test
public
void
networkTypeOverride_updatesBitrateEstimate
()
{
setActiveNetworkInfo
(
networkInfoEthernet
);
ExperimentalBandwidthMeter
bandwidthMeter
=
new
ExperimentalBandwidthMeter
.
Builder
(
ApplicationProvider
.
getApplicationContext
()).
build
();
long
initialEstimateEthernet
=
bandwidthMeter
.
getBitrateEstimate
();
bandwidthMeter
.
setNetworkTypeOverride
(
C
.
NETWORK_TYPE_2G
);
long
initialEstimate2g
=
bandwidthMeter
.
getBitrateEstimate
();
assertThat
(
initialEstimateEthernet
).
isGreaterThan
(
initialEstimate2g
);
}
@Test
public
void
networkTypeOverride_doesFullReset
()
{
// Simulate transfers for an ethernet connection.
setActiveNetworkInfo
(
networkInfoEthernet
);
FakeClock
clock
=
new
FakeClock
(
/* initialTimeMs= */
0
);
ExperimentalBandwidthMeter
bandwidthMeter
=
new
ExperimentalBandwidthMeter
.
Builder
(
ApplicationProvider
.
getApplicationContext
())
.
setClock
(
clock
)
.
build
();
long
[]
bitrateEstimatesWithNewInstance
=
simulateTransfers
(
bandwidthMeter
,
clock
);
// Create a new instance and seed with some transfers.
setActiveNetworkInfo
(
networkInfo2g
);
bandwidthMeter
=
new
ExperimentalBandwidthMeter
.
Builder
(
ApplicationProvider
.
getApplicationContext
())
.
setClock
(
clock
)
.
build
();
simulateTransfers
(
bandwidthMeter
,
clock
);
// Override the network type to ethernet and simulate transfers again.
bandwidthMeter
.
setNetworkTypeOverride
(
C
.
NETWORK_TYPE_ETHERNET
);
long
[]
bitrateEstimatesAfterReset
=
simulateTransfers
(
bandwidthMeter
,
clock
);
// If overriding the network type fully reset the bandwidth meter, we expect the bitrate
// estimates generated during simulation to be the same.
assertThat
(
bitrateEstimatesAfterReset
).
isEqualTo
(
bitrateEstimatesWithNewInstance
);
}
@Test
public
void
defaultInitialBitrateEstimate_withoutContext_isReasonable
()
{
ExperimentalBandwidthMeter
bandwidthMeterWithBuilder
=
new
ExperimentalBandwidthMeter
.
Builder
(
/* context= */
null
).
build
();
long
initialEstimateWithBuilder
=
bandwidthMeterWithBuilder
.
getBitrateEstimate
();
assertThat
(
initialEstimateWithBuilder
).
isGreaterThan
(
100_000L
);
assertThat
(
initialEstimateWithBuilder
).
isLessThan
(
50_000_000L
);
}
private
void
setActiveNetworkInfo
(
NetworkInfo
networkInfo
)
{
Shadows
.
shadowOf
(
connectivityManager
).
setActiveNetworkInfo
(
networkInfo
);
}
private
void
setNetworkCountryIso
(
String
countryIso
)
{
Shadows
.
shadowOf
(
telephonyManager
).
setNetworkCountryIso
(
countryIso
);
}
private
static
long
[]
simulateTransfers
(
ExperimentalBandwidthMeter
bandwidthMeter
,
FakeClock
clock
)
{
long
[]
bitrateEstimates
=
new
long
[
SIMULATED_TRANSFER_COUNT
];
Random
random
=
new
Random
(
/* seed= */
0
);
DataSource
dataSource
=
new
FakeDataSource
();
DataSpec
dataSpec
=
new
DataSpec
(
Uri
.
parse
(
"https://test.com"
));
for
(
int
i
=
0
;
i
<
SIMULATED_TRANSFER_COUNT
;
i
++)
{
bandwidthMeter
.
onTransferStart
(
dataSource
,
dataSpec
,
/* isNetwork= */
true
);
clock
.
advanceTime
(
random
.
nextInt
(
/* bound= */
5000
));
bandwidthMeter
.
onBytesTransferred
(
dataSource
,
dataSpec
,
/* isNetwork= */
true
,
/* bytes= */
random
.
nextInt
(
5
*
1024
*
1024
));
bandwidthMeter
.
onTransferEnd
(
dataSource
,
dataSpec
,
/* isNetwork= */
true
);
bitrateEstimates
[
i
]
=
bandwidthMeter
.
getBitrateEstimate
();
}
return
bitrateEstimates
;
}
}
library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/CacheDataSourceTest.java
View file @
675b81e5
...
...
@@ -364,7 +364,6 @@ public final class CacheDataSourceTest {
new
CacheWriter
(
new
CacheDataSource
(
cache
,
upstream2
),
unboundedDataSpec
,
/* allowShortContent= */
false
,
/* temporaryBuffer= */
null
,
/* progressListener= */
null
);
cacheWriter
.
cache
();
...
...
@@ -414,7 +413,6 @@ public final class CacheDataSourceTest {
new
CacheWriter
(
new
CacheDataSource
(
cache
,
upstream2
),
unboundedDataSpec
,
/* allowShortContent= */
false
,
/* temporaryBuffer= */
null
,
/* progressListener= */
null
);
cacheWriter
.
cache
();
...
...
@@ -439,7 +437,6 @@ public final class CacheDataSourceTest {
new
CacheWriter
(
new
CacheDataSource
(
cache
,
upstream
),
dataSpec
,
/* allowShortContent= */
false
,
/* temporaryBuffer= */
null
,
/* progressListener= */
null
);
cacheWriter
.
cache
();
...
...
@@ -476,7 +473,6 @@ public final class CacheDataSourceTest {
new
CacheWriter
(
new
CacheDataSource
(
cache
,
upstream
),
dataSpec
,
/* allowShortContent= */
false
,
/* temporaryBuffer= */
null
,
/* progressListener= */
null
);
cacheWriter
.
cache
();
...
...
library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/CacheWriterTest.java
View file @
675b81e5
...
...
@@ -30,7 +30,6 @@ import com.google.android.exoplayer2.testutil.TestUtil;
import
com.google.android.exoplayer2.upstream.DataSpec
;
import
com.google.android.exoplayer2.upstream.FileDataSource
;
import
com.google.android.exoplayer2.util.Util
;
import
java.io.EOFException
;
import
java.io.File
;
import
java.io.IOException
;
import
java.util.concurrent.atomic.AtomicBoolean
;
...
...
@@ -72,7 +71,6 @@ public final class CacheWriterTest {
new
CacheWriter
(
new
CacheDataSource
(
cache
,
dataSource
),
new
DataSpec
(
Uri
.
parse
(
"test_data"
)),
/* allowShortContent= */
false
,
/* temporaryBuffer= */
null
,
counters
);
cacheWriter
.
cache
();
...
...
@@ -94,7 +92,6 @@ public final class CacheWriterTest {
new
CacheWriter
(
new
CacheDataSource
(
cache
,
dataSource
),
dataSpec
,
/* allowShortContent= */
false
,
/* temporaryBuffer= */
null
,
counters
);
cacheWriter
.
cache
();
...
...
@@ -106,7 +103,6 @@ public final class CacheWriterTest {
new
CacheWriter
(
new
CacheDataSource
(
cache
,
dataSource
),
new
DataSpec
(
testUri
),
/* allowShortContent= */
false
,
/* temporaryBuffer= */
null
,
counters
);
cacheWriter
.
cache
();
...
...
@@ -129,7 +125,6 @@ public final class CacheWriterTest {
new
CacheWriter
(
new
CacheDataSource
(
cache
,
dataSource
),
dataSpec
,
/* allowShortContent= */
false
,
/* temporaryBuffer= */
null
,
counters
);
cacheWriter
.
cache
();
...
...
@@ -153,7 +148,6 @@ public final class CacheWriterTest {
new
CacheWriter
(
new
CacheDataSource
(
cache
,
dataSource
),
dataSpec
,
/* allowShortContent= */
false
,
/* temporaryBuffer= */
null
,
counters
);
cacheWriter
.
cache
();
...
...
@@ -165,7 +159,6 @@ public final class CacheWriterTest {
new
CacheWriter
(
new
CacheDataSource
(
cache
,
dataSource
),
new
DataSpec
(
testUri
),
/* allowShortContent= */
false
,
/* temporaryBuffer= */
null
,
counters
);
cacheWriter
.
cache
();
...
...
@@ -187,7 +180,6 @@ public final class CacheWriterTest {
new
CacheWriter
(
new
CacheDataSource
(
cache
,
dataSource
),
dataSpec
,
/* allowShortContent= */
true
,
/* temporaryBuffer= */
null
,
counters
);
cacheWriter
.
cache
();
...
...
@@ -197,24 +189,6 @@ public final class CacheWriterTest {
}
@Test
public
void
cacheThrowEOFException
()
throws
Exception
{
FakeDataSet
fakeDataSet
=
new
FakeDataSet
().
setRandomData
(
"test_data"
,
100
);
FakeDataSource
dataSource
=
new
FakeDataSource
(
fakeDataSet
);
Uri
testUri
=
Uri
.
parse
(
"test_data"
);
DataSpec
dataSpec
=
new
DataSpec
(
testUri
,
/* position= */
0
,
/* length= */
1000
);
CacheWriter
cacheWriter
=
new
CacheWriter
(
new
CacheDataSource
(
cache
,
dataSource
),
dataSpec
,
/* allowShortContent= */
false
,
/* temporaryBuffer= */
null
,
/* progressListener= */
null
);
assertThrows
(
EOFException
.
class
,
cacheWriter:
:
cache
);
}
@Test
public
void
cache_afterFailureOnClose_succeeds
()
throws
Exception
{
FakeDataSet
fakeDataSet
=
new
FakeDataSet
().
setRandomData
(
"test_data"
,
100
);
FakeDataSource
upstreamDataSource
=
new
FakeDataSource
(
fakeDataSet
);
...
...
@@ -237,7 +211,6 @@ public final class CacheWriterTest {
new
CacheWriter
(
cacheDataSource
,
new
DataSpec
(
Uri
.
parse
(
"test_data"
)),
/* allowShortContent= */
false
,
/* temporaryBuffer= */
null
,
counters
);
...
...
@@ -276,7 +249,6 @@ public final class CacheWriterTest {
new
CacheWriter
(
new
CacheDataSource
(
cache
,
dataSource
),
new
DataSpec
(
Uri
.
parse
(
"test_data"
)),
/* allowShortContent= */
false
,
/* temporaryBuffer= */
null
,
counters
);
cacheWriter
.
cache
();
...
...
testutils/src/main/java/com/google/android/exoplayer2/testutil/DataSourceContractTest.java
View file @
675b81e5
...
...
@@ -232,24 +232,27 @@ public abstract class DataSourceContractTest {
DataSpec
dataSpec
=
new
DataSpec
.
Builder
().
setUri
(
resource
.
getUri
()).
setPosition
(
resourceLength
).
build
();
try
{
long
length
=
dataSource
.
open
(
dataSpec
);
// The DataSource.open() contract requires the returned length to equal the length in the
// DataSpec if set. This is true even though the DataSource implementation may know that
// fewer bytes will be read in this case.
if
(
length
!=
C
.
LENGTH_UNSET
)
{
assertThat
(
length
).
isEqualTo
(
0
);
}
try
{
byte
[]
data
=
unboundedReadsAreIndefinite
()
?
Util
.
EMPTY_BYTE_ARRAY
:
Util
.
readToEnd
(
dataSource
);
assertThat
(
data
).
isEmpty
();
long
length
=
dataSource
.
open
(
dataSpec
);
// The DataSource.open() contract requires the returned length to equal the length in the
// DataSpec if set. This is true even though the DataSource implementation may know that
// fewer bytes will be read in this case.
if
(
length
!=
C
.
LENGTH_UNSET
)
{
assertThat
(
length
).
isEqualTo
(
0
);
}
try
{
byte
[]
data
=
unboundedReadsAreIndefinite
()
?
Util
.
EMPTY_BYTE_ARRAY
:
Util
.
readToEnd
(
dataSource
);
assertThat
(
data
).
isEmpty
();
}
catch
(
IOException
e
)
{
// TODO: Remove this catch once the one below is removed.
throw
new
RuntimeException
(
e
);
}
}
catch
(
IOException
e
)
{
// TODO: Remove this catch and require that implementations do not throw.
assertThat
(
DataSourceException
.
isCausedByPositionOutOfRange
(
e
)).
isTrue
();
}
}
catch
(
IOException
e
)
{
// TODO: Remove this catch and require that implementations do not throw.
assertThat
(
DataSourceException
.
isCausedByPositionOutOfRange
(
e
)).
isTrue
();
}
finally
{
dataSource
.
close
();
}
...
...
@@ -275,22 +278,25 @@ public abstract class DataSourceContractTest {
.
setLength
(
1
)
.
build
();
try
{
long
length
=
dataSource
.
open
(
dataSpec
);
// The DataSource.open() contract requires the returned length to equal the length in the
// DataSpec if set. This is true even though the DataSource implementation may know that
// fewer bytes will be read in this case.
assertThat
(
length
).
isEqualTo
(
1
);
try
{
byte
[]
data
=
unboundedReadsAreIndefinite
()
?
Util
.
EMPTY_BYTE_ARRAY
:
Util
.
readToEnd
(
dataSource
);
assertThat
(
data
).
isEmpty
();
long
length
=
dataSource
.
open
(
dataSpec
);
// The DataSource.open() contract requires the returned length to equal the length in the
// DataSpec if set. This is true even though the DataSource implementation may know that
// fewer bytes will be read in this case.
assertThat
(
length
).
isEqualTo
(
1
);
try
{
byte
[]
data
=
unboundedReadsAreIndefinite
()
?
Util
.
EMPTY_BYTE_ARRAY
:
Util
.
readToEnd
(
dataSource
);
assertThat
(
data
).
isEmpty
();
}
catch
(
IOException
e
)
{
// TODO: Remove this catch once the one below is removed.
throw
new
RuntimeException
(
e
);
}
}
catch
(
IOException
e
)
{
// TODO: Remove this catch and require that implementations do not throw.
assertThat
(
DataSourceException
.
isCausedByPositionOutOfRange
(
e
)).
isTrue
();
}
}
catch
(
IOException
e
)
{
// TODO: Remove this catch and require that implementations do not throw.
assertThat
(
DataSourceException
.
isCausedByPositionOutOfRange
(
e
)).
isTrue
();
}
finally
{
dataSource
.
close
();
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment