18cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang/*
28cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang * Copyright 2018 The Android Open Source Project
38cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang *
48cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang * Licensed under the Apache License, Version 2.0 (the "License");
58cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang * you may not use this file except in compliance with the License.
68cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang * You may obtain a copy of the License at
78cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang *
88cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang *      http://www.apache.org/licenses/LICENSE-2.0
98cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang *
108cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang * Unless required by applicable law or agreed to in writing, software
118cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang * distributed under the License is distributed on an "AS IS" BASIS,
128cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang * See the License for the specific language governing permissions and
148cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang * limitations under the License.
158cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang */
168cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
178cd24124009a7f6343a4991b58c7db23f16fa973Insun Kangpackage com.android.media.subtitle;
188cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
198cd24124009a7f6343a4991b58c7db23f16fa973Insun Kangimport java.util.Locale;
208cd24124009a7f6343a4991b58c7db23f16fa973Insun Kangimport java.util.Vector;
218cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
228cd24124009a7f6343a4991b58c7db23f16fa973Insun Kangimport android.content.Context;
238cd24124009a7f6343a4991b58c7db23f16fa973Insun Kangimport android.media.MediaFormat;
248cd24124009a7f6343a4991b58c7db23f16fa973Insun Kangimport android.media.MediaPlayer2;
258cd24124009a7f6343a4991b58c7db23f16fa973Insun Kangimport android.media.MediaPlayer2.TrackInfo;
268cd24124009a7f6343a4991b58c7db23f16fa973Insun Kangimport android.os.Handler;
278cd24124009a7f6343a4991b58c7db23f16fa973Insun Kangimport android.os.Looper;
288cd24124009a7f6343a4991b58c7db23f16fa973Insun Kangimport android.os.Message;
298cd24124009a7f6343a4991b58c7db23f16fa973Insun Kangimport android.view.accessibility.CaptioningManager;
308cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
318cd24124009a7f6343a4991b58c7db23f16fa973Insun Kangimport com.android.media.subtitle.SubtitleTrack.RenderingWidget;
328cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
338cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang// Note: This is forked from android.media.SubtitleController since P
348cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang/**
358cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang * The subtitle controller provides the architecture to display subtitles for a
368cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang * media source.  It allows specifying which tracks to display, on which anchor
378cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang * to display them, and also allows adding external, out-of-band subtitle tracks.
388cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang */
398cd24124009a7f6343a4991b58c7db23f16fa973Insun Kangpublic class SubtitleController {
408cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    private MediaTimeProvider mTimeProvider;
418cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    private Vector<Renderer> mRenderers;
428cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    private Vector<SubtitleTrack> mTracks;
438cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    private SubtitleTrack mSelectedTrack;
448cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    private boolean mShowing;
458cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    private CaptioningManager mCaptioningManager;
468cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    private Handler mHandler;
478cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
488cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    private static final int WHAT_SHOW = 1;
498cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    private static final int WHAT_HIDE = 2;
508cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    private static final int WHAT_SELECT_TRACK = 3;
518cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    private static final int WHAT_SELECT_DEFAULT_TRACK = 4;
528cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
538cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    private final Handler.Callback mCallback = new Handler.Callback() {
548cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        @Override
558cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        public boolean handleMessage(Message msg) {
568cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            switch (msg.what) {
578cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            case WHAT_SHOW:
588cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                doShow();
598cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                return true;
608cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            case WHAT_HIDE:
618cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                doHide();
628cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                return true;
638cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            case WHAT_SELECT_TRACK:
648cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                doSelectTrack((SubtitleTrack)msg.obj);
658cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                return true;
668cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            case WHAT_SELECT_DEFAULT_TRACK:
678cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                doSelectDefaultTrack();
688cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                return true;
698cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            default:
708cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                return false;
718cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            }
728cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        }
738cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    };
748cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
758cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    private CaptioningManager.CaptioningChangeListener mCaptioningChangeListener =
768cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        new CaptioningManager.CaptioningChangeListener() {
778cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            @Override
788cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            public void onEnabledChanged(boolean enabled) {
798cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                selectDefaultTrack();
808cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            }
818cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
828cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            @Override
838cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            public void onLocaleChanged(Locale locale) {
848cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                selectDefaultTrack();
858cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            }
868cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        };
878cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
888cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    public SubtitleController(Context context) {
898cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        this(context, null, null);
908cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    }
918cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
928cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    /**
938cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     * Creates a subtitle controller for a media playback object that implements
948cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     * the MediaTimeProvider interface.
958cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     *
968cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     * @param timeProvider
978cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     */
988cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    public SubtitleController(
998cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            Context context,
1008cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            MediaTimeProvider timeProvider,
1018cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            Listener listener) {
1028cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        mTimeProvider = timeProvider;
1038cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        mListener = listener;
1048cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
1058cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        mRenderers = new Vector<Renderer>();
1068cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        mShowing = false;
1078cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        mTracks = new Vector<SubtitleTrack>();
1088cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        mCaptioningManager =
1098cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            (CaptioningManager)context.getSystemService(Context.CAPTIONING_SERVICE);
1108cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    }
1118cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
1128cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    @Override
1138cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    protected void finalize() throws Throwable {
1148cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        mCaptioningManager.removeCaptioningChangeListener(
1158cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                mCaptioningChangeListener);
1168cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        super.finalize();
1178cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    }
1188cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
1198cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    /**
1208cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     * @return the available subtitle tracks for this media. These include
1218cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     * the tracks found by {@link MediaPlayer} as well as any tracks added
1228cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     * manually via {@link #addTrack}.
1238cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     */
1248cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    public SubtitleTrack[] getTracks() {
1258cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        synchronized(mTracks) {
1268cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            SubtitleTrack[] tracks = new SubtitleTrack[mTracks.size()];
1278cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            mTracks.toArray(tracks);
1288cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            return tracks;
1298cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        }
1308cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    }
1318cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
1328cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    /**
1338cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     * @return the currently selected subtitle track
1348cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     */
1358cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    public SubtitleTrack getSelectedTrack() {
1368cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        return mSelectedTrack;
1378cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    }
1388cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
1398cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    private RenderingWidget getRenderingWidget() {
1408cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        if (mSelectedTrack == null) {
1418cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            return null;
1428cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        }
1438cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        return mSelectedTrack.getRenderingWidget();
1448cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    }
1458cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
1468cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    /**
1478cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     * Selects a subtitle track.  As a result, this track will receive
1488cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     * in-band data from the {@link MediaPlayer}.  However, this does
1498cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     * not change the subtitle visibility.
1508cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     *
1518cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     * Should be called from the anchor's (UI) thread. {@see #Anchor.getSubtitleLooper}
1528cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     *
1538cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     * @param track The subtitle track to select.  This must be one of the
1548cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     *              tracks in {@link #getTracks}.
1558cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     * @return true if the track was successfully selected.
1568cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     */
1578cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    public boolean selectTrack(SubtitleTrack track) {
1588cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        if (track != null && !mTracks.contains(track)) {
1598cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            return false;
1608cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        }
1618cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
1628cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        processOnAnchor(mHandler.obtainMessage(WHAT_SELECT_TRACK, track));
1638cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        return true;
1648cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    }
1658cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
1668cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    private void doSelectTrack(SubtitleTrack track) {
1678cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        mTrackIsExplicit = true;
1688cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        if (mSelectedTrack == track) {
1698cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            return;
1708cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        }
1718cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
1728cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        if (mSelectedTrack != null) {
1738cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            mSelectedTrack.hide();
1748cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            mSelectedTrack.setTimeProvider(null);
1758cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        }
1768cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
1778cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        mSelectedTrack = track;
1788cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        if (mAnchor != null) {
1798cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            mAnchor.setSubtitleWidget(getRenderingWidget());
1808cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        }
1818cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
1828cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        if (mSelectedTrack != null) {
1838cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            mSelectedTrack.setTimeProvider(mTimeProvider);
1848cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            mSelectedTrack.show();
1858cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        }
1868cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
1878cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        if (mListener != null) {
1888cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            mListener.onSubtitleTrackSelected(track);
1898cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        }
1908cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    }
1918cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
1928cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    /**
1938cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     * @return the default subtitle track based on system preferences, or null,
1948cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     * if no such track exists in this manager.
1958cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     *
1968cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     * Supports HLS-flags: AUTOSELECT, FORCED & DEFAULT.
1978cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     *
1988cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     * 1. If captioning is disabled, only consider FORCED tracks. Otherwise,
1998cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     * consider all tracks, but prefer non-FORCED ones.
2008cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     * 2. If user selected "Default" caption language:
2018cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     *   a. If there is a considered track with DEFAULT=yes, returns that track
2028cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     *      (favor the first one in the current language if there are more than
2038cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     *      one default tracks, or the first in general if none of them are in
2048cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     *      the current language).
2058cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     *   b. Otherwise, if there is a track with AUTOSELECT=yes in the current
2068cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     *      language, return that one.
2078cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     *   c. If there are no default tracks, and no autoselectable tracks in the
2088cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     *      current language, return null.
2098cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     * 3. If there is a track with the caption language, select that one.  Prefer
2108cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     * the one with AUTOSELECT=no.
2118cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     *
2128cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     * The default values for these flags are DEFAULT=no, AUTOSELECT=yes
2138cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     * and FORCED=no.
2148cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     */
2158cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    public SubtitleTrack getDefaultTrack() {
2168cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        SubtitleTrack bestTrack = null;
2178cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        int bestScore = -1;
2188cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
2198cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        Locale selectedLocale = mCaptioningManager.getLocale();
2208cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        Locale locale = selectedLocale;
2218cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        if (locale == null) {
2228cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            locale = Locale.getDefault();
2238cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        }
2248cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        boolean selectForced = !mCaptioningManager.isEnabled();
2258cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
2268cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        synchronized(mTracks) {
2278cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            for (SubtitleTrack track: mTracks) {
2288cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                MediaFormat format = track.getFormat();
2298cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                String language = format.getString(MediaFormat.KEY_LANGUAGE);
2308cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                boolean forced =
2318cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                    format.getInteger(MediaFormat.KEY_IS_FORCED_SUBTITLE, 0) != 0;
2328cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                boolean autoselect =
2338cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                    format.getInteger(MediaFormat.KEY_IS_AUTOSELECT, 1) != 0;
2348cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                boolean is_default =
2358cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                    format.getInteger(MediaFormat.KEY_IS_DEFAULT, 0) != 0;
2368cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
2378cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                boolean languageMatches =
2388cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                    (locale == null ||
2398cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                    locale.getLanguage().equals("") ||
2408cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                    locale.getISO3Language().equals(language) ||
2418cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                    locale.getLanguage().equals(language));
2428cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                // is_default is meaningless unless caption language is 'default'
2438cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                int score = (forced ? 0 : 8) +
2448cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                    (((selectedLocale == null) && is_default) ? 4 : 0) +
2458cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                    (autoselect ? 0 : 2) + (languageMatches ? 1 : 0);
2468cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
2478cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                if (selectForced && !forced) {
2488cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                    continue;
2498cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                }
2508cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
2518cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                // we treat null locale/language as matching any language
2528cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                if ((selectedLocale == null && is_default) ||
2538cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                    (languageMatches &&
2548cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                     (autoselect || forced || selectedLocale != null))) {
2558cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                    if (score > bestScore) {
2568cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                        bestScore = score;
2578cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                        bestTrack = track;
2588cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                    }
2598cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                }
2608cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            }
2618cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        }
2628cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        return bestTrack;
2638cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    }
2648cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
2658cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    private boolean mTrackIsExplicit = false;
2668cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    private boolean mVisibilityIsExplicit = false;
2678cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
2688cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    /** should be called from anchor thread */
2698cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    public void selectDefaultTrack() {
2708cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        processOnAnchor(mHandler.obtainMessage(WHAT_SELECT_DEFAULT_TRACK));
2718cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    }
2728cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
2738cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    private void doSelectDefaultTrack() {
2748cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        if (mTrackIsExplicit) {
2758cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            // If track selection is explicit, but visibility
2768cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            // is not, it falls back to the captioning setting
2778cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            if (!mVisibilityIsExplicit) {
2788cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                if (mCaptioningManager.isEnabled() ||
2798cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                    (mSelectedTrack != null &&
2808cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                     mSelectedTrack.getFormat().getInteger(
2818cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                            MediaFormat.KEY_IS_FORCED_SUBTITLE, 0) != 0)) {
2828cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                    show();
2838cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                } else if (mSelectedTrack != null
2848cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                        && mSelectedTrack.getTrackType() == TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE) {
2858cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                    hide();
2868cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                }
2878cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                mVisibilityIsExplicit = false;
2888cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            }
2898cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            return;
2908cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        }
2918cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
2928cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        // We can have a default (forced) track even if captioning
2938cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        // is not enabled.  This is handled by getDefaultTrack().
2948cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        // Show this track unless subtitles were explicitly hidden.
2958cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        SubtitleTrack track = getDefaultTrack();
2968cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        if (track != null) {
2978cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            selectTrack(track);
2988cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            mTrackIsExplicit = false;
2998cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            if (!mVisibilityIsExplicit) {
3008cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                show();
3018cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                mVisibilityIsExplicit = false;
3028cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            }
3038cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        }
3048cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    }
3058cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
3068cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    /** must be called from anchor thread */
3078cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    public void reset() {
3088cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        checkAnchorLooper();
3098cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        hide();
3108cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        selectTrack(null);
3118cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        mTracks.clear();
3128cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        mTrackIsExplicit = false;
3138cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        mVisibilityIsExplicit = false;
3148cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        mCaptioningManager.removeCaptioningChangeListener(
3158cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                mCaptioningChangeListener);
3168cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    }
3178cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
3188cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    /**
3198cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     * Adds a new, external subtitle track to the manager.
3208cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     *
3218cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     * @param format the format of the track that will include at least
3228cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     *               the MIME type {@link MediaFormat@KEY_MIME}.
3238cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     * @return the created {@link SubtitleTrack} object
3248cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     */
3258cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    public SubtitleTrack addTrack(MediaFormat format) {
3268cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        synchronized(mRenderers) {
3278cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            for (Renderer renderer: mRenderers) {
3288cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                if (renderer.supports(format)) {
3298cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                    SubtitleTrack track = renderer.createTrack(format);
3308cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                    if (track != null) {
3318cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                        synchronized(mTracks) {
3328cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                            if (mTracks.size() == 0) {
3338cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                                mCaptioningManager.addCaptioningChangeListener(
3348cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                                        mCaptioningChangeListener);
3358cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                            }
3368cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                            mTracks.add(track);
3378cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                        }
3388cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                        return track;
3398cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                    }
3408cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                }
3418cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            }
3428cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        }
3438cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        return null;
3448cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    }
3458cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
3468cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    /**
3478cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     * Show the selected (or default) subtitle track.
3488cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     *
3498cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     * Should be called from the anchor's (UI) thread. {@see #Anchor.getSubtitleLooper}
3508cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     */
3518cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    public void show() {
3528cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        processOnAnchor(mHandler.obtainMessage(WHAT_SHOW));
3538cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    }
3548cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
3558cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    private void doShow() {
3568cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        mShowing = true;
3578cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        mVisibilityIsExplicit = true;
3588cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        if (mSelectedTrack != null) {
3598cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            mSelectedTrack.show();
3608cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        }
3618cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    }
3628cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
3638cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    /**
3648cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     * Hide the selected (or default) subtitle track.
3658cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     *
3668cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     * Should be called from the anchor's (UI) thread. {@see #Anchor.getSubtitleLooper}
3678cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     */
3688cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    public void hide() {
3698cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        processOnAnchor(mHandler.obtainMessage(WHAT_HIDE));
3708cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    }
3718cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
3728cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    private void doHide() {
3738cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        mVisibilityIsExplicit = true;
3748cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        if (mSelectedTrack != null) {
3758cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            mSelectedTrack.hide();
3768cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        }
3778cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        mShowing = false;
3788cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    }
3798cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
3808cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    /**
3818cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     * Interface for supporting a single or multiple subtitle types in {@link
3828cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     * MediaPlayer}.
3838cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     */
3848cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    public abstract static class Renderer {
3858cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        /**
3868cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang         * Called by {@link MediaPlayer}'s {@link SubtitleController} when a new
3878cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang         * subtitle track is detected, to see if it should use this object to
3888cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang         * parse and display this subtitle track.
3898cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang         *
3908cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang         * @param format the format of the track that will include at least
3918cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang         *               the MIME type {@link MediaFormat@KEY_MIME}.
3928cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang         *
3938cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang         * @return true if and only if the track format is supported by this
3948cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang         * renderer
3958cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang         */
3968cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        public abstract boolean supports(MediaFormat format);
3978cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
3988cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        /**
3998cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang         * Called by {@link MediaPlayer}'s {@link SubtitleController} for each
4008cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang         * subtitle track that was detected and is supported by this object to
4018cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang         * create a {@link SubtitleTrack} object.  This object will be created
4028cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang         * for each track that was found.  If the track is selected for display,
4038cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang         * this object will be used to parse and display the track data.
4048cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang         *
4058cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang         * @param format the format of the track that will include at least
4068cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang         *               the MIME type {@link MediaFormat@KEY_MIME}.
4078cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang         * @return a {@link SubtitleTrack} object that will be used to parse
4088cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang         * and render the subtitle track.
4098cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang         */
4108cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        public abstract SubtitleTrack createTrack(MediaFormat format);
4118cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    }
4128cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
4138cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    /**
4148cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     * Add support for a subtitle format in {@link MediaPlayer}.
4158cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     *
4168cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     * @param renderer a {@link SubtitleController.Renderer} object that adds
4178cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     *                 support for a subtitle format.
4188cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     */
4198cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    public void registerRenderer(Renderer renderer) {
4208cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        synchronized(mRenderers) {
4218cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            // TODO how to get available renderers in the system
4228cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            if (!mRenderers.contains(renderer)) {
4238cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                // TODO should added renderers override existing ones (to allow replacing?)
4248cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                mRenderers.add(renderer);
4258cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            }
4268cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        }
4278cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    }
4288cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
4298cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    public boolean hasRendererFor(MediaFormat format) {
4308cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        synchronized(mRenderers) {
4318cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            // TODO how to get available renderers in the system
4328cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            for (Renderer renderer: mRenderers) {
4338cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                if (renderer.supports(format)) {
4348cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                    return true;
4358cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                }
4368cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            }
4378cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            return false;
4388cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        }
4398cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    }
4408cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
4418cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    /**
4428cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     * Subtitle anchor, an object that is able to display a subtitle renderer,
4438cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     * e.g. a VideoView.
4448cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     */
4458cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    public interface Anchor {
4468cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        /**
4478cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang         * Anchor should use the supplied subtitle rendering widget, or
4488cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang         * none if it is null.
4498cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang         */
4508cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        public void setSubtitleWidget(RenderingWidget subtitleWidget);
4518cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
4528cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        /**
4538cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang         * Anchors provide the looper on which all track visibility changes
4548cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang         * (track.show/hide, setSubtitleWidget) will take place.
4558cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang         */
4568cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        public Looper getSubtitleLooper();
4578cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    }
4588cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
4598cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    private Anchor mAnchor;
4608cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
4618cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    /**
4628cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     *  called from anchor's looper (if any, both when unsetting and
4638cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     *  setting)
4648cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang     */
4658cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    public void setAnchor(Anchor anchor) {
4668cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        if (mAnchor == anchor) {
4678cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            return;
4688cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        }
4698cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
4708cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        if (mAnchor != null) {
4718cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            checkAnchorLooper();
4728cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            mAnchor.setSubtitleWidget(null);
4738cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        }
4748cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        mAnchor = anchor;
4758cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        mHandler = null;
4768cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        if (mAnchor != null) {
4778cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            mHandler = new Handler(mAnchor.getSubtitleLooper(), mCallback);
4788cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            checkAnchorLooper();
4798cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            mAnchor.setSubtitleWidget(getRenderingWidget());
4808cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        }
4818cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    }
4828cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
4838cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    private void checkAnchorLooper() {
4848cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        assert mHandler != null : "Should have a looper already";
4858cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        assert Looper.myLooper() == mHandler.getLooper()
4868cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang                : "Must be called from the anchor's looper";
4878cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    }
4888cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
4898cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    private void processOnAnchor(Message m) {
4908cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        assert mHandler != null : "Should have a looper already";
4918cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        if (Looper.myLooper() == mHandler.getLooper()) {
4928cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            mHandler.dispatchMessage(m);
4938cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        } else {
4948cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang            mHandler.sendMessage(m);
4958cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        }
4968cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    }
4978cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
4988cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    public interface Listener {
4998cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        /**
5008cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang         * Called when a subtitle track has been selected.
5018cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang         *
5028cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang         * @param track selected subtitle track or null
5038cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang         */
5048cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang        public void onSubtitleTrackSelected(SubtitleTrack track);
5058cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    }
5068cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang
5078cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang    private Listener mListener;
5088cd24124009a7f6343a4991b58c7db23f16fa973Insun Kang}
509