Merge "Add an exported flag in manifest"
diff --git a/jni/Android.bp b/jni/Android.bp
index bbf2778..c409a1e 100644
--- a/jni/Android.bp
+++ b/jni/Android.bp
@@ -26,5 +26,6 @@
     ],
     sdk_version: "23",
     stl: "c++_static",
+    header_libs: ["jni_headers"],
     shared_libs: ["liblog"],
 }
diff --git a/tuner/src/com/android/tv/tuner/exoplayer2/FileSampleExtractor.java b/tuner/src/com/android/tv/tuner/exoplayer2/FileSampleExtractor.java
index 87f3a22..9bd5d37 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer2/FileSampleExtractor.java
+++ b/tuner/src/com/android/tv/tuner/exoplayer2/FileSampleExtractor.java
@@ -33,6 +33,9 @@
 import com.google.android.exoplayer2.util.MimeTypes;
 import com.google.auto.factory.AutoFactory;
 import com.google.auto.factory.Provided;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
 
 import java.io.IOException;
 import java.nio.ByteBuffer;
@@ -49,9 +52,7 @@
     private final long mRecordingDurationMs;
     private IOException mOnPrepareException = null;
 
-    private int mTrackCount;
     private boolean mReleased;
-
     private final BufferManager mBufferManager;
     private final PlaybackBufferListener mBufferListener;
     private BufferManager.SampleBuffer mSampleBuffer;
@@ -81,7 +82,6 @@
             @Provided RecordingSampleBuffer.Factory recordingSampleBufferFactory) {
         mBufferManager = bufferManager;
         mBufferListener = bufferListener;
-        mTrackCount = -1;
         mRecordingSampleBufferFactory = recordingSampleBufferFactory;
         mRecordingDurationMs = durationMs;
         mRunnable = () -> {
@@ -111,25 +111,29 @@
         if (trackFormatList == null || trackFormatList.isEmpty()) {
             throw new IOException("Cannot find meta files for the recording.");
         }
-        mTrackCount = trackFormatList.size();
-        List<String> ids = new ArrayList<>();
-        List<Format> trackFormats = new ArrayList<>();
-        TrackGroup[] trackGroups = new TrackGroup[mTrackCount];
-        for (int i = 0; i < mTrackCount; ++i) {
-            BufferManager.TrackFormat trackFormat = trackFormatList.get(i);
-            ids.add(trackFormat.trackId);
-            Format format = createFormat(trackFormat.mediaFormat);
-            trackFormats.add(format);
-            trackGroups[i] = new TrackGroup(format);
+        List<Format> formats = ImmutableList.copyOf(
+                Lists.transform(trackFormatList, tf -> createFormat(tf.mediaFormat)));
+        Format videoFormat = Iterables.find(formats, f -> MimeTypes.isVideo(f.sampleMimeType));
+        Iterable<TrackGroup> captionTrackGroups = new ArrayList<>();
+        if (videoFormat != null) {
+            Format textFormat = Format.createTextSampleFormat(
+                    /* id= */ null,
+                    MimeTypes.APPLICATION_CEA708,
+                    /* selectionFlags= */ 0,
+                    videoFormat.language,
+                    /* drmInitData= */ null);
+            captionTrackGroups = ImmutableList.of(new TrackGroup(textFormat));
         }
-        mTrackGroupArray = new TrackGroupArray(trackGroups);
+        Iterable<TrackGroup> trackGroups =
+                Iterables.concat(Iterables.transform(formats, TrackGroup::new), captionTrackGroups);
+        mTrackGroupArray = new TrackGroupArray(Iterables.toArray(trackGroups, TrackGroup.class));
         mSampleBuffer =
                 mRecordingSampleBufferFactory.create(
                         mBufferManager,
                         mBufferListener,
                         true,
                         RecordingSampleBuffer.BUFFER_REASON_RECORDED_PLAYBACK);
-        mSampleBuffer.init(ids, trackFormats);
+        mSampleBuffer.init(Lists.transform(trackFormatList, tf -> tf.trackId), formats);
         mCallback.onPrepared();
     }
 
diff --git a/tuner/src/com/android/tv/tuner/exoplayer2/MpegTsPlayerV2.java b/tuner/src/com/android/tv/tuner/exoplayer2/MpegTsPlayerV2.java
index 1b0c793..7cb4b9b 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer2/MpegTsPlayerV2.java
+++ b/tuner/src/com/android/tv/tuner/exoplayer2/MpegTsPlayerV2.java
@@ -118,9 +118,11 @@
 
     private DefaultTrackSelector.Parameters mTrackSelectorParameters;
     private TrackGroupArray mLastSeenTrackGroupArray;
+    private TrackSelectionArray mLastSeenTrackSelections;
     private Callback mCallback;
     private TsDataSource mDataSource;
     private VideoEventListener mVideoEventListener;
+    private boolean mCaptionsAvailable = false;
 
     /**
      * Creates MPEG2-TS stream player.
@@ -129,7 +131,9 @@
      * @param callback      callback for playback state changes
      */
     public MpegTsPlayerV2(Context context, Callback callback) {
-        mTrackSelectorParameters = new DefaultTrackSelector.ParametersBuilder().build();
+        mTrackSelectorParameters = new DefaultTrackSelector.ParametersBuilder()
+                                           .setSelectUndeterminedTextLanguage(true)
+                                           .build();
         mTrackSelector = new DefaultTrackSelector();
         mTrackSelector.setParameters(mTrackSelectorParameters);
         mLastSeenTrackGroupArray = null;
@@ -184,6 +188,10 @@
      */
     @Override
     public void onCues(List<Cue> cues) {
+        if (!mCaptionsAvailable && cues != null && cues.size() != 0) {
+            mCaptionsAvailable = true;
+            onTracksChanged(mLastSeenTrackGroupArray, mLastSeenTrackSelections);
+        }
         mVideoEventListener.onEmitCaptionEvent(
                 new CaptionEvent(
                         Cea708Parser.CAPTION_EMIT_TYPE_COMMAND_DFX,
@@ -251,6 +259,7 @@
         if (mDataSource != null) {
             mDataSource = null;
         }
+        mCaptionsAvailable = false;
         mCallback = null;
         mPlayer.release();
     }
@@ -320,7 +329,10 @@
             }
             mLastSeenTrackGroupArray = trackGroups;
         }
-        if (mVideoEventListener != null) {
+        if (trackSelections != mLastSeenTrackSelections) {
+            mLastSeenTrackSelections = trackSelections;
+        }
+        if (mVideoEventListener != null && mCaptionsAvailable) {
             MappedTrackInfo mappedTrackInfo = mTrackSelector.getCurrentMappedTrackInfo();
             if (mappedTrackInfo != null) {
                 int rendererCount = mappedTrackInfo.getRendererCount();
diff --git a/tuner/src/com/android/tv/tuner/exoplayer2/MpegTsSampleExtractor.java b/tuner/src/com/android/tv/tuner/exoplayer2/MpegTsSampleExtractor.java
index 74670ac..d6640b5 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer2/MpegTsSampleExtractor.java
+++ b/tuner/src/com/android/tv/tuner/exoplayer2/MpegTsSampleExtractor.java
@@ -47,7 +47,6 @@
  * //TODO: Can be discarded from exoplayer2
  */
 public final class MpegTsSampleExtractor implements SampleExtractor, SampleExtractor.Callback {
-    private static final String MIMETYPE_TEXT_CEA_708 = "text/cea-708";
 
     private static final int CC_BUFFER_SIZE_IN_BYTES = 9600 / 8;
 
@@ -183,9 +182,7 @@
 
     @Override
     public void getTrackMediaFormat(int track, FormatHolder outMediaFormatHolder) {
-        if (track != mCea708TextTrackIndex) {
-            mSampleExtractor.getTrackMediaFormat(track, outMediaFormatHolder);
-        }
+        mSampleExtractor.getTrackMediaFormat(track, outMediaFormatHolder);
     }
 
     @Override
@@ -193,8 +190,10 @@
         if (track == mCea708TextTrackIndex) {
             if (mCea708TextTrackSelected && !mPendingCcSamples.isEmpty()) {
                 DecoderInputBuffer holder = mPendingCcSamples.remove(0);
+                sampleHolder.ensureSpaceForWrite(CC_BUFFER_SIZE_IN_BYTES);
                 holder.data.flip();
                 sampleHolder.timeUs = holder.timeUs;
+                sampleHolder.data.clear();
                 sampleHolder.data.put(holder.data);
                 mCcInputBufferPool.releaseSample(holder);
                 return C.RESULT_BUFFER_READ;
@@ -259,17 +258,10 @@
                 } else if (MediaFormat.MIMETYPE_VIDEO_AVC.equals(mime)) {
                     mCcParser = new H264CcParser();
                 }
+            } else if (MimeTypes.APPLICATION_CEA708.equals(mime)) {
+                mCea708TextTrackIndex = i;
             }
         }
-
-        if (mVideoTrackIndex != -1) {
-            mCea708TextTrackIndex = trackCount;
-        }
-        if (mCea708TextTrackIndex >= 0) {
-            mTrackFormats.add(
-                    Format.createTextSampleFormat(
-                            null, MIMETYPE_TEXT_CEA_708, 0, mTrackFormats.get(0).language, null));
-        }
         mCallback.onPrepared();
     }
 
diff --git a/tuner/src/com/android/tv/tuner/exoplayer2/buffer/SampleChunkIoHelper.java b/tuner/src/com/android/tv/tuner/exoplayer2/buffer/SampleChunkIoHelper.java
index 5a3f668..93fc055 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer2/buffer/SampleChunkIoHelper.java
+++ b/tuner/src/com/android/tv/tuner/exoplayer2/buffer/SampleChunkIoHelper.java
@@ -259,8 +259,11 @@
         mediaFormat.setString(MediaFormat.KEY_MIME, format.sampleMimeType);
         mediaFormat.setInteger(MediaFormat.KEY_CHANNEL_COUNT, format.channelCount);
         mediaFormat.setInteger(MediaFormat.KEY_SAMPLE_RATE, format.sampleRate);
-        // Set mediaFormat parameters that may be unset.
         MediaFormatUtil.setCsdBuffers(mediaFormat, format.initializationData);
+        // Set mediaFormat parameters that may be unset.
+        if (format.language != null) {
+            mediaFormat.setString(MediaFormat.KEY_LANGUAGE, format.language);
+        }
         MediaFormatUtil.maybeSetInteger(
                 mediaFormat, MediaFormat.KEY_MAX_INPUT_SIZE, format.maxInputSize);
         if (Util.SDK_INT >= 23) {