Java tutorial
/***************************************************************************** * MainTvActivity.java ***************************************************************************** * Copyright 2014-2015 VLC authors, VideoLAN and VideoLabs * Author: Geoffrey Mtais * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ package org.videolan.vlc.gui.tv; import android.annotation.TargetApi; import android.app.Activity; import android.app.FragmentManager; import android.content.Intent; import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.graphics.drawable.Drawable; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.support.v17.leanback.app.BackgroundManager; import android.support.v17.leanback.app.BrowseFragment; import android.support.v17.leanback.widget.ArrayObjectAdapter; import android.support.v17.leanback.widget.HeaderItem; import android.support.v17.leanback.widget.ListRow; import android.support.v17.leanback.widget.ListRowPresenter; import android.support.v17.leanback.widget.OnItemViewClickedListener; import android.support.v17.leanback.widget.OnItemViewSelectedListener; import android.support.v17.leanback.widget.Presenter; import android.support.v17.leanback.widget.Row; import android.support.v17.leanback.widget.RowPresenter; import android.support.v4.util.ArrayMap; import android.view.KeyEvent; import android.view.View; import android.view.View.OnClickListener; import android.widget.ProgressBar; import org.videolan.libvlc.Media; import org.videolan.libvlc.MediaPlayer; import org.videolan.medialibrary.Medialibrary; import org.videolan.medialibrary.Tools; import org.videolan.medialibrary.interfaces.MediaUpdatedCb; import org.videolan.medialibrary.media.MediaWrapper; import org.videolan.vlc.PlaybackService; import org.videolan.vlc.R; import org.videolan.vlc.RecommendationsService; import org.videolan.vlc.StartActivity; import org.videolan.vlc.VLCApplication; import org.videolan.vlc.gui.helpers.AudioUtil; import org.videolan.vlc.gui.preferences.PreferencesActivity; import org.videolan.vlc.gui.preferences.PreferencesFragment; import org.videolan.vlc.gui.tv.audioplayer.AudioPlayerActivity; import org.videolan.vlc.gui.tv.browser.BaseTvActivity; import org.videolan.vlc.gui.tv.browser.MusicFragment; import org.videolan.vlc.gui.tv.browser.VerticalGridActivity; import org.videolan.vlc.media.MediaDatabase; import org.videolan.vlc.media.MediaUtils; import org.videolan.vlc.util.AndroidDevices; import org.videolan.vlc.util.Permissions; import org.videolan.vlc.util.VLCInstance; import java.util.ArrayList; import java.util.List; @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) public class MainTvActivity extends BaseTvActivity implements OnItemViewSelectedListener, OnItemViewClickedListener, OnClickListener, PlaybackService.Callback, MediaUpdatedCb { private static final int NUM_ITEMS_PREVIEW = 5; public static final long HEADER_VIDEO = 0; public static final long HEADER_CATEGORIES = 1; public static final long HEADER_HISTORY = 2; public static final long HEADER_NETWORK = 3; public static final long HEADER_DIRECTORIES = 4; public static final long HEADER_MISC = 5; public static final long ID_SETTINGS = 0; public static final long ID_ABOUT = 1; public static final long ID_LICENCE = 2; private static final int ACTIVITY_RESULT_PREFERENCES = 1; public static final String BROWSER_TYPE = "browser_type"; public static final String TAG = "VLC/MainTvActivity"; private Handler mHandler = new Handler(); protected BrowseFragment mBrowseFragment; private ProgressBar mProgressBar; ArrayObjectAdapter mRowsAdapter = new ArrayObjectAdapter(new ListRowPresenter()); ArrayObjectAdapter mVideoAdapter, mCategoriesAdapter, mHistoryAdapter, mBrowserAdapter, mOtherAdapter; View mRootContainer; final ArrayMap<String, Integer> mVideoIndex = new ArrayMap<>(), mHistoryIndex = new ArrayMap<>(); Drawable mDefaultBackground; Activity mContext; private Object mSelectedItem; private AsyncUpdate mUpdateTask; private CardPresenter.SimpleCard mNowPlayingCard; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (mSettings.getBoolean(PreferencesActivity.AUTO_RESCAN, true) && Permissions.canReadStorage()) mMediaLibrary.reload(); if (!VLCInstance.testCompatibleCPU(this)) { finish(); return; } Permissions.checkReadStoragePermission(this, false); mContext = this; setContentView(R.layout.tv_main); mDefaultBackground = getResources().getDrawable(R.drawable.background); final FragmentManager fragmentManager = getFragmentManager(); mBrowseFragment = (BrowseFragment) fragmentManager.findFragmentById(R.id.browse_fragment); mProgressBar = (ProgressBar) findViewById(R.id.tv_main_progress); // Set display parameters for the BrowseFragment mBrowseFragment.setHeadersState(BrowseFragment.HEADERS_ENABLED); mBrowseFragment.setTitle(getString(R.string.app_name)); mBrowseFragment.setBadgeDrawable(getResources().getDrawable(R.drawable.icon)); // add a listener for selected items mBrowseFragment.setOnItemViewClickedListener(this); mBrowseFragment.setOnItemViewSelectedListener(this); //Enable search feature only if we detect Google Play Services. if (AndroidDevices.hasPlayServices()) { mBrowseFragment.setOnSearchClickedListener(this); // set search icon color mBrowseFragment.setSearchAffordanceColor(getResources().getColor(R.color.orange500)); } mRootContainer = mBrowseFragment.getView(); } @Override public void onConnected(PlaybackService service) { super.onConnected(service); mService.addCallback(this); /* * skip browser and show directly Audio Player if a song is playing */ if (mRowsAdapter.size() == 0 && Permissions.canReadStorage()) update(); else { updateBrowsers(); updateNowPlayingCard(); VLCApplication.runBackground(new Runnable() { @Override public void run() { final MediaWrapper[] history = VLCApplication.getMLInstance().lastMediaPlayed(); mHandler.post(new Runnable() { @Override public void run() { updateHistory(history); } }); } }); } } @Override protected void onStop() { if (mService != null) mService.removeCallback(this); super.onStop(); if (AndroidDevices.isAndroidTv()) { Intent recommendationIntent = new Intent(this, RecommendationsService.class); startService(recommendationIntent); } } protected void onResume() { super.onResume(); mMediaLibrary.setMediaUpdatedCb(this, Medialibrary.FLAG_MEDIA_UPDATED_VIDEO); mBrowseFragment.setBrandColor(getResources().getColor(R.color.orange800)); } protected void onPause() { super.onPause(); mMediaLibrary.removeMediaUpdatedCb(); } @Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { switch (requestCode) { case Permissions.PERMISSION_STORAGE_TAG: { // If request is cancelled, the result arrays are empty. if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { mMediaLibrary.init(this); ((VLCApplication) VLCApplication.getAppContext()).discoverStorages(mMediaLibrary); } else { Permissions.showStoragePermissionDialog(this, false); } return; } // other 'case' lines to check for other // permissions this app might request } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == ACTIVITY_RESULT_PREFERENCES) { if (resultCode == PreferencesActivity.RESULT_RESCAN) { VLCApplication.getMLInstance().reload(); update(); } else if (resultCode == PreferencesActivity.RESULT_RESTART) { Intent intent = getIntent(); intent.setClass(this, StartActivity.class); finish(); startActivity(intent); } } } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if ((keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE || keyCode == KeyEvent.KEYCODE_BUTTON_Y) && mSelectedItem instanceof MediaWrapper) { MediaWrapper media = (MediaWrapper) mSelectedItem; if (media.getType() != MediaWrapper.TYPE_DIR) return false; Intent intent = new Intent(this, DetailsActivity.class); // pass the item information intent.putExtra("media", (MediaWrapper) mSelectedItem); intent.putExtra("item", new MediaItemDetails(media.getTitle(), media.getArtist(), media.getAlbum(), media.getLocation(), media.getArtworkURL())); startActivity(intent); return true; } return super.onKeyDown(keyCode, event); } protected void updateBackground(Drawable drawable) { BackgroundManager.getInstance(this).setDrawable(drawable); } protected void clearBackground() { BackgroundManager.getInstance(this).setDrawable(mDefaultBackground); } public void update() { if (mUpdateTask == null || mUpdateTask.getStatus() == AsyncTask.Status.FINISHED) { mUpdateTask = new AsyncUpdate(); mUpdateTask.execute(); } else { mUpdateTask.AskRefresh(); } } @Override public void onMediaUpdated(final MediaWrapper[] mediaList) { if (mVideoAdapter.size() > NUM_ITEMS_PREVIEW) return; mHandler.post(new Runnable() { @Override public void run() { for (MediaWrapper media : mediaList) if (media != null) updateItem(media); } }); } public void updateItem(MediaWrapper item) { if (mVideoAdapter != null && mVideoIndex != null && item != null) { if (mVideoIndex.containsKey(item.getLocation())) { mVideoAdapter.notifyArrayItemRangeChanged(mVideoIndex.get(item.getLocation()).intValue(), 1); } else { int position = mVideoAdapter.size(); mVideoAdapter.add(position, item); mVideoIndex.put(item.getLocation(), Integer.valueOf(position)); } } if (mHistoryAdapter != null && mHistoryIndex != null && item != null) { if (mHistoryIndex.containsKey(item.getLocation())) { mHistoryAdapter.notifyArrayItemRangeChanged(mHistoryIndex.get(item.getLocation()).intValue(), 1); } } } @Override public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item, RowPresenter.ViewHolder rowViewHolder, Row row) { mSelectedItem = item; } @Override public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item, RowPresenter.ViewHolder rowViewHolder, Row row) { if (row.getId() == HEADER_CATEGORIES) { if (((CardPresenter.SimpleCard) item).getId() == MusicFragment.CATEGORY_NOW_PLAYING) { //NOW PLAYING CARD startActivity(new Intent(this, AudioPlayerActivity.class)); return; } CardPresenter.SimpleCard card = (CardPresenter.SimpleCard) item; Intent intent = new Intent(mContext, VerticalGridActivity.class); intent.putExtra(BROWSER_TYPE, HEADER_CATEGORIES); intent.putExtra(MusicFragment.AUDIO_CATEGORY, card.getId()); startActivity(intent); } else if (row.getId() == HEADER_MISC) { long id = ((CardPresenter.SimpleCard) item).getId(); if (id == ID_SETTINGS) startActivityForResult( new Intent(this, org.videolan.vlc.gui.tv.preferences.PreferencesActivity.class), ACTIVITY_RESULT_PREFERENCES); else if (id == ID_ABOUT) startActivity(new Intent(this, org.videolan.vlc.gui.tv.AboutActivity.class)); else if (id == ID_LICENCE) startActivity(new Intent(this, org.videolan.vlc.gui.tv.LicenceActivity.class)); } else { TvUtil.openMedia(mContext, item, row); } } @Override public void onClick(View v) { Intent intent = new Intent(mContext, SearchActivity.class); startActivity(intent); } public class AsyncUpdate extends AsyncTask<Void, Void, Void> { private boolean askRefresh = false; boolean showHistory; MediaWrapper[] history, videoList; public AsyncUpdate() { } public void AskRefresh() { //Ask for refresh while update is ongoing askRefresh = true; } @Override protected void onPreExecute() { showHistory = mSettings.getBoolean(PreferencesFragment.PLAYBACK_HISTORY, true); mRowsAdapter.clear(); mProgressBar.setVisibility(View.VISIBLE); mHistoryIndex.clear(); //Video Section mVideoIndex.clear(); } @Override protected Void doInBackground(Void... params) { videoList = mMediaLibrary.getVideos(); if (showHistory) history = VLCApplication.getMLInstance().lastMediaPlayed(); return null; } @Override protected void onPostExecute(Void result) { mVideoAdapter = new ArrayObjectAdapter(new CardPresenter(mContext)); final HeaderItem videoHeader = new HeaderItem(HEADER_VIDEO, getString(R.string.video)); // Empty item to launch grid activity mVideoAdapter.add(new CardPresenter.SimpleCard(0, "All videos", R.drawable.ic_video_collection_big)); // Update video section if (!Tools.isArrayEmpty(videoList)) { final int size = Math.min(NUM_ITEMS_PREVIEW, videoList.length); mRootContainer.post(new Runnable() { @Override public void run() { MediaWrapper item; for (int i = 0; i < size; ++i) { item = videoList[i]; mVideoAdapter.add(item); mVideoIndex.put(item.getLocation(), Integer.valueOf(i)); } } }); mVideoAdapter.notifyArrayItemRangeChanged(0, size); } mRowsAdapter.add(new ListRow(videoHeader, mVideoAdapter)); //Music sections mCategoriesAdapter = new ArrayObjectAdapter(new CardPresenter(mContext)); final HeaderItem musicHeader = new HeaderItem(HEADER_CATEGORIES, getString(R.string.audio)); updateNowPlayingCard(); mCategoriesAdapter.add(new CardPresenter.SimpleCard(MusicFragment.CATEGORY_ARTISTS, getString(R.string.artists), R.drawable.ic_artist_big)); mCategoriesAdapter.add(new CardPresenter.SimpleCard(MusicFragment.CATEGORY_ALBUMS, getString(R.string.albums), R.drawable.ic_album_big)); mCategoriesAdapter.add(new CardPresenter.SimpleCard(MusicFragment.CATEGORY_GENRES, getString(R.string.genres), R.drawable.ic_genre_big)); mCategoriesAdapter.add(new CardPresenter.SimpleCard(MusicFragment.CATEGORY_SONGS, getString(R.string.songs), R.drawable.ic_song_big)); mRowsAdapter.add(new ListRow(musicHeader, mCategoriesAdapter)); //History if (showHistory && !Tools.isArrayEmpty(history)) { mHistoryAdapter = new ArrayObjectAdapter(new CardPresenter(mContext)); final HeaderItem historyHeader = new HeaderItem(HEADER_HISTORY, getString(R.string.history)); updateHistory(history); mRowsAdapter.add(new ListRow(historyHeader, mHistoryAdapter)); } //Browser section mBrowserAdapter = new ArrayObjectAdapter(new CardPresenter(mContext)); final HeaderItem browserHeader = new HeaderItem(HEADER_NETWORK, getString(R.string.browsing)); updateBrowsers(); mRowsAdapter.add(new ListRow(browserHeader, mBrowserAdapter)); mOtherAdapter = new ArrayObjectAdapter(new CardPresenter(mContext)); final HeaderItem miscHeader = new HeaderItem(HEADER_MISC, getString(R.string.other)); mOtherAdapter.add(new CardPresenter.SimpleCard(ID_SETTINGS, getString(R.string.preferences), R.drawable.ic_menu_preferences_big)); mOtherAdapter.add( new CardPresenter.SimpleCard(ID_ABOUT, getString(R.string.about), R.drawable.ic_tv_icon_small)); mOtherAdapter.add(new CardPresenter.SimpleCard(ID_LICENCE, getString(R.string.licence), R.drawable.ic_tv_icon_small)); mRowsAdapter.add(new ListRow(miscHeader, mOtherAdapter)); mBrowseFragment.setAdapter(mRowsAdapter); mProgressBar.setVisibility(View.GONE); if (askRefresh) { //in case new event occurred while loading view mHandler.post(new Runnable() { @Override public void run() { refresh(); } }); } } } private void updateHistory(MediaWrapper[] history) { if (mHistoryAdapter == null || history == null) return; mHistoryAdapter.clear(); if (!mSettings.getBoolean(PreferencesFragment.PLAYBACK_HISTORY, true)) return; MediaWrapper item; for (int i = 0; i < history.length; ++i) { item = history[i]; mHistoryAdapter.add(item); mHistoryIndex.put(item.getLocation(), Integer.valueOf(i)); } } private void updateBrowsers() { if (mBrowserAdapter == null) return; mBrowserAdapter.clear(); List<MediaWrapper> directories = AndroidDevices.getMediaDirectoriesList(); if (!AndroidDevices.showInternalStorage()) directories.remove(0); for (MediaWrapper directory : directories) mBrowserAdapter.add(new CardPresenter.SimpleCard(HEADER_DIRECTORIES, directory.getTitle(), R.drawable.ic_menu_folder_big, directory.getUri())); if (AndroidDevices.hasLANConnection()) { final ArrayList<MediaWrapper> favs = MediaDatabase.getInstance().getAllNetworkFav(); mBrowserAdapter.add(new CardPresenter.SimpleCard(HEADER_NETWORK, getString(R.string.network_browsing), R.drawable.ic_menu_network_big)); if (!favs.isEmpty()) { for (MediaWrapper fav : favs) { fav.setDescription(fav.getUri().getScheme()); mBrowserAdapter.add(fav); } } } mBrowserAdapter.notifyArrayItemRangeChanged(0, mBrowserAdapter.size()); } protected void refresh() { mMediaLibrary.reload(); } @Override protected void onNetworkUpdated() { updateBrowsers(); } @Override protected void onExternelDeviceChange() { updateBrowsers(); } @Override public void updateProgress() { } @Override public void onMediaEvent(Media.Event event) { } @Override public void onMediaPlayerEvent(MediaPlayer.Event event) { switch (event.type) { case MediaPlayer.Event.Opening: updateNowPlayingCard(); break; case MediaPlayer.Event.Stopped: if (mNowPlayingCard != null) mCategoriesAdapter.remove(mNowPlayingCard); break; } } public void updateNowPlayingCard() { if (mService == null) return; if ((!mService.hasMedia() || mService.canSwitchToVideo()) && mNowPlayingCard != null) { mCategoriesAdapter.removeItems(0, 1); mNowPlayingCard = null; } else if (mService.hasMedia()) { MediaWrapper mw = mService.getCurrentMediaWrapper(); String display = MediaUtils.getMediaTitle(mw) + " - " + MediaUtils.getMediaReferenceArtist(MainTvActivity.this, mw); Bitmap cover = AudioUtil.getCover(MainTvActivity.this, mw, VLCApplication.getAppResources().getDimensionPixelSize(R.dimen.grid_card_thumb_width)); if (mNowPlayingCard == null) { if (cover != null) mNowPlayingCard = new CardPresenter.SimpleCard(MusicFragment.CATEGORY_NOW_PLAYING, display, cover); else mNowPlayingCard = new CardPresenter.SimpleCard(MusicFragment.CATEGORY_NOW_PLAYING, display, R.drawable.ic_tv_icon_small); mCategoriesAdapter.add(0, mNowPlayingCard); } else { mNowPlayingCard.setId(MusicFragment.CATEGORY_NOW_PLAYING); mNowPlayingCard.setName(display); if (cover != null) mNowPlayingCard.setImage(cover); else mNowPlayingCard.setImageId(R.drawable.ic_tv_icon_small); } mCategoriesAdapter.notifyArrayItemRangeChanged(0, 1); } } }