1*30877f79SAndroid Build Coastguard Worker---
2*30877f79SAndroid Build Coastguard Workertitle: Downloading media
3*30877f79SAndroid Build Coastguard Worker---
4*30877f79SAndroid Build Coastguard Worker
5*30877f79SAndroid Build Coastguard WorkerExoPlayer provides functionality to download media for offline playback. In most
6*30877f79SAndroid Build Coastguard Workeruse cases it's desirable for downloads to continue even when your app is in the
7*30877f79SAndroid Build Coastguard Workerbackground. For these use cases your app should subclass `DownloadService`, and
8*30877f79SAndroid Build Coastguard Workersend commands to the service to add, remove and control the downloads. The
9*30877f79SAndroid Build Coastguard Workerdiagram below shows the main classes that are involved.
10*30877f79SAndroid Build Coastguard Worker
11*30877f79SAndroid Build Coastguard Worker{% include figure.html url="/images/downloading.svg" index="1" caption="Classes
12*30877f79SAndroid Build Coastguard Workerfor downloading media. The arrow directions indicate the flow of data."
13*30877f79SAndroid Build Coastguard Workerwidth="85%" %}
14*30877f79SAndroid Build Coastguard Worker
15*30877f79SAndroid Build Coastguard Worker* `DownloadService`: Wraps a `DownloadManager` and forwards commands to it. The
16*30877f79SAndroid Build Coastguard Worker  service allows the `DownloadManager` to keep running even when the app is in
17*30877f79SAndroid Build Coastguard Worker  the background.
18*30877f79SAndroid Build Coastguard Worker* `DownloadManager`: Manages multiple downloads, loading (and storing) their
19*30877f79SAndroid Build Coastguard Worker  states from (and to) a `DownloadIndex`, starting and stopping downloads based
20*30877f79SAndroid Build Coastguard Worker  on requirements such as network connectivity, and so on. To download the
21*30877f79SAndroid Build Coastguard Worker  content, the manager will typically read the data being downloaded from a
22*30877f79SAndroid Build Coastguard Worker  `HttpDataSource`, and write it into a `Cache`.
23*30877f79SAndroid Build Coastguard Worker* `DownloadIndex`: Persists the states of the downloads.
24*30877f79SAndroid Build Coastguard Worker
25*30877f79SAndroid Build Coastguard Worker## Creating a DownloadService ##
26*30877f79SAndroid Build Coastguard Worker
27*30877f79SAndroid Build Coastguard WorkerTo create a `DownloadService`, you need to subclass it and implement its
28*30877f79SAndroid Build Coastguard Workerabstract methods:
29*30877f79SAndroid Build Coastguard Worker
30*30877f79SAndroid Build Coastguard Worker* `getDownloadManager()`: Returns the `DownloadManager` to be used.
31*30877f79SAndroid Build Coastguard Worker* `getScheduler()`: Returns an optional `Scheduler`, which can restart the
32*30877f79SAndroid Build Coastguard Worker  service when requirements needed for pending downloads to progress are met.
33*30877f79SAndroid Build Coastguard Worker  ExoPlayer provides these implementations:
34*30877f79SAndroid Build Coastguard Worker  * `PlatformScheduler`, which uses [JobScheduler][] (Minimum API is 21). See
35*30877f79SAndroid Build Coastguard Worker    the [PlatformScheduler][] javadocs for app permission requirements.
36*30877f79SAndroid Build Coastguard Worker  * `WorkManagerScheduler`, which uses [WorkManager][].
37*30877f79SAndroid Build Coastguard Worker* `getForegroundNotification()`: Returns a notification to be displayed when the
38*30877f79SAndroid Build Coastguard Worker  service is running in the foreground. You can use
39*30877f79SAndroid Build Coastguard Worker  `DownloadNotificationHelper.buildProgressNotification` to create a
40*30877f79SAndroid Build Coastguard Worker  notification in default style.
41*30877f79SAndroid Build Coastguard Worker
42*30877f79SAndroid Build Coastguard WorkerFinally, you need to define the service in your `AndroidManifest.xml` file:
43*30877f79SAndroid Build Coastguard Worker
44*30877f79SAndroid Build Coastguard Worker~~~
45*30877f79SAndroid Build Coastguard Worker<service android:name="com.myapp.MyDownloadService"
46*30877f79SAndroid Build Coastguard Worker    android:exported="false">
47*30877f79SAndroid Build Coastguard Worker  <!-- This is needed for Scheduler -->
48*30877f79SAndroid Build Coastguard Worker  <intent-filter>
49*30877f79SAndroid Build Coastguard Worker    <action android:name="com.google.android.exoplayer.downloadService.action.RESTART"/>
50*30877f79SAndroid Build Coastguard Worker    <category android:name="android.intent.category.DEFAULT"/>
51*30877f79SAndroid Build Coastguard Worker  </intent-filter>
52*30877f79SAndroid Build Coastguard Worker</service>
53*30877f79SAndroid Build Coastguard Worker~~~
54*30877f79SAndroid Build Coastguard Worker{: .language-xml}
55*30877f79SAndroid Build Coastguard Worker
56*30877f79SAndroid Build Coastguard WorkerSee [`DemoDownloadService`][] and [`AndroidManifest.xml`][] in the ExoPlayer
57*30877f79SAndroid Build Coastguard Workerdemo app for a concrete example.
58*30877f79SAndroid Build Coastguard Worker
59*30877f79SAndroid Build Coastguard Worker## Creating a DownloadManager ##
60*30877f79SAndroid Build Coastguard Worker
61*30877f79SAndroid Build Coastguard WorkerThe following code snippet demonstrates how to instantiate a `DownloadManager`,
62*30877f79SAndroid Build Coastguard Workerwhich can be returned by `getDownloadManager()` in your `DownloadService`:
63*30877f79SAndroid Build Coastguard Worker
64*30877f79SAndroid Build Coastguard Worker~~~
65*30877f79SAndroid Build Coastguard Worker// Note: This should be a singleton in your app.
66*30877f79SAndroid Build Coastguard WorkerdatabaseProvider = new StandaloneDatabaseProvider(context);
67*30877f79SAndroid Build Coastguard Worker
68*30877f79SAndroid Build Coastguard Worker// A download cache should not evict media, so should use a NoopCacheEvictor.
69*30877f79SAndroid Build Coastguard WorkerdownloadCache = new SimpleCache(
70*30877f79SAndroid Build Coastguard Worker    downloadDirectory,
71*30877f79SAndroid Build Coastguard Worker    new NoOpCacheEvictor(),
72*30877f79SAndroid Build Coastguard Worker    databaseProvider);
73*30877f79SAndroid Build Coastguard Worker
74*30877f79SAndroid Build Coastguard Worker// Create a factory for reading the data from the network.
75*30877f79SAndroid Build Coastguard WorkerdataSourceFactory = new DefaultHttpDataSource.Factory();
76*30877f79SAndroid Build Coastguard Worker
77*30877f79SAndroid Build Coastguard Worker// Choose an executor for downloading data. Using Runnable::run will cause each download task to
78*30877f79SAndroid Build Coastguard Worker// download data on its own thread. Passing an executor that uses multiple threads will speed up
79*30877f79SAndroid Build Coastguard Worker// download tasks that can be split into smaller parts for parallel execution. Applications that
80*30877f79SAndroid Build Coastguard Worker// already have an executor for background downloads may wish to reuse their existing executor.
81*30877f79SAndroid Build Coastguard WorkerExecutor downloadExecutor = Runnable::run;
82*30877f79SAndroid Build Coastguard Worker
83*30877f79SAndroid Build Coastguard Worker// Create the download manager.
84*30877f79SAndroid Build Coastguard WorkerdownloadManager = new DownloadManager(
85*30877f79SAndroid Build Coastguard Worker    context,
86*30877f79SAndroid Build Coastguard Worker    databaseProvider,
87*30877f79SAndroid Build Coastguard Worker    downloadCache,
88*30877f79SAndroid Build Coastguard Worker    dataSourceFactory,
89*30877f79SAndroid Build Coastguard Worker    downloadExecutor);
90*30877f79SAndroid Build Coastguard Worker
91*30877f79SAndroid Build Coastguard Worker// Optionally, setters can be called to configure the download manager.
92*30877f79SAndroid Build Coastguard WorkerdownloadManager.setRequirements(requirements);
93*30877f79SAndroid Build Coastguard WorkerdownloadManager.setMaxParallelDownloads(3);
94*30877f79SAndroid Build Coastguard Worker~~~
95*30877f79SAndroid Build Coastguard Worker{: .language-java}
96*30877f79SAndroid Build Coastguard Worker
97*30877f79SAndroid Build Coastguard WorkerSee [`DemoUtil`][] in the demo app for a concrete example.
98*30877f79SAndroid Build Coastguard Worker
99*30877f79SAndroid Build Coastguard WorkerThe example in the demo app also imports download state from legacy `ActionFile`
100*30877f79SAndroid Build Coastguard Workerinstances. This is only necessary if your app used `ActionFile` prior to
101*30877f79SAndroid Build Coastguard WorkerExoPlayer 2.10.0.
102*30877f79SAndroid Build Coastguard Worker{:.info}
103*30877f79SAndroid Build Coastguard Worker
104*30877f79SAndroid Build Coastguard Worker## Adding a download ##
105*30877f79SAndroid Build Coastguard Worker
106*30877f79SAndroid Build Coastguard WorkerTo add a download you need to create a `DownloadRequest` and send it to your
107*30877f79SAndroid Build Coastguard Worker`DownloadService`. For adaptive streams `DownloadHelper` can be used to help
108*30877f79SAndroid Build Coastguard Workerbuild a `DownloadRequest`, as described [further down this page][]. The example
109*30877f79SAndroid Build Coastguard Workerbelow shows how to create a download request:
110*30877f79SAndroid Build Coastguard Worker
111*30877f79SAndroid Build Coastguard Worker~~~
112*30877f79SAndroid Build Coastguard WorkerDownloadRequest downloadRequest =
113*30877f79SAndroid Build Coastguard Worker    new DownloadRequest.Builder(contentId, contentUri).build();
114*30877f79SAndroid Build Coastguard Worker~~~
115*30877f79SAndroid Build Coastguard Worker{: .language-java}
116*30877f79SAndroid Build Coastguard Worker
117*30877f79SAndroid Build Coastguard Workerwhere `contentId` is a unique identifier for the content. In simple cases, the
118*30877f79SAndroid Build Coastguard Worker`contentUri` can often be used as the `contentId`, however apps are free to use
119*30877f79SAndroid Build Coastguard Workerwhatever ID scheme best suits their use case. `DownloadRequest.Builder` also has
120*30877f79SAndroid Build Coastguard Workersome optional setters. For example, `setKeySetId` and `setData` can be used to
121*30877f79SAndroid Build Coastguard Workerset DRM and custom data that the app wishes to associate with the download,
122*30877f79SAndroid Build Coastguard Workerrespectively. The content's MIME type can also be specified using `setMimeType`,
123*30877f79SAndroid Build Coastguard Workeras a hint for cases where the content type cannot be inferred from `contentUri`.
124*30877f79SAndroid Build Coastguard Worker
125*30877f79SAndroid Build Coastguard WorkerOnce created, the request can be sent to the `DownloadService` to add the
126*30877f79SAndroid Build Coastguard Workerdownload:
127*30877f79SAndroid Build Coastguard Worker
128*30877f79SAndroid Build Coastguard Worker~~~
129*30877f79SAndroid Build Coastguard WorkerDownloadService.sendAddDownload(
130*30877f79SAndroid Build Coastguard Worker    context,
131*30877f79SAndroid Build Coastguard Worker    MyDownloadService.class,
132*30877f79SAndroid Build Coastguard Worker    downloadRequest,
133*30877f79SAndroid Build Coastguard Worker    /* foreground= */ false)
134*30877f79SAndroid Build Coastguard Worker~~~
135*30877f79SAndroid Build Coastguard Worker{: .language-java}
136*30877f79SAndroid Build Coastguard Worker
137*30877f79SAndroid Build Coastguard Workerwhere `MyDownloadService` is the app's `DownloadService` subclass, and the
138*30877f79SAndroid Build Coastguard Worker`foreground` parameter controls whether the service will be started in the
139*30877f79SAndroid Build Coastguard Workerforeground. If your app is already in the foreground then the `foreground`
140*30877f79SAndroid Build Coastguard Workerparameter should normally be set to `false`, since the `DownloadService` will
141*30877f79SAndroid Build Coastguard Workerput itself in the foreground if it determines that it has work to do.
142*30877f79SAndroid Build Coastguard Worker
143*30877f79SAndroid Build Coastguard Worker## Removing downloads ##
144*30877f79SAndroid Build Coastguard Worker
145*30877f79SAndroid Build Coastguard WorkerA download can be removed by sending a remove command to the `DownloadService`,
146*30877f79SAndroid Build Coastguard Workerwhere `contentId` identifies the download to be removed:
147*30877f79SAndroid Build Coastguard Worker
148*30877f79SAndroid Build Coastguard Worker~~~
149*30877f79SAndroid Build Coastguard WorkerDownloadService.sendRemoveDownload(
150*30877f79SAndroid Build Coastguard Worker    context,
151*30877f79SAndroid Build Coastguard Worker    MyDownloadService.class,
152*30877f79SAndroid Build Coastguard Worker    contentId,
153*30877f79SAndroid Build Coastguard Worker    /* foreground= */ false)
154*30877f79SAndroid Build Coastguard Worker~~~
155*30877f79SAndroid Build Coastguard Worker{: .language-java}
156*30877f79SAndroid Build Coastguard Worker
157*30877f79SAndroid Build Coastguard WorkerYou can also remove all downloaded data with
158*30877f79SAndroid Build Coastguard Worker`DownloadService.sendRemoveAllDownloads`.
159*30877f79SAndroid Build Coastguard Worker
160*30877f79SAndroid Build Coastguard Worker## Starting and stopping downloads ##
161*30877f79SAndroid Build Coastguard Worker
162*30877f79SAndroid Build Coastguard WorkerA download will only progress if four conditions are met:
163*30877f79SAndroid Build Coastguard Worker
164*30877f79SAndroid Build Coastguard Worker* The download doesn't have a stop reason.
165*30877f79SAndroid Build Coastguard Worker* Downloads aren't paused.
166*30877f79SAndroid Build Coastguard Worker* The requirements for downloads to progress are met. Requirements can specify
167*30877f79SAndroid Build Coastguard Worker  constraints on the allowed network types, as well as whether the device should
168*30877f79SAndroid Build Coastguard Worker  be idle or connected to a charger.
169*30877f79SAndroid Build Coastguard Worker* The maximum number of parallel downloads is not exceeded.
170*30877f79SAndroid Build Coastguard Worker
171*30877f79SAndroid Build Coastguard WorkerAll of these conditions can be controlled by sending commands to your
172*30877f79SAndroid Build Coastguard Worker`DownloadService`.
173*30877f79SAndroid Build Coastguard Worker
174*30877f79SAndroid Build Coastguard Worker#### Setting and clearing download stop reasons ####
175*30877f79SAndroid Build Coastguard Worker
176*30877f79SAndroid Build Coastguard WorkerIt's possible to set a reason for one or all downloads being stopped:
177*30877f79SAndroid Build Coastguard Worker
178*30877f79SAndroid Build Coastguard Worker~~~
179*30877f79SAndroid Build Coastguard Worker// Set the stop reason for a single download.
180*30877f79SAndroid Build Coastguard WorkerDownloadService.sendSetStopReason(
181*30877f79SAndroid Build Coastguard Worker    context,
182*30877f79SAndroid Build Coastguard Worker    MyDownloadService.class,
183*30877f79SAndroid Build Coastguard Worker    contentId,
184*30877f79SAndroid Build Coastguard Worker    stopReason,
185*30877f79SAndroid Build Coastguard Worker    /* foreground= */ false);
186*30877f79SAndroid Build Coastguard Worker
187*30877f79SAndroid Build Coastguard Worker// Clear the stop reason for a single download.
188*30877f79SAndroid Build Coastguard WorkerDownloadService.sendSetStopReason(
189*30877f79SAndroid Build Coastguard Worker    context,
190*30877f79SAndroid Build Coastguard Worker    MyDownloadService.class,
191*30877f79SAndroid Build Coastguard Worker    contentId,
192*30877f79SAndroid Build Coastguard Worker    Download.STOP_REASON_NONE,
193*30877f79SAndroid Build Coastguard Worker    /* foreground= */ false);
194*30877f79SAndroid Build Coastguard Worker~~~
195*30877f79SAndroid Build Coastguard Worker{: .language-java}
196*30877f79SAndroid Build Coastguard Worker
197*30877f79SAndroid Build Coastguard Workerwhere `stopReason` can be any non-zero value (`Download.STOP_REASON_NONE = 0` is
198*30877f79SAndroid Build Coastguard Workera special value meaning that the download is not stopped). Apps that have
199*30877f79SAndroid Build Coastguard Workermultiple reasons for stopping downloads can use different values to keep track
200*30877f79SAndroid Build Coastguard Workerof why each download is stopped. Setting and clearing the stop reason for all
201*30877f79SAndroid Build Coastguard Workerdownloads works the same way as setting and clearing the stop reason for a
202*30877f79SAndroid Build Coastguard Workersingle download, except that `contentId` should be set to `null`.
203*30877f79SAndroid Build Coastguard Worker
204*30877f79SAndroid Build Coastguard WorkerSetting a stop reason does not remove a download. The partial download will be
205*30877f79SAndroid Build Coastguard Workerretained, and clearing the stop reason will cause the download to continue.
206*30877f79SAndroid Build Coastguard Worker{:.info}
207*30877f79SAndroid Build Coastguard Worker
208*30877f79SAndroid Build Coastguard WorkerWhen a download has a non-zero stop reason, it will be in the
209*30877f79SAndroid Build Coastguard Worker`Download.STATE_STOPPED` state. Stop reasons are persisted in the
210*30877f79SAndroid Build Coastguard Worker`DownloadIndex`, and so are retained if the application process is killed and
211*30877f79SAndroid Build Coastguard Workerlater restarted.
212*30877f79SAndroid Build Coastguard Worker
213*30877f79SAndroid Build Coastguard Worker#### Pausing and resuming all downloads ####
214*30877f79SAndroid Build Coastguard Worker
215*30877f79SAndroid Build Coastguard WorkerAll downloads can be paused and resumed as follows:
216*30877f79SAndroid Build Coastguard Worker
217*30877f79SAndroid Build Coastguard Worker~~~
218*30877f79SAndroid Build Coastguard Worker// Pause all downloads.
219*30877f79SAndroid Build Coastguard WorkerDownloadService.sendPauseDownloads(
220*30877f79SAndroid Build Coastguard Worker    context,
221*30877f79SAndroid Build Coastguard Worker    MyDownloadService.class,
222*30877f79SAndroid Build Coastguard Worker    /* foreground= */ false);
223*30877f79SAndroid Build Coastguard Worker
224*30877f79SAndroid Build Coastguard Worker// Resume all downloads.
225*30877f79SAndroid Build Coastguard WorkerDownloadService.sendResumeDownloads(
226*30877f79SAndroid Build Coastguard Worker    context,
227*30877f79SAndroid Build Coastguard Worker    MyDownloadService.class,
228*30877f79SAndroid Build Coastguard Worker    /* foreground= */ false);
229*30877f79SAndroid Build Coastguard Worker~~~
230*30877f79SAndroid Build Coastguard Worker{: .language-java}
231*30877f79SAndroid Build Coastguard Worker
232*30877f79SAndroid Build Coastguard WorkerWhen downloads are paused, they will be in the `Download.STATE_QUEUED` state.
233*30877f79SAndroid Build Coastguard WorkerUnlike [setting stop reasons][], this approach does not persist any state
234*30877f79SAndroid Build Coastguard Workerchanges. It only affects the runtime state of the `DownloadManager`.
235*30877f79SAndroid Build Coastguard Worker
236*30877f79SAndroid Build Coastguard Worker#### Setting the requirements for downloads to progress ####
237*30877f79SAndroid Build Coastguard Worker
238*30877f79SAndroid Build Coastguard Worker[`Requirements`][] can be used to specify constraints that must be met for
239*30877f79SAndroid Build Coastguard Workerdownloads to proceed. The requirements can be set by calling
240*30877f79SAndroid Build Coastguard Worker`DownloadManager.setRequirements()` when creating the `DownloadManager`, as in
241*30877f79SAndroid Build Coastguard Workerthe example [above][]. They can also be changed dynamically by sending a command
242*30877f79SAndroid Build Coastguard Workerto the `DownloadService`:
243*30877f79SAndroid Build Coastguard Worker
244*30877f79SAndroid Build Coastguard Worker~~~
245*30877f79SAndroid Build Coastguard Worker// Set the download requirements.
246*30877f79SAndroid Build Coastguard WorkerDownloadService.sendSetRequirements(
247*30877f79SAndroid Build Coastguard Worker    context,
248*30877f79SAndroid Build Coastguard Worker    MyDownloadService.class,
249*30877f79SAndroid Build Coastguard Worker    requirements,
250*30877f79SAndroid Build Coastguard Worker    /* foreground= */ false);
251*30877f79SAndroid Build Coastguard Worker~~~
252*30877f79SAndroid Build Coastguard Worker{: .language-java}
253*30877f79SAndroid Build Coastguard Worker
254*30877f79SAndroid Build Coastguard WorkerWhen a download cannot proceed because the requirements are not met, it
255*30877f79SAndroid Build Coastguard Workerwill be in the `Download.STATE_QUEUED` state. You can query the not met
256*30877f79SAndroid Build Coastguard Workerrequirements with `DownloadManager.getNotMetRequirements()`.
257*30877f79SAndroid Build Coastguard Worker
258*30877f79SAndroid Build Coastguard Worker#### Setting the maximum number of parallel downloads ####
259*30877f79SAndroid Build Coastguard Worker
260*30877f79SAndroid Build Coastguard WorkerThe maximum number of parallel downloads can be set by calling
261*30877f79SAndroid Build Coastguard Worker`DownloadManager.setMaxParallelDownloads()`. This would normally be done when
262*30877f79SAndroid Build Coastguard Workercreating the `DownloadManager`, as in the example [above][].
263*30877f79SAndroid Build Coastguard Worker
264*30877f79SAndroid Build Coastguard WorkerWhen a download cannot proceed because the maximum number of parallel downloads
265*30877f79SAndroid Build Coastguard Workerare already in progress, it will be in the `Download.STATE_QUEUED` state.
266*30877f79SAndroid Build Coastguard Worker
267*30877f79SAndroid Build Coastguard Worker## Querying downloads ##
268*30877f79SAndroid Build Coastguard Worker
269*30877f79SAndroid Build Coastguard WorkerThe `DownloadIndex` of a `DownloadManager` can be queried for the state of all
270*30877f79SAndroid Build Coastguard Workerdownloads, including those that have completed or failed. The `DownloadIndex`
271*30877f79SAndroid Build Coastguard Workercan be obtained by calling `DownloadManager.getDownloadIndex()`. A cursor that
272*30877f79SAndroid Build Coastguard Workeriterates over all downloads can then be obtained by calling
273*30877f79SAndroid Build Coastguard Worker`DownloadIndex.getDownloads()`. Alternatively, the state of a single download
274*30877f79SAndroid Build Coastguard Workercan be queried by calling `DownloadIndex.getDownload()`.
275*30877f79SAndroid Build Coastguard Worker
276*30877f79SAndroid Build Coastguard Worker`DownloadManager` also provides `DownloadManager.getCurrentDownloads()`, which
277*30877f79SAndroid Build Coastguard Workerreturns the state of current (i.e. not completed or failed) downloads only. This
278*30877f79SAndroid Build Coastguard Workermethod is useful for updating notifications and other UI components that display
279*30877f79SAndroid Build Coastguard Workerthe progress and status of current downloads.
280*30877f79SAndroid Build Coastguard Worker
281*30877f79SAndroid Build Coastguard Worker## Listening to downloads ##
282*30877f79SAndroid Build Coastguard Worker
283*30877f79SAndroid Build Coastguard WorkerYou can add a listener to `DownloadManager` to be informed when current
284*30877f79SAndroid Build Coastguard Workerdownloads change state:
285*30877f79SAndroid Build Coastguard Worker
286*30877f79SAndroid Build Coastguard Worker~~~
287*30877f79SAndroid Build Coastguard WorkerdownloadManager.addListener(
288*30877f79SAndroid Build Coastguard Worker    new DownloadManager.Listener() {
289*30877f79SAndroid Build Coastguard Worker      // Override methods of interest here.
290*30877f79SAndroid Build Coastguard Worker    });
291*30877f79SAndroid Build Coastguard Worker~~~
292*30877f79SAndroid Build Coastguard Worker{: .language-java}
293*30877f79SAndroid Build Coastguard Worker
294*30877f79SAndroid Build Coastguard WorkerSee `DownloadManagerListener` in the demo app's [`DownloadTracker`][] class for
295*30877f79SAndroid Build Coastguard Workera concrete example.
296*30877f79SAndroid Build Coastguard Worker
297*30877f79SAndroid Build Coastguard WorkerDownload progress updates do not trigger calls on `DownloadManager.Listener`. To
298*30877f79SAndroid Build Coastguard Workerupdate a UI component that shows download progress, you should periodically
299*30877f79SAndroid Build Coastguard Workerquery the `DownloadManager` at your desired update rate. [`DownloadService`][]
300*30877f79SAndroid Build Coastguard Workercontains an example of this, which periodically updates the service foreground
301*30877f79SAndroid Build Coastguard Workernotification.
302*30877f79SAndroid Build Coastguard Worker{:.info}
303*30877f79SAndroid Build Coastguard Worker
304*30877f79SAndroid Build Coastguard Worker## Playing downloaded content ##
305*30877f79SAndroid Build Coastguard Worker
306*30877f79SAndroid Build Coastguard WorkerPlaying downloaded content is similar to playing online content, except that
307*30877f79SAndroid Build Coastguard Workerdata is read from the download `Cache` instead of over the network.
308*30877f79SAndroid Build Coastguard Worker
309*30877f79SAndroid Build Coastguard WorkerIt's important that you do not try and read files directly from the download
310*30877f79SAndroid Build Coastguard Workerdirectory. Instead, use ExoPlayer library classes as described below.
311*30877f79SAndroid Build Coastguard Worker{:.info}
312*30877f79SAndroid Build Coastguard Worker
313*30877f79SAndroid Build Coastguard WorkerTo play downloaded content, create a `CacheDataSource.Factory` using the same
314*30877f79SAndroid Build Coastguard Worker`Cache` instance that was used for downloading, and inject it into
315*30877f79SAndroid Build Coastguard Worker`DefaultMediaSourceFactory` when building the player:
316*30877f79SAndroid Build Coastguard Worker
317*30877f79SAndroid Build Coastguard Worker~~~
318*30877f79SAndroid Build Coastguard Worker// Create a read-only cache data source factory using the download cache.
319*30877f79SAndroid Build Coastguard WorkerDataSource.Factory cacheDataSourceFactory =
320*30877f79SAndroid Build Coastguard Worker    new CacheDataSource.Factory()
321*30877f79SAndroid Build Coastguard Worker        .setCache(downloadCache)
322*30877f79SAndroid Build Coastguard Worker        .setUpstreamDataSourceFactory(httpDataSourceFactory)
323*30877f79SAndroid Build Coastguard Worker        .setCacheWriteDataSinkFactory(null); // Disable writing.
324*30877f79SAndroid Build Coastguard Worker
325*30877f79SAndroid Build Coastguard WorkerExoPlayer player = new ExoPlayer.Builder(context)
326*30877f79SAndroid Build Coastguard Worker    .setMediaSourceFactory(
327*30877f79SAndroid Build Coastguard Worker        new DefaultMediaSourceFactory(cacheDataSourceFactory))
328*30877f79SAndroid Build Coastguard Worker    .build();
329*30877f79SAndroid Build Coastguard Worker~~~
330*30877f79SAndroid Build Coastguard Worker{: .language-java}
331*30877f79SAndroid Build Coastguard Worker
332*30877f79SAndroid Build Coastguard WorkerIf the same player instance will also be used to play non-downloaded content
333*30877f79SAndroid Build Coastguard Workerthen the `CacheDataSource.Factory` should be configured as read-only to avoid
334*30877f79SAndroid Build Coastguard Workerdownloading that content as well during playback.
335*30877f79SAndroid Build Coastguard Worker
336*30877f79SAndroid Build Coastguard WorkerOnce the player has been configured with the `CacheDataSource.Factory`, it will
337*30877f79SAndroid Build Coastguard Workerhave access to the downloaded content for playback. Playing a download is then
338*30877f79SAndroid Build Coastguard Workeras simple as passing the corresponding `MediaItem` to the player. A `MediaItem`
339*30877f79SAndroid Build Coastguard Workercan be obtained from a `Download` using `Download.request.toMediaItem`, or
340*30877f79SAndroid Build Coastguard Workerdirectly from a `DownloadRequest` using `DownloadRequest.toMediaItem`.
341*30877f79SAndroid Build Coastguard Worker
342*30877f79SAndroid Build Coastguard Worker### MediaSource configuration ###
343*30877f79SAndroid Build Coastguard Worker
344*30877f79SAndroid Build Coastguard WorkerThe example above makes the download cache available for playback of all
345*30877f79SAndroid Build Coastguard Worker`MediaItem`s. It's also possible to make the download cache available for
346*30877f79SAndroid Build Coastguard Workerindividual `MediaSource` instances, which can be passed directly to the player:
347*30877f79SAndroid Build Coastguard Worker
348*30877f79SAndroid Build Coastguard Worker~~~
349*30877f79SAndroid Build Coastguard WorkerProgressiveMediaSource mediaSource =
350*30877f79SAndroid Build Coastguard Worker    new ProgressiveMediaSource.Factory(cacheDataSourceFactory)
351*30877f79SAndroid Build Coastguard Worker        .createMediaSource(MediaItem.fromUri(contentUri));
352*30877f79SAndroid Build Coastguard Workerplayer.setMediaSource(mediaSource);
353*30877f79SAndroid Build Coastguard Workerplayer.prepare();
354*30877f79SAndroid Build Coastguard Worker~~~
355*30877f79SAndroid Build Coastguard Worker{: .language-java}
356*30877f79SAndroid Build Coastguard Worker
357*30877f79SAndroid Build Coastguard Worker## Downloading and playing adaptive streams ##
358*30877f79SAndroid Build Coastguard Worker
359*30877f79SAndroid Build Coastguard WorkerAdaptive streams (e.g. DASH, SmoothStreaming and HLS) normally contain multiple
360*30877f79SAndroid Build Coastguard Workermedia tracks. There are often multiple tracks that contain the same content in
361*30877f79SAndroid Build Coastguard Workerdifferent qualities (e.g. SD, HD and 4K video tracks). There may also be
362*30877f79SAndroid Build Coastguard Workermultiple tracks of the same type containing different content (e.g. multiple
363*30877f79SAndroid Build Coastguard Workeraudio tracks in different languages).
364*30877f79SAndroid Build Coastguard Worker
365*30877f79SAndroid Build Coastguard WorkerFor streaming playbacks, a track selector can be used to choose which of the
366*30877f79SAndroid Build Coastguard Workertracks are played. Similarly, for downloading, a `DownloadHelper` can be used to
367*30877f79SAndroid Build Coastguard Workerchoose which of the tracks are downloaded. Typical usage of a `DownloadHelper`
368*30877f79SAndroid Build Coastguard Workerfollows these steps:
369*30877f79SAndroid Build Coastguard Worker
370*30877f79SAndroid Build Coastguard Worker1. Build a `DownloadHelper` using one of the `DownloadHelper.forMediaItem`
371*30877f79SAndroid Build Coastguard Worker   methods. Prepare the helper and wait for the callback.
372*30877f79SAndroid Build Coastguard Worker   ~~~
373*30877f79SAndroid Build Coastguard Worker   DownloadHelper downloadHelper =
374*30877f79SAndroid Build Coastguard Worker       DownloadHelper.forMediaItem(
375*30877f79SAndroid Build Coastguard Worker           context,
376*30877f79SAndroid Build Coastguard Worker           MediaItem.fromUri(contentUri),
377*30877f79SAndroid Build Coastguard Worker           new DefaultRenderersFactory(context),
378*30877f79SAndroid Build Coastguard Worker           dataSourceFactory);
379*30877f79SAndroid Build Coastguard Worker   downloadHelper.prepare(myCallback);
380*30877f79SAndroid Build Coastguard Worker   ~~~
381*30877f79SAndroid Build Coastguard Worker   {: .language-java}
382*30877f79SAndroid Build Coastguard Worker1. Optionally, inspect the default selected tracks using `getMappedTrackInfo`
383*30877f79SAndroid Build Coastguard Worker   and `getTrackSelections`, and make adjustments using `clearTrackSelections`,
384*30877f79SAndroid Build Coastguard Worker   `replaceTrackSelections` and `addTrackSelection`.
385*30877f79SAndroid Build Coastguard Worker1. Create a `DownloadRequest` for the selected tracks by calling
386*30877f79SAndroid Build Coastguard Worker   `getDownloadRequest`. The request can be passed to your `DownloadService` to
387*30877f79SAndroid Build Coastguard Worker   add the download, as described above.
388*30877f79SAndroid Build Coastguard Worker1. Release the helper using `release()`.
389*30877f79SAndroid Build Coastguard Worker
390*30877f79SAndroid Build Coastguard WorkerPlayback of downloaded adaptive content requires configuring the player and
391*30877f79SAndroid Build Coastguard Workerpassing the corresponding `MediaItem`, as described above.
392*30877f79SAndroid Build Coastguard Worker
393*30877f79SAndroid Build Coastguard WorkerWhen building the `MediaItem`, `MediaItem.playbackProperties.streamKeys` must be
394*30877f79SAndroid Build Coastguard Workerset to match those in the `DownloadRequest` so that the player only tries to
395*30877f79SAndroid Build Coastguard Workerplay the subset of tracks that have been downloaded. Using
396*30877f79SAndroid Build Coastguard Worker`Download.request.toMediaItem` and `DownloadRequest.toMediaItem` to build the
397*30877f79SAndroid Build Coastguard Worker`MediaItem` will take care of this for you.
398*30877f79SAndroid Build Coastguard Worker
399*30877f79SAndroid Build Coastguard WorkerIf you see data being requested from the network when trying to play downloaded
400*30877f79SAndroid Build Coastguard Workeradaptive content, the most likely cause is that the player is trying to adapt to
401*30877f79SAndroid Build Coastguard Workera track that was not downloaded. Ensure you've set the stream keys correctly.
402*30877f79SAndroid Build Coastguard Worker{:.info}
403*30877f79SAndroid Build Coastguard Worker
404*30877f79SAndroid Build Coastguard Worker[JobScheduler]: {{ site.android_sdk }}/android/app/job/JobScheduler
405*30877f79SAndroid Build Coastguard Worker[PlatformScheduler]: {{ site.exo_sdk }}/scheduler/PlatformScheduler.html
406*30877f79SAndroid Build Coastguard Worker[WorkManager]: https://developer.android.com/topic/libraries/architecture/workmanager/
407*30877f79SAndroid Build Coastguard Worker[`DemoDownloadService`]: {{ site.release_v2 }}/demos/main/src/main/java/com/google/android/exoplayer2/demo/DemoDownloadService.java
408*30877f79SAndroid Build Coastguard Worker[`AndroidManifest.xml`]: {{ site.release_v2 }}/demos/main/src/main/AndroidManifest.xml
409*30877f79SAndroid Build Coastguard Worker[`DemoUtil`]: {{ site.release_v2 }}/demos/main/src/main/java/com/google/android/exoplayer2/demo/DemoUtil.java
410*30877f79SAndroid Build Coastguard Worker[`DownloadTracker`]: {{ site.release_v2 }}/demos/main/src/main/java/com/google/android/exoplayer2/demo/DownloadTracker.java
411*30877f79SAndroid Build Coastguard Worker[`DownloadService`]: {{ site.release_v2 }}/library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadService.java
412*30877f79SAndroid Build Coastguard Worker[`Requirements`]: {{ site.exo_sdk }}/scheduler/Requirements.html
413*30877f79SAndroid Build Coastguard Worker[further down this page]: #downloading-and-playing-adaptive-streams
414*30877f79SAndroid Build Coastguard Worker[above]: #creating-a-downloadmanager
415*30877f79SAndroid Build Coastguard Worker[setting stop reasons]: #setting-and-clearing-download-stop-reasons
416