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