/*
* Copyright (C) 2015 Google Inc. All Rights Reserved.
*
* 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.google.android.libraries.cast.companionlibrary.cast.tracks.ui;
import com.google.android.gms.cast.MediaInfo;
import com.google.android.gms.cast.MediaTrack;
import com.google.android.libraries.cast.companionlibrary.R;
import com.google.android.libraries.cast.companionlibrary.cast.VideoCastManager;
import com.google.android.libraries.cast.companionlibrary.utils.Utils;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ListView;
import android.widget.TabHost;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
/**
* A dialog to show the available tracks (Text and Audio) for user to select.
*/
public class TracksChooserDialog extends DialogFragment {
private VideoCastManager mCastManager;
private long[] mActiveTracks = null;
private MediaInfo mMediaInfo;
private TracksListAdapter mTextAdapter;
private TracksListAdapter mAudioVideoAdapter;
private List<MediaTrack> mTextTracks = new ArrayList<>();
private List<MediaTrack> mAudioTracks = new ArrayList<>();
private List<MediaTrack> mVideoTracks = new ArrayList<>();
private static final long TEXT_TRACK_NONE_ID = -1;
private int mSelectedTextPosition = 0;
private int mSelectedAudioPosition = -1;
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater();
// since dialog doesn't expose its root view at this point (doesn't exist yet), we cannot
// attach to the unknown eventual parent, so we need to pass null for the rootView parameter
// of the inflate() method
@SuppressLint("InflateParams")
View view = inflater.inflate(R.layout.custom_tracks_dialog_layout, null);
setUpView(view);
builder.setView(view)
.setPositiveButton(getString(R.string.ccl_ok),
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
List<MediaTrack> selectedTracks = new ArrayList<>();
MediaTrack textTrack = mTextAdapter.getSelectedTrack();
if (textTrack.getId() != TEXT_TRACK_NONE_ID) {
selectedTracks.add(textTrack);
}
MediaTrack audioVideoTrack = mAudioVideoAdapter.getSelectedTrack();
if (audioVideoTrack != null) {
selectedTracks.add(audioVideoTrack);
}
// If there is any video tracks at all, we just add the currently
// selected one, we do not offer a choice to user to select a
// video track in this dialog
if (!mVideoTracks.isEmpty()) {
boolean foundMatch = false;
for (MediaTrack videoTrack : mVideoTracks) {
for (Long activeTrackId : mCastManager
.getActiveTrackIds()) {
if (videoTrack.getId() == activeTrackId) {
// we found an active video track
foundMatch = true;
selectedTracks.add(videoTrack);
break;
}
}
if (foundMatch) {
break;
}
}
}
mCastManager.notifyTracksSelectedListeners(selectedTracks);
TracksChooserDialog.this.getDialog().cancel();
}
})
.setNegativeButton(R.string.ccl_cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
TracksChooserDialog.this.getDialog().cancel();
}
})
.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
TracksChooserDialog.this.getDialog().cancel();
}
});
return builder.create();
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
Bundle mediaWrapper = getArguments().getBundle(VideoCastManager.EXTRA_MEDIA);
mMediaInfo = Utils.bundleToMediaInfo(mediaWrapper);
mCastManager = VideoCastManager.getInstance();
mActiveTracks = mCastManager.getActiveTrackIds();
List<MediaTrack> allTracks = mMediaInfo.getMediaTracks();
if (allTracks == null || allTracks.isEmpty()) {
Utils.showToast(getActivity(), R.string.ccl_caption_no_tracks_available);
dismiss();
}
}
/**
* This is to get around the following bug:
* https://code.google.com/p/android/issues/detail?id=17423
*/
@Override
public void onDestroyView() {
if (getDialog() != null && getRetainInstance()) {
getDialog().setDismissMessage(null);
}
super.onDestroyView();
}
private void setUpView(View view) {
ListView listView1 = (ListView) view.findViewById(R.id.listview1);
ListView listView2 = (ListView) view.findViewById(R.id.listview2);
TextView textEmptyMessageView = (TextView) view.findViewById(R.id.text_empty_message);
TextView audioEmptyMessageView = (TextView) view.findViewById(R.id.audio_empty_message);
partitionTracks();
mTextAdapter = new TracksListAdapter(getActivity(), R.layout.tracks_row_layout,
mTextTracks, mSelectedTextPosition);
mAudioVideoAdapter = new TracksListAdapter(getActivity(), R.layout.tracks_row_layout,
mAudioTracks, mSelectedAudioPosition);
listView1.setAdapter(mTextAdapter);
listView2.setAdapter(mAudioVideoAdapter);
TabHost tabs = (TabHost) view.findViewById(R.id.tabhost);
tabs.setup();
// create tab 1
TabHost.TabSpec tab1 = tabs.newTabSpec("tab1");
if (mTextTracks == null || mTextTracks.isEmpty()) {
listView1.setVisibility(View.INVISIBLE);
tab1.setContent(R.id.text_empty_message);
} else {
textEmptyMessageView.setVisibility(View.INVISIBLE);
tab1.setContent(R.id.listview1);
}
tab1.setIndicator(getString(R.string.ccl_caption_subtitles));
tabs.addTab(tab1);
// create tab 2
TabHost.TabSpec tab2 = tabs.newTabSpec("tab2");
if (mAudioTracks == null || mAudioTracks.isEmpty()) {
listView2.setVisibility(View.INVISIBLE);
tab2.setContent(R.id.audio_empty_message);
} else {
audioEmptyMessageView.setVisibility(View.INVISIBLE);
tab2.setContent(R.id.listview2);
}
tab2.setIndicator(getString(R.string.ccl_caption_audio));
tabs.addTab(tab2);
}
private MediaTrack buildNoneTrack() {
return new MediaTrack.Builder(TEXT_TRACK_NONE_ID, MediaTrack.TYPE_TEXT)
.setName(getString(R.string.ccl_none))
.setSubtype(MediaTrack.SUBTYPE_CAPTIONS)
.setContentId("").build();
}
/**
* This method loops through the tracks and partitions them into a group of Text tracks and a
* group of Audio tracks, and skips over the Video tracks.
*/
private void partitionTracks() {
List<MediaTrack> allTracks = mMediaInfo.getMediaTracks();
mAudioTracks.clear();
mTextTracks.clear();
mVideoTracks.clear();
mTextTracks.add(buildNoneTrack());
mSelectedTextPosition = 0;
mSelectedAudioPosition = -1;
if (allTracks != null) {
int textPosition = 1; /* start from 1 since we have a NONE selection at the beginning */
int audioPosition = 0;
for (MediaTrack track : allTracks) {
switch (track.getType()) {
case MediaTrack.TYPE_TEXT:
mTextTracks.add(track);
if (mActiveTracks != null) {
for (long mActiveTrack : mActiveTracks) {
if (mActiveTrack == track.getId()) {
mSelectedTextPosition = textPosition;
}
}
}
textPosition++;
break;
case MediaTrack.TYPE_AUDIO:
mAudioTracks.add(track);
if (mActiveTracks != null) {
for (long mActiveTrack : mActiveTracks) {
if (mActiveTrack == track.getId()) {
mSelectedAudioPosition = audioPosition;
}
}
}
audioPosition++;
break;
case MediaTrack.TYPE_VIDEO:
mVideoTracks.add(track);
}
}
}
}
/**
* Call this static method to create a new instance of the dialog.
*/
public static TracksChooserDialog newInstance(MediaInfo mediaInfo) {
TracksChooserDialog fragment = new TracksChooserDialog();
Bundle bundle = new Bundle();
bundle.putBundle(VideoCastManager.EXTRA_MEDIA, Utils.mediaInfoToBundle(mediaInfo));
fragment.setArguments(bundle);
return fragment;
}
}