Created
September 4, 2015 07:59
-
-
Save bespechnost/ade375298ab628e7bd35 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| * Copyright (C) 2014 The Android Open Source Project | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| package com.example.vkulibaba.smartnemotv; | |
| import android.annotation.TargetApi; | |
| import android.app.Activity; | |
| import android.content.Context; | |
| import android.content.Intent; | |
| import android.graphics.Color; | |
| import android.net.Uri; | |
| import android.os.Build; | |
| import android.os.Bundle; | |
| import android.os.Handler; | |
| import android.telephony.TelephonyManager; | |
| import android.text.TextUtils; | |
| import android.util.Log; | |
| import android.view.KeyEvent; | |
| import android.view.Menu; | |
| import android.view.MenuItem; | |
| import android.view.MotionEvent; | |
| import android.view.SurfaceHolder; | |
| import android.view.SurfaceView; | |
| import android.view.View; | |
| import android.view.View.OnClickListener; | |
| import android.view.View.OnKeyListener; | |
| import android.view.View.OnTouchListener; | |
| import android.view.accessibility.CaptioningManager; | |
| import android.webkit.JavascriptInterface; | |
| import android.webkit.WebView; | |
| import android.widget.Button; | |
| import android.widget.MediaController; | |
| import android.widget.PopupMenu; | |
| import android.widget.PopupMenu.OnMenuItemClickListener; | |
| import android.widget.TextView; | |
| import android.widget.Toast; | |
| import com.google.android.exoplayer.AspectRatioFrameLayout; | |
| import com.google.android.exoplayer.ExoPlayer; | |
| import com.google.android.exoplayer.audio.AudioCapabilities; | |
| import com.google.android.exoplayer.audio.AudioCapabilitiesReceiver; | |
| import com.google.android.exoplayer.drm.UnsupportedDrmException; | |
| import com.google.android.exoplayer.metadata.GeobMetadata; | |
| import com.google.android.exoplayer.metadata.PrivMetadata; | |
| import com.google.android.exoplayer.metadata.TxxxMetadata; | |
| import com.google.android.exoplayer.text.CaptionStyleCompat; | |
| import com.google.android.exoplayer.text.Cue; | |
| import com.google.android.exoplayer.text.SubtitleLayout; | |
| import com.google.android.exoplayer.util.DebugTextViewHelper; | |
| import com.google.android.exoplayer.util.Util; | |
| import com.google.android.exoplayer.util.VerboseLogUtil; | |
| import java.net.CookieHandler; | |
| import java.net.CookieManager; | |
| import java.net.CookiePolicy; | |
| import java.util.List; | |
| import java.util.Map; | |
| import java.util.UUID; | |
| /** | |
| * An activity that plays media using {@link NemoPlayer}. | |
| */ | |
| public class MainActivity extends Activity implements SurfaceHolder.Callback, OnClickListener, | |
| NemoPlayer.Listener, NemoPlayer.CaptionListener, NemoPlayer.Id3MetadataListener, | |
| AudioCapabilitiesReceiver.Listener { | |
| public static final int TYPE_DASH = 0; | |
| public static final int TYPE_SS = 1; | |
| public static final int TYPE_HLS = 2; | |
| public static final int TYPE_OTHER = 3; | |
| public static final String CONTENT_TYPE_EXTRA = "content_type"; | |
| public static final String CONTENT_ID_EXTRA = "content_id"; | |
| private static final String TAG = "MainActivity"; | |
| private static final int MENU_GROUP_TRACKS = 1; | |
| private static final int ID_OFFSET = 2; | |
| private static final CookieManager defaultCookieManager; | |
| static { | |
| defaultCookieManager = new CookieManager(); | |
| defaultCookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ORIGINAL_SERVER); | |
| } | |
| private EventLogger eventLogger; | |
| private MediaController mediaController; | |
| private View debugRootView; | |
| private View shutterView; | |
| private AspectRatioFrameLayout videoFrame; | |
| private SurfaceView surfaceView; | |
| private TextView debugTextView; | |
| private TextView playerStateTextView; | |
| private SubtitleLayout subtitleLayout; | |
| private Button videoButton; | |
| private Button audioButton; | |
| private Button textButton; | |
| private Button retryButton; | |
| private NemoPlayer player; | |
| private DebugTextViewHelper debugViewHelper; | |
| private boolean playerNeedsPrepare; | |
| private long playerPosition; | |
| private boolean enableBackgroundAudio; | |
| private Uri contentUri; | |
| private int contentType; | |
| private String contentId; | |
| private AudioCapabilitiesReceiver audioCapabilitiesReceiver; | |
| private AudioCapabilities audioCapabilities; | |
| private WebView webView; | |
| private JsObject jsObject; | |
| private String callBackName = "androidCallBack"; | |
| private Activity activity; | |
| private Handler handlerUpd; | |
| private Runnable runnableUpd; | |
| // Activity lifecycle | |
| @Override | |
| public void onCreate(Bundle savedInstanceState) { | |
| super.onCreate(savedInstanceState); | |
| activity = this; | |
| Intent intent = getIntent(); | |
| contentUri = intent.getData(); | |
| contentType = intent.getIntExtra(CONTENT_TYPE_EXTRA, -1); | |
| contentId = intent.getStringExtra(CONTENT_ID_EXTRA); | |
| setContentView(R.layout.player_activity); | |
| View root = findViewById(R.id.root); | |
| root.setOnTouchListener(new OnTouchListener() { | |
| @Override | |
| public boolean onTouch(View view, MotionEvent motionEvent) { | |
| if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) { | |
| toggleControlsVisibility(); | |
| } else if (motionEvent.getAction() == MotionEvent.ACTION_UP) { | |
| view.performClick(); | |
| } | |
| return true; | |
| } | |
| }); | |
| root.setOnKeyListener(new OnKeyListener() { | |
| @Override | |
| public boolean onKey(View v, int keyCode, KeyEvent event) { | |
| if (keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE) { | |
| return mediaController.dispatchKeyEvent(event); | |
| } | |
| return false; | |
| } | |
| }); | |
| audioCapabilitiesReceiver = new AudioCapabilitiesReceiver(getApplicationContext(), this); | |
| shutterView = findViewById(R.id.shutter); | |
| debugRootView = findViewById(R.id.controls_root); | |
| videoFrame = (AspectRatioFrameLayout) findViewById(R.id.video_frame); | |
| surfaceView = (SurfaceView) findViewById(R.id.surface_view); | |
| surfaceView.getHolder().addCallback(this); | |
| debugTextView = (TextView) findViewById(R.id.debug_text_view); | |
| playerStateTextView = (TextView) findViewById(R.id.player_state_view); | |
| subtitleLayout = (SubtitleLayout) findViewById(R.id.subtitles); | |
| mediaController = new MediaController(this); | |
| mediaController.setAnchorView(root); | |
| retryButton = (Button) findViewById(R.id.retry_button); | |
| retryButton.setOnClickListener(this); | |
| videoButton = (Button) findViewById(R.id.video_controls); | |
| audioButton = (Button) findViewById(R.id.audio_controls); | |
| textButton = (Button) findViewById(R.id.text_controls); | |
| CookieHandler currentHandler = CookieHandler.getDefault(); | |
| if (currentHandler != defaultCookieManager) { | |
| CookieHandler.setDefault(defaultCookieManager); | |
| } | |
| webView = (WebView) findViewById(R.id.webView); | |
| webView.getSettings().setJavaScriptEnabled(true); | |
| webView.getSettings().setAllowContentAccess(true); | |
| webView.getSettings().setAppCacheEnabled(true); | |
| webView.getSettings().setDomStorageEnabled(true); | |
| webView.setFocusable(true); | |
| webView.setFocusableInTouchMode(true); | |
| webView.setBackgroundColor(Color.TRANSPARENT); | |
| webView.setBackgroundColor(Color.TRANSPARENT); | |
| webView.requestFocus(); | |
| setDebug(); | |
| handlerUpd = new Handler(); | |
| runnableUpd = new Runnable() { | |
| @Override | |
| public void run() { | |
| javaCallBack("{'name':'" + "timeupdate" + "','value':'" + 0 + "'}"); | |
| handlerUpd.postDelayed(runnableUpd, 1000); | |
| } | |
| }; | |
| jsObject = new JsObject(this); | |
| webView.addJavascriptInterface(jsObject, "Android"); | |
| //webView.loadUrl("http://192.168.5.107/nightly/nemotv3/NemoTV_v3.0.0.29-1-g0c480f0-android-release/"); | |
| webView.loadUrl("http://192.168.5.107/nightly/nemotv3/android-release/"); | |
| // webView.loadUrl("http://192.168.6.141:8080/android/index.html"); | |
| } | |
| @TargetApi(Build.VERSION_CODES.KITKAT) | |
| public void setDebug() { | |
| webView.setWebContentsDebuggingEnabled(true); | |
| } | |
| public void javaCallBack(String jsString) { | |
| final String webUrl = "javascript:"+callBackName+"("+jsString+")"; | |
| if(!activity.isFinishing()) | |
| // loadurl on UI main thread | |
| activity.runOnUiThread(new Runnable() { | |
| @Override | |
| public void run() { | |
| webView.loadUrl(webUrl); | |
| } | |
| }); | |
| } | |
| private class JsObject { | |
| private Context mContext; | |
| private Handler jsHandler; | |
| private Runnable jsRunnable; | |
| private long lastSeekTime = 0; | |
| private final int UPDATE_DURATION = 100;//100ms | |
| public JsObject(Context context) { | |
| mContext = context; | |
| jsHandler = new Handler(); | |
| } | |
| @JavascriptInterface | |
| public void setCallBack(String name) { | |
| callBackName = name; | |
| } | |
| @JavascriptInterface | |
| public void play(String videoUri) { | |
| //videoUri = "http://217.29.54.235/stream/tvzavr/3/23a91cc6-b58e-4567-95ca-84da0a4af88b/mnf.m3u8?usessionid=y91lgNzwRB89RtUAqF9x9N0F+PFqsKz13KUdCV+qnXE=&token=a0d8a3447c51e40e1e4d7387d5d1455d5b2f11edf8d71b0d1e7443196eefa48a40c0f44aef06dfad5949dcc42653c68a&pageurl=null&platform=ntv"; | |
| Uri uri = Uri.parse(videoUri); | |
| contentUri = uri; | |
| contentType = TYPE_HLS; | |
| contentId = "1"; | |
| audioCapabilitiesReceiver.register(); | |
| } | |
| @JavascriptInterface | |
| public boolean stop() { | |
| releasePlayer(); | |
| audioCapabilitiesReceiver.unregister(); | |
| //TODO очистить поверхность | |
| return true; | |
| } | |
| @JavascriptInterface | |
| public void pause() { | |
| player.setPlayWhenReady(false); | |
| } | |
| @JavascriptInterface | |
| public void resume() { | |
| player.setPlayWhenReady(true); | |
| //audioCapabilitiesReceiver.register(); | |
| } | |
| @JavascriptInterface | |
| public int getDuration() { | |
| return (int)player.getDuration(); | |
| } | |
| @JavascriptInterface | |
| public int getCurrentPosition() { | |
| int pos = 0; | |
| if (player == null) { | |
| pos = -1; | |
| } | |
| else { | |
| pos = (int)player.getCurrentPosition(); | |
| } | |
| return pos; | |
| } | |
| @JavascriptInterface | |
| public void seekTo(int mSec) { | |
| final int finalmSec = mSec; | |
| player.seekTo(finalmSec); | |
| /* | |
| Log.w(TAG, "currentTimeMillis:" + System.currentTimeMillis()); | |
| lastSeekTime = System.currentTimeMillis(); | |
| jsRunnable = new Runnable() { | |
| @Override | |
| public void run() { | |
| long currentTime = System.currentTimeMillis(); | |
| if (currentTime - lastSeekTime > UPDATE_DURATION) { | |
| //Прошло больше 100ms с последнего запроса на сикту | |
| player.seekTo(finalmSec); | |
| lastSeekTime = currentTime; | |
| } | |
| else { | |
| //Прошло менее 100ms | |
| //do nothing | |
| } | |
| } | |
| }; | |
| */ | |
| //jsHandler.postDelayed(jsRunnable, UPDATE_DURATION); | |
| } | |
| @JavascriptInterface | |
| public boolean isPlaying() { | |
| return player.getPlaybackState() == ExoPlayer.STATE_READY; | |
| } | |
| @JavascriptInterface | |
| public int getState() { | |
| return player.getPlaybackState(); | |
| } | |
| @JavascriptInterface | |
| public String getStateString() { | |
| return EventLogger.getStateString(player.getPlaybackState()); | |
| } | |
| @JavascriptInterface | |
| public String getDeviceId() { | |
| final TelephonyManager tm = (TelephonyManager) getBaseContext().getSystemService(Context.TELEPHONY_SERVICE); | |
| final String tmDevice, tmSerial, androidId; | |
| tmDevice = "" + tm.getDeviceId(); | |
| tmSerial = "" + tm.getSimSerialNumber(); | |
| androidId = "" + android.provider.Settings.Secure.getString(getContentResolver(), android.provider.Settings.Secure.ANDROID_ID); | |
| UUID deviceUuid = new UUID(androidId.hashCode(), ((long)tmDevice.hashCode() << 32) | tmSerial.hashCode()); | |
| return deviceUuid.toString(); | |
| } | |
| @JavascriptInterface | |
| public void exit() { | |
| finish(); | |
| } | |
| } | |
| @Override | |
| public void onBackPressed() | |
| { | |
| webView.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ESCAPE)); | |
| } | |
| @Override | |
| public void onResume() { | |
| super.onResume(); | |
| configureSubtitleView(); | |
| // The player will be prepared on receiving audio capabilities. | |
| if (contentUri != null) { | |
| audioCapabilitiesReceiver.register(); | |
| } | |
| } | |
| @Override | |
| public void onPause() { | |
| super.onPause(); | |
| if (!enableBackgroundAudio) { | |
| releasePlayer(); | |
| } else { | |
| player.setBackgrounded(true); | |
| } | |
| audioCapabilitiesReceiver.unregister(); | |
| } | |
| @Override | |
| public void onDestroy() { | |
| super.onDestroy(); | |
| releasePlayer(); | |
| } | |
| // OnClickListener methods | |
| @Override | |
| public void onClick(View view) { | |
| if (view == retryButton) { | |
| preparePlayer(); | |
| } | |
| } | |
| // AudioCapabilitiesReceiver.Listener methods | |
| @Override | |
| public void onAudioCapabilitiesChanged(AudioCapabilities audioCapabilities) { | |
| boolean audioCapabilitiesChanged = !audioCapabilities.equals(this.audioCapabilities); | |
| if (player == null || audioCapabilitiesChanged) { | |
| this.audioCapabilities = audioCapabilities; | |
| releasePlayer(); | |
| preparePlayer(); | |
| } else if (player != null) { | |
| player.setBackgrounded(false); | |
| } | |
| } | |
| // Internal methods | |
| private NemoPlayer.RendererBuilder getRendererBuilder() { | |
| String userAgent = Util.getUserAgent(this, "ExoPlayerDemo"); | |
| switch (contentType) { | |
| /* | |
| case TYPE_SS: | |
| return new SmoothStreamingRendererBuilder(this, userAgent, contentUri.toString(), | |
| new SmoothStreamingTestMediaDrmCallback()); | |
| case TYPE_DASH: | |
| return new DashRendererBuilder(this, userAgent, contentUri.toString(), | |
| new WidevineTestMediaDrmCallback(contentId), audioCapabilities); | |
| */ | |
| case TYPE_HLS: | |
| return new HlsRendererBuilder(this, userAgent, contentUri.toString(), audioCapabilities); | |
| /* | |
| case TYPE_OTHER: | |
| return new ExtractorRendererBuilder(this, userAgent, contentUri); | |
| */ | |
| default: | |
| throw new IllegalStateException("Unsupported type: " + contentType); | |
| } | |
| } | |
| private void preparePlayer() { | |
| if (player == null) { | |
| player = new NemoPlayer(getRendererBuilder()); | |
| player.addListener(this); | |
| player.setCaptionListener(this); | |
| player.setMetadataListener(this); | |
| player.seekTo(playerPosition); | |
| playerNeedsPrepare = true; | |
| mediaController.setMediaPlayer(player.getPlayerControl()); | |
| mediaController.setEnabled(true); | |
| eventLogger = new EventLogger(); | |
| eventLogger.startSession(); | |
| player.addListener(eventLogger); | |
| player.setInfoListener(eventLogger); | |
| player.setInternalErrorListener(eventLogger); | |
| debugViewHelper = new DebugTextViewHelper(player, debugTextView); | |
| activity.runOnUiThread(new Runnable() { | |
| @Override | |
| public void run() { | |
| debugViewHelper.start(); | |
| } | |
| }); | |
| } | |
| if (playerNeedsPrepare) { | |
| player.prepare(); | |
| playerNeedsPrepare = false; | |
| updateButtonVisibilities(); | |
| } | |
| player.setSurface(surfaceView.getHolder().getSurface()); | |
| player.setPlayWhenReady(true); | |
| } | |
| private void releasePlayer() { | |
| if (player != null) { | |
| debugViewHelper.stop(); | |
| debugViewHelper = null; | |
| playerPosition = player.getCurrentPosition(); | |
| player.release(); | |
| player = null; | |
| eventLogger.endSession(); | |
| eventLogger = null; | |
| } | |
| } | |
| // NemoPlayer.Listener implementation | |
| @Override | |
| public void onStateChanged(boolean playWhenReady, int playbackState) { | |
| if (playbackState == ExoPlayer.STATE_ENDED) { | |
| showControls(); | |
| } | |
| String text = "playWhenReady=" + playWhenReady + ", playbackState="; | |
| String name; | |
| switch (playbackState) { | |
| case ExoPlayer.STATE_BUFFERING: | |
| handlerUpd.removeCallbacks(runnableUpd); | |
| name = "onBuffering"; | |
| break; | |
| case ExoPlayer.STATE_ENDED: | |
| handlerUpd.removeCallbacks(runnableUpd); | |
| name = "onCompletion"; | |
| break; | |
| case ExoPlayer.STATE_IDLE: | |
| handlerUpd.removeCallbacks(runnableUpd); | |
| name = "onIdle"; | |
| break; | |
| case ExoPlayer.STATE_PREPARING: | |
| handlerUpd.removeCallbacks(runnableUpd); | |
| name = "onPrepared"; | |
| break; | |
| case ExoPlayer.STATE_READY: | |
| name = "onReady"; | |
| handlerUpd.postDelayed(runnableUpd, 1000); | |
| break; | |
| default: | |
| name = "onUnknown"; | |
| handlerUpd.removeCallbacks(runnableUpd); | |
| break; | |
| } | |
| final String finalText = text + name; | |
| javaCallBack("{'name':'" + name + "','value':'" + playWhenReady + "'}"); | |
| activity.runOnUiThread(new Runnable() { | |
| @Override | |
| public void run() { | |
| playerStateTextView.setText(finalText); | |
| } | |
| }); | |
| updateButtonVisibilities(); | |
| } | |
| @Override | |
| public void onError(Exception e) { | |
| if (e instanceof UnsupportedDrmException) { | |
| // Special case DRM failures. | |
| UnsupportedDrmException unsupportedDrmException = (UnsupportedDrmException) e; | |
| String stringId = Util.SDK_INT < 18 ? "drm_error_not_supported" | |
| : unsupportedDrmException.reason == UnsupportedDrmException.REASON_UNSUPPORTED_SCHEME | |
| ? "drm_error_unsupported_scheme" : "drm_error_unknown"; | |
| Toast.makeText(getApplicationContext(), stringId, Toast.LENGTH_LONG).show(); | |
| } | |
| playerNeedsPrepare = true; | |
| updateButtonVisibilities(); | |
| showControls(); | |
| javaCallBack("{'name':'" + "onError" + "','value':'" + e.getMessage() + "'}"); | |
| } | |
| @Override | |
| public void onVideoSizeChanged(final int width, final int height, final float pixelWidthAspectRatio) { | |
| activity.runOnUiThread(new Runnable() { | |
| @Override | |
| public void run() { | |
| shutterView.setVisibility(View.GONE); | |
| videoFrame.setAspectRatio( | |
| height == 0 ? 1 : (width * pixelWidthAspectRatio) / height); | |
| } | |
| }); | |
| javaCallBack("{'name':'" + "onVideoSizeChanged" + "','value':'" + width+":"+height + "'}"); | |
| } | |
| // User controls | |
| private void updateButtonVisibilities() { | |
| retryButton.setVisibility(playerNeedsPrepare ? View.VISIBLE : View.GONE); | |
| videoButton.setVisibility(haveTracks(NemoPlayer.TYPE_VIDEO) ? View.VISIBLE : View.GONE); | |
| audioButton.setVisibility(haveTracks(NemoPlayer.TYPE_AUDIO) ? View.VISIBLE : View.GONE); | |
| textButton.setVisibility(haveTracks(NemoPlayer.TYPE_TEXT) ? View.VISIBLE : View.GONE); | |
| } | |
| private boolean haveTracks(int type) { | |
| return player != null && player.getTrackCount(type) > 0; | |
| } | |
| public void showVideoPopup(View v) { | |
| PopupMenu popup = new PopupMenu(this, v); | |
| configurePopupWithTracks(popup, null, NemoPlayer.TYPE_VIDEO); | |
| popup.show(); | |
| } | |
| public void showAudioPopup(View v) { | |
| PopupMenu popup = new PopupMenu(this, v); | |
| Menu menu = popup.getMenu(); | |
| menu.add(Menu.NONE, Menu.NONE, Menu.NONE, R.string.enable_background_audio); | |
| final MenuItem backgroundAudioItem = menu.findItem(0); | |
| backgroundAudioItem.setCheckable(true); | |
| backgroundAudioItem.setChecked(enableBackgroundAudio); | |
| OnMenuItemClickListener clickListener = new OnMenuItemClickListener() { | |
| @Override | |
| public boolean onMenuItemClick(MenuItem item) { | |
| if (item == backgroundAudioItem) { | |
| enableBackgroundAudio = !item.isChecked(); | |
| return true; | |
| } | |
| return false; | |
| } | |
| }; | |
| configurePopupWithTracks(popup, clickListener, NemoPlayer.TYPE_AUDIO); | |
| popup.show(); | |
| } | |
| public void showTextPopup(View v) { | |
| PopupMenu popup = new PopupMenu(this, v); | |
| configurePopupWithTracks(popup, null, NemoPlayer.TYPE_TEXT); | |
| popup.show(); | |
| } | |
| public void showVerboseLogPopup(View v) { | |
| PopupMenu popup = new PopupMenu(this, v); | |
| Menu menu = popup.getMenu(); | |
| menu.add(Menu.NONE, 0, Menu.NONE, R.string.logging_normal); | |
| menu.add(Menu.NONE, 1, Menu.NONE, R.string.logging_verbose); | |
| menu.setGroupCheckable(Menu.NONE, true, true); | |
| menu.findItem((VerboseLogUtil.areAllTagsEnabled()) ? 1 : 0).setChecked(true); | |
| popup.setOnMenuItemClickListener(new OnMenuItemClickListener() { | |
| @Override | |
| public boolean onMenuItemClick(MenuItem item) { | |
| if (item.getItemId() == 0) { | |
| VerboseLogUtil.setEnableAllTags(false); | |
| } else { | |
| VerboseLogUtil.setEnableAllTags(true); | |
| } | |
| return true; | |
| } | |
| }); | |
| popup.show(); | |
| } | |
| private void configurePopupWithTracks(PopupMenu popup, | |
| final OnMenuItemClickListener customActionClickListener, | |
| final int trackType) { | |
| if (player == null) { | |
| return; | |
| } | |
| int trackCount = player.getTrackCount(trackType); | |
| if (trackCount == 0) { | |
| return; | |
| } | |
| popup.setOnMenuItemClickListener(new OnMenuItemClickListener() { | |
| @Override | |
| public boolean onMenuItemClick(MenuItem item) { | |
| return (customActionClickListener != null | |
| && customActionClickListener.onMenuItemClick(item)) | |
| || onTrackItemClick(item, trackType); | |
| } | |
| }); | |
| Menu menu = popup.getMenu(); | |
| // ID_OFFSET ensures we avoid clashing with Menu.NONE (which equals 0) | |
| menu.add(MENU_GROUP_TRACKS, NemoPlayer.DISABLED_TRACK + ID_OFFSET, Menu.NONE, R.string.off); | |
| if (trackCount == 1 && TextUtils.isEmpty(player.getTrackName(trackType, 0))) { | |
| menu.add(MENU_GROUP_TRACKS, NemoPlayer.PRIMARY_TRACK + ID_OFFSET, Menu.NONE, R.string.on); | |
| } else { | |
| for (int i = 0; i < trackCount; i++) { | |
| menu.add(MENU_GROUP_TRACKS, i + ID_OFFSET, Menu.NONE, player.getTrackName(trackType, i)); | |
| } | |
| } | |
| menu.setGroupCheckable(MENU_GROUP_TRACKS, true, true); | |
| menu.findItem(player.getSelectedTrackIndex(trackType) + ID_OFFSET).setChecked(true); | |
| } | |
| private boolean onTrackItemClick(MenuItem item, int type) { | |
| if (player == null || item.getGroupId() != MENU_GROUP_TRACKS) { | |
| return false; | |
| } | |
| player.selectTrack(type, item.getItemId() - ID_OFFSET); | |
| return true; | |
| } | |
| private void toggleControlsVisibility() { | |
| if (mediaController.isShowing()) { | |
| mediaController.hide(); | |
| debugRootView.setVisibility(View.GONE); | |
| } else { | |
| showControls(); | |
| } | |
| } | |
| private void showControls() { | |
| // mediaController.show(0); | |
| // debugRootView.setVisibility(View.VISIBLE); | |
| } | |
| // NemoPlayer.CaptionListener implementation | |
| @Override | |
| public void onCues(List<Cue> cues) { | |
| subtitleLayout.setCues(cues); | |
| } | |
| // NemoPlayer.MetadataListener implementation | |
| @Override | |
| public void onId3Metadata(Map<String, Object> metadata) { | |
| for (Map.Entry<String, Object> entry : metadata.entrySet()) { | |
| if (TxxxMetadata.TYPE.equals(entry.getKey())) { | |
| TxxxMetadata txxxMetadata = (TxxxMetadata) entry.getValue(); | |
| Log.i(TAG, String.format("ID3 TimedMetadata %s: description=%s, value=%s", | |
| TxxxMetadata.TYPE, txxxMetadata.description, txxxMetadata.value)); | |
| } else if (PrivMetadata.TYPE.equals(entry.getKey())) { | |
| PrivMetadata privMetadata = (PrivMetadata) entry.getValue(); | |
| Log.i(TAG, String.format("ID3 TimedMetadata %s: owner=%s", | |
| PrivMetadata.TYPE, privMetadata.owner)); | |
| } else if (GeobMetadata.TYPE.equals(entry.getKey())) { | |
| GeobMetadata geobMetadata = (GeobMetadata) entry.getValue(); | |
| Log.i(TAG, String.format("ID3 TimedMetadata %s: mimeType=%s, filename=%s, description=%s", | |
| GeobMetadata.TYPE, geobMetadata.mimeType, geobMetadata.filename, | |
| geobMetadata.description)); | |
| } else { | |
| Log.i(TAG, String.format("ID3 TimedMetadata %s", entry.getKey())); | |
| } | |
| } | |
| } | |
| // SurfaceHolder.Callback implementation | |
| @Override | |
| public void surfaceCreated(SurfaceHolder holder) { | |
| if (player != null) { | |
| player.setSurface(holder.getSurface()); | |
| } | |
| } | |
| @Override | |
| public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { | |
| // Do nothing. | |
| } | |
| @Override | |
| public void surfaceDestroyed(SurfaceHolder holder) { | |
| if (player != null) { | |
| player.blockingClearSurface(); | |
| } | |
| } | |
| private void configureSubtitleView() { | |
| CaptionStyleCompat captionStyle; | |
| float captionFontScale; | |
| if (Util.SDK_INT >= 19) { | |
| captionStyle = getUserCaptionStyleV19(); | |
| captionFontScale = getUserCaptionFontScaleV19(); | |
| } else { | |
| captionStyle = CaptionStyleCompat.DEFAULT; | |
| captionFontScale = 1.0f; | |
| } | |
| subtitleLayout.setStyle(captionStyle); | |
| subtitleLayout.setFontScale(captionFontScale); | |
| } | |
| @TargetApi(19) | |
| private float getUserCaptionFontScaleV19() { | |
| CaptioningManager captioningManager = | |
| (CaptioningManager) getSystemService(Context.CAPTIONING_SERVICE); | |
| return captioningManager.getFontScale(); | |
| } | |
| @TargetApi(19) | |
| private CaptionStyleCompat getUserCaptionStyleV19() { | |
| CaptioningManager captioningManager = | |
| (CaptioningManager) getSystemService(Context.CAPTIONING_SERVICE); | |
| return CaptionStyleCompat.createFromCaptionStyle(captioningManager.getUserStyle()); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment