| /* |
| * Copyright (C) 2013 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.android.supportv7.media; |
| |
| import android.app.PendingIntent; |
| import android.content.ComponentName; |
| import android.content.Context; |
| import android.content.DialogInterface; |
| import android.content.Intent; |
| import android.net.Uri; |
| import android.os.Build; |
| import android.os.Bundle; |
| import android.os.Environment; |
| import android.os.Handler; |
| import android.os.SystemClock; |
| import android.provider.Settings; |
| import android.support.v4.media.session.MediaSessionCompat; |
| import android.util.Log; |
| import android.view.KeyEvent; |
| import android.view.Menu; |
| import android.view.MenuItem; |
| import android.view.View; |
| import android.view.View.OnClickListener; |
| import android.view.ViewGroup; |
| import android.widget.AdapterView; |
| import android.widget.AdapterView.OnItemClickListener; |
| import android.widget.ArrayAdapter; |
| import android.widget.CheckBox; |
| import android.widget.ImageButton; |
| import android.widget.ListView; |
| import android.widget.SeekBar; |
| import android.widget.SeekBar.OnSeekBarChangeListener; |
| import android.widget.TabHost; |
| import android.widget.TabHost.OnTabChangeListener; |
| import android.widget.TabHost.TabSpec; |
| import android.widget.TextView; |
| |
| import androidx.annotation.NonNull; |
| import androidx.appcompat.app.AppCompatActivity; |
| import androidx.concurrent.futures.CallbackToFutureAdapter; |
| import androidx.core.view.MenuItemCompat; |
| import androidx.fragment.app.FragmentManager; |
| import androidx.mediarouter.app.MediaRouteActionProvider; |
| import androidx.mediarouter.app.MediaRouteControllerDialog; |
| import androidx.mediarouter.app.MediaRouteControllerDialogFragment; |
| import androidx.mediarouter.app.MediaRouteDialogFactory; |
| import androidx.mediarouter.app.MediaRouteDiscoveryFragment; |
| import androidx.mediarouter.media.MediaControlIntent; |
| import androidx.mediarouter.media.MediaItemStatus; |
| import androidx.mediarouter.media.MediaRouteSelector; |
| import androidx.mediarouter.media.MediaRouter; |
| import androidx.mediarouter.media.MediaRouter.Callback; |
| import androidx.mediarouter.media.MediaRouter.ProviderInfo; |
| import androidx.mediarouter.media.MediaRouter.RouteInfo; |
| import androidx.mediarouter.media.MediaRouterParams; |
| |
| import com.example.android.supportv7.R; |
| |
| import java.io.File; |
| |
| /** |
| * <h3>Media Router Support Activity</h3> |
| * |
| * <p> |
| * This demonstrates how to use the {@link MediaRouter} API to build an |
| * application that allows the user to send content to various rendering |
| * targets. |
| * </p> |
| */ |
| public class SampleMediaRouterActivity extends AppCompatActivity { |
| private static final String TAG = "SampleMediaRouterActivity"; |
| private static final String DISCOVERY_FRAGMENT_TAG = "DiscoveryFragment"; |
| private static final boolean ENABLE_DEFAULT_CONTROL_CHECK_BOX = false; |
| |
| private MediaRouter mMediaRouter; |
| private MediaRouteSelector mSelector; |
| private LibraryAdapter mLibraryItems; |
| private PlaylistAdapter mPlayListItems; |
| private TextView mInfoTextView; |
| private ListView mLibraryView; |
| private ListView mPlayListView; |
| private CheckBox mUseDefaultControlCheckBox; |
| private ImageButton mPauseResumeButton; |
| private ImageButton mStopButton; |
| private SeekBar mSeekBar; |
| private boolean mSeeking; |
| |
| @SuppressWarnings("deprecation") |
| private final Handler mHandler = new Handler(); |
| private final Runnable mUpdateSeekRunnable = new Runnable() { |
| @Override |
| public void run() { |
| updateProgress(); |
| // update Ui every 1 second |
| mHandler.postDelayed(this, 1000); |
| } |
| }; |
| |
| private final SessionManager mSessionManager = new SessionManager("app"); |
| private Player mPlayer; |
| |
| private final MediaRouter.Callback mMediaRouterCB = new MediaRouter.Callback() { |
| // Return a custom callback that will simply log all of the route events |
| // for demonstration purposes. |
| @Override |
| public void onRouteAdded(MediaRouter router, RouteInfo route) { |
| Log.d(TAG, "onRouteAdded: route=" + route); |
| } |
| |
| @Override |
| public void onRouteChanged(MediaRouter router, RouteInfo route) { |
| Log.d(TAG, "onRouteChanged: route=" + route); |
| } |
| |
| @Override |
| public void onRouteRemoved(MediaRouter router, RouteInfo route) { |
| Log.d(TAG, "onRouteRemoved: route=" + route); |
| } |
| |
| @Override |
| public void onRouteSelected(@NonNull MediaRouter router, |
| @NonNull RouteInfo selectedRoute, int reason, @NonNull RouteInfo requestedRoute) { |
| Log.d(TAG, "onRouteSelected: requestedRoute=" + requestedRoute |
| + ", route=" + selectedRoute + ", reason=" + reason); |
| |
| mPlayer = Player.create(SampleMediaRouterActivity.this, selectedRoute, mMediaSession); |
| if (isPresentationApiSupported()) { |
| mPlayer.updatePresentation(); |
| } |
| mSessionManager.setPlayer(mPlayer); |
| if (reason == MediaRouter.UNSELECT_REASON_STOPPED) { |
| mSessionManager.stop(); |
| } else { |
| mSessionManager.unsuspend(); |
| } |
| |
| updateUi(); |
| } |
| |
| @Override |
| public void onRouteUnselected(MediaRouter router, RouteInfo route) { |
| Log.d(TAG, "onRouteUnselected: route=" + route); |
| mMediaSession.setActive(false); |
| |
| PlaylistItem item = getCheckedPlaylistItem(); |
| if (item != null) { |
| long pos = item.getPosition() + (mSessionManager.isPaused() ? |
| 0 : (SystemClock.elapsedRealtime() - item.getTimestamp())); |
| mSessionManager.suspend(pos); |
| } |
| if (isPresentationApiSupported()) { |
| mPlayer.updatePresentation(); |
| } |
| mPlayer.release(); |
| } |
| |
| @Override |
| public void onRouteVolumeChanged(MediaRouter router, RouteInfo route) { |
| Log.d(TAG, "onRouteVolumeChanged: route=" + route); |
| } |
| |
| @Override |
| public void onRoutePresentationDisplayChanged( |
| MediaRouter router, RouteInfo route) { |
| Log.d(TAG, "onRoutePresentationDisplayChanged: route=" + route); |
| if (isPresentationApiSupported()) { |
| mPlayer.updatePresentation(); |
| } |
| } |
| |
| @Override |
| public void onProviderAdded(MediaRouter router, ProviderInfo provider) { |
| Log.d(TAG, "onRouteProviderAdded: provider=" + provider); |
| } |
| |
| @Override |
| public void onProviderRemoved(MediaRouter router, ProviderInfo provider) { |
| Log.d(TAG, "onRouteProviderRemoved: provider=" + provider); |
| } |
| |
| @Override |
| public void onProviderChanged(MediaRouter router, ProviderInfo provider) { |
| Log.d(TAG, "onRouteProviderChanged: provider=" + provider); |
| } |
| |
| private boolean isPresentationApiSupported() { |
| return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1; |
| } |
| }; |
| |
| private MediaSessionCompat mMediaSession; |
| private ComponentName mEventReceiver; |
| private PendingIntent mMediaPendingIntent; |
| |
| @Override |
| protected void onCreate(Bundle savedInstanceState) { |
| // Be sure to call the super class. |
| super.onCreate(savedInstanceState); |
| |
| // Need overlay permission for emulating remote display. |
| if (Build.VERSION.SDK_INT >= 23 && !Settings.canDrawOverlays(this)) { |
| Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, |
| Uri.parse("package:" + getPackageName())); |
| startActivityForResult(intent, 0); |
| } |
| |
| // Get the media router service. |
| mMediaRouter = MediaRouter.getInstance(this); |
| |
| mMediaRouter.setRouterParams(getRouterParams()); |
| |
| // Create a route selector for the type of routes that we care about. |
| mSelector = new MediaRouteSelector.Builder() |
| .addControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK) |
| .addControlCategory(SampleMediaRouteProvider.CATEGORY_SAMPLE_ROUTE) |
| .build(); |
| |
| mMediaRouter.setOnPrepareTransferListener((fromRoute, toRoute) -> { |
| Log.d(TAG, "onPrepareTransfer: from=" + fromRoute.getId() |
| + ", to=" + toRoute.getId()); |
| return CallbackToFutureAdapter.getFuture(completer -> { |
| completer.set(null); |
| return "onPrepareTransfer"; |
| }); |
| }); |
| |
| // Add a fragment to take care of media route discovery. |
| // This fragment automatically adds or removes a callback whenever the activity |
| // is started or stopped. |
| FragmentManager fm = getSupportFragmentManager(); |
| DiscoveryFragment fragment = (DiscoveryFragment) fm.findFragmentByTag( |
| DISCOVERY_FRAGMENT_TAG); |
| if (fragment == null) { |
| fragment = new DiscoveryFragment(); |
| fm.beginTransaction() |
| .add(fragment, DISCOVERY_FRAGMENT_TAG) |
| .commit(); |
| } |
| fragment.setCallback(mMediaRouterCB); |
| fragment.setRouteSelector(mSelector); |
| |
| // Populate an array adapter with streaming media items. |
| String[] mediaNames = getResources().getStringArray(R.array.media_names); |
| String[] mediaUris = getResources().getStringArray(R.array.media_uris); |
| String[] mediaMimes = getResources().getStringArray(R.array.media_mimes); |
| mLibraryItems = new LibraryAdapter(); |
| for (int i = 0; i < mediaNames.length; i++) { |
| mLibraryItems.add(new MediaItem( |
| "[streaming] " + mediaNames[i], Uri.parse(mediaUris[i]), mediaMimes[i])); |
| } |
| |
| // Scan local external storage directory for media files. |
| File externalDir = Environment.getExternalStorageDirectory(); |
| if (externalDir != null) { |
| File list[] = externalDir.listFiles(); |
| if (list != null) { |
| for (int i = 0; i < list.length; i++) { |
| String filename = list[i].getName(); |
| if (filename.matches(".*\\.(m4v|mp4)")) { |
| mLibraryItems.add(new MediaItem("[local] " + filename, |
| Uri.fromFile(list[i]), "video/mp4")); |
| } |
| } |
| } |
| } |
| |
| mPlayListItems = new PlaylistAdapter(); |
| |
| // Initialize the layout. |
| setContentView(R.layout.sample_media_router); |
| |
| TabHost tabHost=(TabHost)findViewById(R.id.tabHost); |
| tabHost.setup(); |
| String tabName = getResources().getString(R.string.library_tab_text); |
| TabSpec spec1=tabHost.newTabSpec(tabName); |
| spec1.setContent(R.id.tab1); |
| spec1.setIndicator(tabName); |
| |
| tabName = getResources().getString(R.string.playlist_tab_text); |
| TabSpec spec2=tabHost.newTabSpec(tabName); |
| spec2.setIndicator(tabName); |
| spec2.setContent(R.id.tab2); |
| |
| tabName = getResources().getString(R.string.info_tab_text); |
| TabSpec spec3=tabHost.newTabSpec(tabName); |
| spec3.setIndicator(tabName); |
| spec3.setContent(R.id.tab3); |
| |
| tabHost.addTab(spec1); |
| tabHost.addTab(spec2); |
| tabHost.addTab(spec3); |
| tabHost.setOnTabChangedListener(new OnTabChangeListener() { |
| @Override |
| public void onTabChanged(String arg0) { |
| updateUi(); |
| } |
| }); |
| |
| mLibraryView = findViewById(R.id.media); |
| mLibraryView.setAdapter(mLibraryItems); |
| mLibraryView.setChoiceMode(ListView.CHOICE_MODE_SINGLE); |
| mLibraryView.setOnItemClickListener(new OnItemClickListener() { |
| @Override |
| public void onItemClick(AdapterView<?> parent, View view, int position, long id) { |
| updateButtons(); |
| } |
| }); |
| |
| mPlayListView = findViewById(R.id.playlist); |
| mPlayListView.setAdapter(mPlayListItems); |
| mPlayListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE); |
| mPlayListView.setOnItemClickListener(new OnItemClickListener() { |
| @Override |
| public void onItemClick(AdapterView<?> parent, View view, int position, long id) { |
| updateButtons(); |
| } |
| }); |
| |
| mInfoTextView = findViewById(R.id.info); |
| |
| mUseDefaultControlCheckBox = findViewById(R.id.custom_control_view_checkbox); |
| if (ENABLE_DEFAULT_CONTROL_CHECK_BOX) { |
| mUseDefaultControlCheckBox.setVisibility(View.VISIBLE); |
| } |
| mPauseResumeButton = (ImageButton)findViewById(R.id.pause_resume_button); |
| mPauseResumeButton.setOnClickListener(new OnClickListener() { |
| @Override |
| public void onClick(View v) { |
| if (mSessionManager.isPaused()) { |
| mSessionManager.resume(); |
| } else { |
| mSessionManager.pause(); |
| } |
| } |
| }); |
| |
| mStopButton = (ImageButton)findViewById(R.id.stop_button); |
| mStopButton.setOnClickListener(new OnClickListener() { |
| @Override |
| public void onClick(View v) { |
| mSessionManager.stop(); |
| } |
| }); |
| |
| mSeekBar = findViewById(R.id.seekbar); |
| mSeekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() { |
| @Override |
| public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { |
| PlaylistItem item = getCheckedPlaylistItem(); |
| if (fromUser && item != null && item.getDuration() > 0) { |
| long pos = progress * item.getDuration() / 100; |
| mSessionManager.seek(item.getItemId(), pos); |
| item.setPosition(pos); |
| item.setTimestamp(SystemClock.elapsedRealtime()); |
| } |
| } |
| @Override |
| public void onStartTrackingTouch(SeekBar seekBar) { |
| mSeeking = true; |
| } |
| @Override |
| public void onStopTrackingTouch(SeekBar seekBar) { |
| mSeeking = false; |
| updateUi(); |
| } |
| }); |
| |
| // Schedule Ui update |
| mHandler.postDelayed(mUpdateSeekRunnable, 1000); |
| |
| // Build the PendingIntent for the remote control client |
| mEventReceiver = new ComponentName(getPackageName(), |
| SampleMediaButtonReceiver.class.getName()); |
| Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); |
| mediaButtonIntent.setComponent(mEventReceiver); |
| mMediaPendingIntent = PendingIntent.getBroadcast(this, 0, mediaButtonIntent, 0); |
| |
| // Create and register the remote control client |
| createMediaSession(); |
| mMediaRouter.setMediaSessionCompat(mMediaSession); |
| |
| // Set up playback manager and player |
| mPlayer = Player.create(SampleMediaRouterActivity.this, |
| mMediaRouter.getSelectedRoute(), mMediaSession); |
| |
| mSessionManager.setPlayer(mPlayer); |
| mSessionManager.setCallback(new SessionManager.Callback() { |
| @Override |
| public void onStatusChanged() { |
| updateUi(); |
| } |
| |
| @Override |
| public void onItemChanged(PlaylistItem item) { |
| } |
| }); |
| |
| updateUi(); |
| } |
| |
| private void createMediaSession() { |
| // Create the MediaSession |
| mMediaSession = new MediaSessionCompat(this, "SampleMediaRouter", mEventReceiver, |
| mMediaPendingIntent); |
| mMediaSession.setCallback(new MediaSessionCompat.Callback() { |
| @Override |
| public boolean onMediaButtonEvent(Intent mediaButtonEvent) { |
| if (mediaButtonEvent != null) { |
| return handleMediaKey( |
| (KeyEvent) mediaButtonEvent.getParcelableExtra(Intent.EXTRA_KEY_EVENT)); |
| } |
| return super.onMediaButtonEvent(mediaButtonEvent); |
| } |
| |
| @Override |
| public void onPlay() { |
| mSessionManager.resume(); |
| } |
| |
| @Override |
| public void onPause() { |
| mSessionManager.pause(); |
| } |
| }); |
| |
| SampleMediaButtonReceiver.setActivity(SampleMediaRouterActivity.this); |
| } |
| |
| public boolean handleMediaKey(KeyEvent event) { |
| if (event != null && event.getAction() == KeyEvent.ACTION_DOWN |
| && event.getRepeatCount() == 0) { |
| switch (event.getKeyCode()) { |
| case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: |
| case KeyEvent.KEYCODE_HEADSETHOOK: |
| { |
| Log.d(TAG, "Received Play/Pause event from RemoteControlClient"); |
| if (mSessionManager.isPaused()) { |
| mSessionManager.resume(); |
| } else { |
| mSessionManager.pause(); |
| } |
| return true; |
| } |
| case KeyEvent.KEYCODE_MEDIA_PLAY: |
| { |
| Log.d(TAG, "Received Play event from RemoteControlClient"); |
| if (mSessionManager.isPaused()) { |
| mSessionManager.resume(); |
| } |
| return true; |
| } |
| case KeyEvent.KEYCODE_MEDIA_PAUSE: |
| { |
| Log.d(TAG, "Received Pause event from RemoteControlClient"); |
| if (!mSessionManager.isPaused()) { |
| mSessionManager.pause(); |
| } |
| return true; |
| } |
| case KeyEvent.KEYCODE_MEDIA_STOP: |
| { |
| Log.d(TAG, "Received Stop event from RemoteControlClient"); |
| mSessionManager.stop(); |
| return true; |
| } |
| default: |
| break; |
| } |
| } |
| return false; |
| } |
| |
| @Override |
| public boolean onKeyDown(int keyCode, KeyEvent event) { |
| return handleMediaKey(event) || super.onKeyDown(keyCode, event); |
| } |
| |
| @Override |
| public boolean onKeyUp(int keyCode, KeyEvent event) { |
| return handleMediaKey(event) || super.onKeyUp(keyCode, event); |
| } |
| |
| @Override |
| public void onStart() { |
| // Be sure to call the super class. |
| super.onStart(); |
| } |
| |
| @Override |
| public void onDestroy() { |
| mSessionManager.stop(); |
| mPlayer.release(); |
| mMediaSession.release(); |
| super.onDestroy(); |
| } |
| |
| @Override |
| public boolean onCreateOptionsMenu(Menu menu) { |
| // Be sure to call the super class. |
| super.onCreateOptionsMenu(menu); |
| |
| // Inflate the menu and configure the media router action provider. |
| getMenuInflater().inflate(R.menu.sample_media_router_menu, menu); |
| |
| MenuItem mediaRouteMenuItem = menu.findItem(R.id.media_route_menu_item); |
| MediaRouteActionProvider mediaRouteActionProvider = |
| (MediaRouteActionProvider) MenuItemCompat.getActionProvider(mediaRouteMenuItem); |
| mediaRouteActionProvider.setRouteSelector(mSelector); |
| mediaRouteActionProvider.setDialogFactory(new MediaRouteDialogFactory() { |
| @Override |
| public MediaRouteControllerDialogFragment onCreateControllerDialogFragment() { |
| return new ControllerDialogFragment(mUseDefaultControlCheckBox); |
| } |
| }); |
| |
| // Return true to show the menu. |
| return true; |
| } |
| |
| private void updateProgress() { |
| // Estimate content position from last status time and elapsed time. |
| // (Note this might be slightly out of sync with remote side, however |
| // it avoids frequent polling the MRP.) |
| int progress = 0; |
| PlaylistItem item = getCheckedPlaylistItem(); |
| if (item != null) { |
| int state = item.getState(); |
| long duration = item.getDuration(); |
| if (duration <= 0) { |
| if (state == MediaItemStatus.PLAYBACK_STATE_PLAYING |
| || state == MediaItemStatus.PLAYBACK_STATE_PAUSED) { |
| mSessionManager.updateStatus(); |
| } |
| } else { |
| long position = item.getPosition(); |
| long timeDelta = mSessionManager.isPaused() ? 0 : |
| (SystemClock.elapsedRealtime() - item.getTimestamp()); |
| progress = (int)(100.0 * (position + timeDelta) / duration); |
| } |
| } |
| mSeekBar.setProgress(progress); |
| } |
| |
| private void updateUi() { |
| updatePlaylist(); |
| updateRouteDescription(); |
| updateButtons(); |
| if (mPlayer != null && mSessionManager != null) { |
| PlaylistItem currentItem = mSessionManager.getCurrentItem(); |
| if (currentItem != null) { |
| mPlayer.updateMetadata(currentItem); |
| int currentItemState = Player.STATE_IDLE; |
| switch(currentItem.getState()) { |
| case MediaItemStatus.PLAYBACK_STATE_PLAYING: |
| currentItemState = Player.STATE_PLAYING; |
| break; |
| case MediaItemStatus.PLAYBACK_STATE_PAUSED: |
| currentItemState = Player.STATE_PAUSED; |
| break; |
| case MediaItemStatus.PLAYBACK_STATE_PENDING: |
| case MediaItemStatus.PLAYBACK_STATE_BUFFERING: |
| currentItemState = Player.STATE_PREPARING_FOR_PLAY; |
| break; |
| } |
| mPlayer.publishState(currentItemState); |
| } |
| } |
| } |
| |
| private void updatePlaylist() { |
| mPlayListItems.clear(); |
| for (PlaylistItem item : mSessionManager.getPlaylist()) { |
| mPlayListItems.add(item); |
| } |
| mPlayListView.invalidate(); |
| } |
| |
| private void updateRouteDescription() { |
| RouteInfo route = mMediaRouter.getSelectedRoute(); |
| mInfoTextView.setText("Currently selected route:" |
| + "\nName: " + route.getName() |
| + "\nProvider: " + route.getProvider().getPackageName()); |
| } |
| |
| private void updateButtons() { |
| // show pause or resume icon depending on current state |
| mPauseResumeButton.setImageResource(mSessionManager.isPaused() ? |
| R.drawable.ic_media_play : R.drawable.ic_media_pause); |
| // only enable seek bar when duration is known |
| PlaylistItem item = getCheckedPlaylistItem(); |
| mSeekBar.setEnabled(item != null && item.getDuration() > 0); |
| } |
| |
| private PlaylistItem getCheckedPlaylistItem() { |
| int count = mPlayListView.getCount(); |
| int index = mPlayListView.getCheckedItemPosition(); |
| if (count > 0) { |
| if (index < 0 || index >= count) { |
| index = 0; |
| mPlayListView.setItemChecked(0, true); |
| } |
| return mPlayListItems.getItem(index); |
| } |
| return null; |
| } |
| |
| public MediaRouterParams getRouterParams() { |
| return new MediaRouterParams.Builder() |
| .setDialogType(MediaRouterParams.DIALOG_TYPE_DEFAULT) |
| .setTransferToLocalEnabled(true) // Phone speaker will be shown when casting. |
| .build(); |
| } |
| |
| /** |
| * Media route discovery fragment. |
| */ |
| public static final class DiscoveryFragment extends MediaRouteDiscoveryFragment { |
| private static final String TAG = "DiscoveryFragment"; |
| private Callback mCallback; |
| |
| public void setCallback(Callback cb) { |
| mCallback = cb; |
| } |
| |
| @Override |
| public Callback onCreateCallback() { |
| return mCallback; |
| } |
| |
| @Override |
| public int onPrepareCallbackFlags() { |
| // Add the CALLBACK_FLAG_UNFILTERED_EVENTS flag to ensure that we will |
| // observe and log all route events including those that are for routes |
| // that do not match our selector. This is only for demonstration purposes |
| // and should not be needed by most applications. |
| return super.onPrepareCallbackFlags() |
| | MediaRouter.CALLBACK_FLAG_UNFILTERED_EVENTS; |
| } |
| } |
| |
| private static final class MediaItem { |
| public final String mName; |
| public final Uri mUri; |
| public final String mMime; |
| |
| public MediaItem(String name, Uri uri, String mime) { |
| mName = name; |
| mUri = uri; |
| mMime = mime; |
| } |
| |
| @Override |
| public String toString() { |
| return mName; |
| } |
| } |
| |
| private final class LibraryAdapter extends ArrayAdapter<MediaItem> { |
| public LibraryAdapter() { |
| super(SampleMediaRouterActivity.this, R.layout.media_item); |
| } |
| |
| @Override |
| public View getView(int position, View convertView, ViewGroup parent) { |
| final View v; |
| if (convertView == null) { |
| v = getLayoutInflater().inflate(R.layout.media_item, null); |
| } else { |
| v = convertView; |
| } |
| |
| final MediaItem item = getItem(position); |
| |
| TextView tv = (TextView)v.findViewById(R.id.item_text); |
| tv.setText(item.mName); |
| |
| ImageButton b = (ImageButton)v.findViewById(R.id.item_action); |
| b.setImageResource(R.drawable.ic_menu_add); |
| b.setTag(item); |
| b.setOnClickListener(new OnClickListener() { |
| @Override |
| public void onClick(View v) { |
| if (item != null) { |
| mSessionManager.add(item.mName, item.mUri, item.mMime); |
| } |
| } |
| }); |
| |
| return v; |
| } |
| } |
| |
| private final class PlaylistAdapter extends ArrayAdapter<PlaylistItem> { |
| public PlaylistAdapter() { |
| super(SampleMediaRouterActivity.this, R.layout.media_item); |
| } |
| |
| @Override |
| public View getView(int position, View convertView, ViewGroup parent) { |
| final View v; |
| if (convertView == null) { |
| v = getLayoutInflater().inflate(R.layout.media_item, null); |
| } else { |
| v = convertView; |
| } |
| |
| final PlaylistItem item = getItem(position); |
| |
| TextView tv = (TextView)v.findViewById(R.id.item_text); |
| tv.setText(item.toString()); |
| |
| ImageButton b = (ImageButton)v.findViewById(R.id.item_action); |
| b.setImageResource(R.drawable.ic_menu_delete); |
| b.setTag(item); |
| b.setOnClickListener(new OnClickListener() { |
| @Override |
| public void onClick(View v) { |
| if (item != null) { |
| mSessionManager.remove(item.getItemId()); |
| } |
| } |
| }); |
| |
| return v; |
| } |
| } |
| |
| /** |
| * Trivial subclass of this activity used to provide another copy of the |
| * same activity using a light theme instead of the dark theme. |
| */ |
| public static class Light extends SampleMediaRouterActivity { |
| } |
| |
| /** |
| * Trivial subclass of this activity used to provide another copy of the |
| * same activity using a light theme with dark action bar instead of the dark theme. |
| */ |
| public static class LightWithDarkActionBar extends SampleMediaRouterActivity { |
| } |
| |
| /** |
| * This will show dynamic group dialog when ther user clicks the media route button. |
| */ |
| public static class DynamicGroupActivity extends SampleMediaRouterActivity { |
| @Override |
| public MediaRouterParams getRouterParams() { |
| return new MediaRouterParams.Builder(super.getRouterParams()) |
| .setDialogType(MediaRouterParams.DIALOG_TYPE_DYNAMIC_GROUP) |
| .build(); |
| } |
| } |
| |
| /** |
| * This pops up the output switcher if run on Android R+ |
| */ |
| public static class OutputSwitcherActivity extends SampleMediaRouterActivity { |
| @Override |
| public MediaRouterParams getRouterParams() { |
| return new MediaRouterParams.Builder(super.getRouterParams()) |
| .setOutputSwitcherEnabled(true) |
| .build(); |
| } |
| } |
| |
| public static class ControllerDialogFragment extends MediaRouteControllerDialogFragment { |
| private MediaRouteControllerDialog mControllerDialog; |
| private CheckBox mUseDefaultControlCheckBox; |
| |
| public ControllerDialogFragment() { |
| super(); |
| } |
| |
| public ControllerDialogFragment(CheckBox customControlViewCheckBox) { |
| this.mUseDefaultControlCheckBox = customControlViewCheckBox; |
| } |
| |
| @Override |
| public MediaRouteControllerDialog onCreateControllerDialog( |
| Context context, Bundle savedInstanceState) { |
| mControllerDialog = this.mUseDefaultControlCheckBox.isChecked() |
| ? super.onCreateControllerDialog(context, savedInstanceState) |
| : new MyMediaRouteControllerDialog(context); |
| mControllerDialog.setOnDismissListener(new DialogInterface.OnDismissListener() { |
| @Override |
| public void onDismiss(DialogInterface dialog) { |
| mControllerDialog = null; |
| } |
| }); |
| return mControllerDialog; |
| } |
| } |
| } |