Skip to content

Most visited

Recently visited

navigation
MediaRouter / src / com.example.android.mediarouter / player /

MainActivity.java

1
/*
2
 * Copyright (C) 2013 The Android Open Source Project
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
 
17
package com.example.android.mediarouter.player;
18
 
19
import android.app.PendingIntent;
20
import android.content.ComponentName;
21
import android.content.Context;
22
import android.content.Intent;
23
import android.media.AudioManager;
24
import android.media.AudioManager.OnAudioFocusChangeListener;
25
import android.media.RemoteControlClient;
26
import android.net.Uri;
27
import android.os.Build;
28
import android.os.Bundle;
29
import android.os.Environment;
30
import android.os.Handler;
31
import android.os.SystemClock;
32
import android.support.v4.app.FragmentManager;
33
import android.support.v4.view.MenuItemCompat;
34
import android.support.v7.app.ActionBarActivity;
35
import android.support.v7.app.MediaRouteActionProvider;
36
import android.support.v7.app.MediaRouteDiscoveryFragment;
37
import android.support.v7.media.MediaControlIntent;
38
import android.support.v7.media.MediaItemStatus;
39
import android.support.v7.media.MediaRouteSelector;
40
import android.support.v7.media.MediaRouter;
41
import android.support.v7.media.MediaRouter.Callback;
42
import android.support.v7.media.MediaRouter.ProviderInfo;
43
import android.support.v7.media.MediaRouter.RouteInfo;
44
import android.util.Log;
45
import android.view.KeyEvent;
46
import android.view.Menu;
47
import android.view.MenuItem;
48
import android.view.View;
49
import android.view.View.OnClickListener;
50
import android.view.ViewGroup;
51
import android.widget.AdapterView;
52
import android.widget.AdapterView.OnItemClickListener;
53
import android.widget.ArrayAdapter;
54
import android.widget.ImageButton;
55
import android.widget.ListView;
56
import android.widget.SeekBar;
57
import android.widget.SeekBar.OnSeekBarChangeListener;
58
import android.widget.TabHost;
59
import android.widget.TabHost.OnTabChangeListener;
60
import android.widget.TabHost.TabSpec;
61
import android.widget.TextView;
62
import android.widget.Toast;
63
 
64
import com.example.android.mediarouter.R;
65
import com.example.android.mediarouter.provider.SampleMediaRouteProvider;
66
 
67
import java.io.File;
68
 
69
/**
70
 * <h3>Media Router Support Activity</h3>
71
 * <p/>
72
 * <p>
73
 * This demonstrates how to use the {@link MediaRouter} API to build an
74
 * application that allows the user to send content to various rendering
75
 * targets.
76
 * </p>
77
 */
78
public class MainActivity extends ActionBarActivity {
79
    private static final String TAG = "MainActivity";
80
    private static final String DISCOVERY_FRAGMENT_TAG = "DiscoveryFragment";
81
 
82
    private MediaRouter mMediaRouter;
83
    private MediaRouteSelector mSelector;
84
    private LibraryAdapter mLibraryItems;
85
    private PlaylistAdapter mPlayListItems;
86
    private TextView mInfoTextView;
87
    private ListView mLibraryView;
88
    private ListView mPlayListView;
89
    private ImageButton mPauseResumeButton;
90
    private ImageButton mStopButton;
91
    private SeekBar mSeekBar;
92
    private boolean mPaused;
93
    private boolean mNeedResume;
94
    private boolean mSeeking;
95
 
96
    private RemoteControlClient mRemoteControlClient;
97
    private ComponentName mEventReceiver;
98
    private AudioManager mAudioManager;
99
    private PendingIntent mMediaPendingIntent;
100
 
101
    private final Handler mHandler = new Handler();
102
    private final Runnable mUpdateSeekRunnable = new Runnable() {
103
        @Override
104
        public void run() {
105
            updateProgress();
106
            // update UI every 1 second
107
            mHandler.postDelayed(this, 1000);
108
        }
109
    };
110
 
111
    private final SessionManager mSessionManager = new SessionManager("app");
112
    private Player mPlayer;
113
 
114
    private final MediaRouter.Callback mMediaRouterCB = new MediaRouter.Callback() {
115
        // Return a custom callback that will simply log all of the route events
116
        // for demonstration purposes.
117
        @Override
118
        public void onRouteAdded(MediaRouter router, RouteInfo route) {
119
            Log.d(TAG, "onRouteAdded: route=" + route);
120
        }
121
 
122
        @Override
123
        public void onRouteChanged(MediaRouter router, RouteInfo route) {
124
            Log.d(TAG, "onRouteChanged: route=" + route);
125
        }
126
 
127
        @Override
128
        public void onRouteRemoved(MediaRouter router, RouteInfo route) {
129
            Log.d(TAG, "onRouteRemoved: route=" + route);
130
        }
131
 
132
        @Override
133
        public void onRouteSelected(MediaRouter router, RouteInfo route) {
134
            Log.d(TAG, "onRouteSelected: route=" + route);
135
 
136
            mPlayer = Player.create(MainActivity.this, route);
137
            mPlayer.updatePresentation();
138
            mSessionManager.setPlayer(mPlayer);
139
            mSessionManager.unsuspend();
140
 
141
            registerRemoteControlClient();
142
            updateUi();
143
        }
144
 
145
        @Override
146
        public void onRouteUnselected(MediaRouter router, RouteInfo route) {
147
            Log.d(TAG, "onRouteUnselected: route=" + route);
148
            unregisterRemoteControlClient();
149
 
150
            PlaylistItem item = getCheckedPlaylistItem();
151
            if (item != null) {
152
                long pos = item.getPosition() +
153
                        (mPaused ? 0 : (SystemClock.elapsedRealtime() - item.getTimestamp()));
154
                mSessionManager.suspend(pos);
155
            }
156
            mPlayer.updatePresentation();
157
            mPlayer.release();
158
        }
159
 
160
        @Override
161
        public void onRouteVolumeChanged(MediaRouter router, RouteInfo route) {
162
            Log.d(TAG, "onRouteVolumeChanged: route=" + route);
163
        }
164
 
165
        @Override
166
        public void onRoutePresentationDisplayChanged(MediaRouter router, RouteInfo route) {
167
            Log.d(TAG, "onRoutePresentationDisplayChanged: route=" + route);
168
            mPlayer.updatePresentation();
169
        }
170
 
171
        @Override
172
        public void onProviderAdded(MediaRouter router, ProviderInfo provider) {
173
            Log.d(TAG, "onRouteProviderAdded: provider=" + provider);
174
        }
175
 
176
        @Override
177
        public void onProviderRemoved(MediaRouter router, ProviderInfo provider) {
178
            Log.d(TAG, "onRouteProviderRemoved: provider=" + provider);
179
        }
180
 
181
        @Override
182
        public void onProviderChanged(MediaRouter router, ProviderInfo provider) {
183
            Log.d(TAG, "onRouteProviderChanged: provider=" + provider);
184
        }
185
    };
186
 
187
    private final OnAudioFocusChangeListener mAfChangeListener = new OnAudioFocusChangeListener() {
188
        @Override
189
        public void onAudioFocusChange(int focusChange) {
190
            if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) {
191
                Log.d(TAG, "onAudioFocusChange: LOSS_TRANSIENT");
192
            } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
193
                Log.d(TAG, "onAudioFocusChange: AUDIOFOCUS_GAIN");
194
            } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
195
                Log.d(TAG, "onAudioFocusChange: AUDIOFOCUS_LOSS");
196
            }
197
        }
198
    };
199
 
200
    @Override
201
    protected void onCreate(Bundle savedInstanceState) {
202
        // Be sure to call the super class.
203
        super.onCreate(savedInstanceState);
204
        if (savedInstanceState != null) {
205
            mPlayer = (Player) savedInstanceState.getSerializable("mPlayer");
206
        }
207
 
208
        // Get the media router service.
209
        mMediaRouter = MediaRouter.getInstance(this);
210
 
211
        // Create a route selector for the type of routes that we care about.
212
        mSelector =
213
                new MediaRouteSelector.Builder().addControlCategory(MediaControlIntent
214
                        .CATEGORY_LIVE_AUDIO).addControlCategory(MediaControlIntent
215
                        .CATEGORY_LIVE_VIDEO).addControlCategory(MediaControlIntent
216
                        .CATEGORY_REMOTE_PLAYBACK).addControlCategory(SampleMediaRouteProvider
217
                        .CATEGORY_SAMPLE_ROUTE).build();
218
 
219
        // Add a fragment to take care of media route discovery.
220
        // This fragment automatically adds or removes a callback whenever the activity
221
        // is started or stopped.
222
        FragmentManager fm = getSupportFragmentManager();
223
        DiscoveryFragment fragment =
224
                (DiscoveryFragment) fm.findFragmentByTag(DISCOVERY_FRAGMENT_TAG);
225
        if (fragment == null) {
226
            fragment = new DiscoveryFragment(mMediaRouterCB);
227
            fragment.setRouteSelector(mSelector);
228
            fm.beginTransaction().add(fragment, DISCOVERY_FRAGMENT_TAG).commit();
229
        } else {
230
            fragment.setCallback(mMediaRouterCB);
231
            fragment.setRouteSelector(mSelector);
232
        }
233
 
234
        // Populate an array adapter with streaming media items.
235
        String[] mediaNames = getResources().getStringArray(R.array.media_names);
236
        String[] mediaUris = getResources().getStringArray(R.array.media_uris);
237
        mLibraryItems = new LibraryAdapter();
238
        for (int i = 0; i < mediaNames.length; i++) {
239
            mLibraryItems.add(new MediaItem(
240
                    "[streaming] " + mediaNames[i], Uri.parse(mediaUris[i]), "video/mp4"));
241
        }
242
 
243
        // Scan local external storage directory for media files.
244
        File externalDir = Environment.getExternalStorageDirectory();
245
        if (externalDir != null) {
246
            File list[] = externalDir.listFiles();
247
            if (list != null) {
248
                for (int i = 0; i < list.length; i++) {
249
                    String filename = list[i].getName();
250
                    if (filename.matches(".*\\.(m4v|mp4)")) {
251
                        mLibraryItems.add(new MediaItem(
252
                                "[local] " + filename, Uri.fromFile(list[i]), "video/mp4"));
253
                    }
254
                }
255
            }
256
        }
257
 
258
        mPlayListItems = new PlaylistAdapter();
259
 
260
        // Initialize the layout.
261
        setContentView(R.layout.sample_media_router);
262
 
263
        TabHost tabHost = (TabHost) findViewById(R.id.tabHost);
264
        tabHost.setup();
265
        String tabName = getResources().getString(R.string.library_tab_text);
266
        TabSpec spec1 = tabHost.newTabSpec(tabName);
267
        spec1.setContent(R.id.tab1);
268
        spec1.setIndicator(tabName);
269
 
270
        tabName = getResources().getString(R.string.playlist_tab_text);
271
        TabSpec spec2 = tabHost.newTabSpec(tabName);
272
        spec2.setIndicator(tabName);
273
        spec2.setContent(R.id.tab2);
274
 
275
        tabName = getResources().getString(R.string.statistics_tab_text);
276
        TabSpec spec3 = tabHost.newTabSpec(tabName);
277
        spec3.setIndicator(tabName);
278
        spec3.setContent(R.id.tab3);
279
 
280
        tabHost.addTab(spec1);
281
        tabHost.addTab(spec2);
282
        tabHost.addTab(spec3);
283
        tabHost.setOnTabChangedListener(new OnTabChangeListener() {
284
            @Override
285
            public void onTabChanged(String arg0) {
286
                updateUi();
287
            }
288
        });
289
 
290
        mLibraryView = (ListView) findViewById(R.id.media);
291
        mLibraryView.setAdapter(mLibraryItems);
292
        mLibraryView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
293
        mLibraryView.setOnItemClickListener(new OnItemClickListener() {
294
            @Override
295
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
296
                updateButtons();
297
            }
298
        });
299
 
300
        mPlayListView = (ListView) findViewById(R.id.playlist);
301
        mPlayListView.setAdapter(mPlayListItems);
302
        mPlayListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
303
        mPlayListView.setOnItemClickListener(new OnItemClickListener() {
304
            @Override
305
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
306
                updateButtons();
307
            }
308
        });
309
 
310
        mInfoTextView = (TextView) findViewById(R.id.info);
311
 
312
        mPauseResumeButton = (ImageButton) findViewById(R.id.pause_resume_button);
313
        mPauseResumeButton.setOnClickListener(new OnClickListener() {
314
            @Override
315
            public void onClick(View v) {
316
                mPaused = !mPaused;
317
                if (mPaused) {
318
                    mSessionManager.pause();
319
                } else {
320
                    mSessionManager.resume();
321
                }
322
            }
323
        });
324
 
325
        mStopButton = (ImageButton) findViewById(R.id.stop_button);
326
        mStopButton.setOnClickListener(new OnClickListener() {
327
            @Override
328
            public void onClick(View v) {
329
                mPaused = false;
330
                mSessionManager.stop();
331
            }
332
        });
333
 
334
        mSeekBar = (SeekBar) findViewById(R.id.seekbar);
335
        mSeekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
336
            @Override
337
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
338
                PlaylistItem item = getCheckedPlaylistItem();
339
                if (fromUser && item != null && item.getDuration() > 0) {
340
                    long pos = progress * item.getDuration() / 100;
341
                    mSessionManager.seek(item.getItemId(), pos);
342
                    item.setPosition(pos);
343
                    item.setTimestamp(SystemClock.elapsedRealtime());
344
                }
345
            }
346
 
347
            @Override
348
            public void onStartTrackingTouch(SeekBar seekBar) {
349
                mSeeking = true;
350
            }
351
 
352
            @Override
353
            public void onStopTrackingTouch(SeekBar seekBar) {
354
                mSeeking = false;
355
                updateUi();
356
            }
357
        });
358
 
359
        // Schedule Ui update
360
        mHandler.postDelayed(mUpdateSeekRunnable, 1000);
361
 
362
        // Build the PendingIntent for the remote control client
363
        mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
364
        mEventReceiver =
365
                new ComponentName(getPackageName(), SampleMediaButtonReceiver.class.getName());
366
        Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
367
        mediaButtonIntent.setComponent(mEventReceiver);
368
        mMediaPendingIntent = PendingIntent.getBroadcast(this, 0, mediaButtonIntent, 0);
369
 
370
        // Create and register the remote control client
371
        registerRemoteControlClient();
372
 
373
        // Set up playback manager and player
374
        mPlayer = Player.create(MainActivity.this, mMediaRouter.getSelectedRoute());
375
        mSessionManager.setPlayer(mPlayer);
376
        mSessionManager.setCallback(new SessionManager.Callback() {
377
            @Override
378
            public void onStatusChanged() {
379
                updateUi();
380
            }
381
 
382
            @Override
383
            public void onItemChanged(PlaylistItem item) {
384
            }
385
        });
386
 
387
        updateUi();
388
    }
389
 
390
    private void registerRemoteControlClient() {
391
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
392
            // Create the RCC and register with AudioManager and MediaRouter
393
            mAudioManager.requestAudioFocus(mAfChangeListener, AudioManager.STREAM_MUSIC,
394
                    AudioManager.AUDIOFOCUS_GAIN);
395
            mAudioManager.registerMediaButtonEventReceiver(mEventReceiver);
396
            mRemoteControlClient = new RemoteControlClient(mMediaPendingIntent);
397
            mAudioManager.registerRemoteControlClient(mRemoteControlClient);
398
            mMediaRouter.addRemoteControlClient(mRemoteControlClient);
399
            SampleMediaButtonReceiver.setActivity(MainActivity.this);
400
            mRemoteControlClient.setTransportControlFlags(RemoteControlClient
401
                    .FLAG_KEY_MEDIA_PLAY_PAUSE);
402
            mRemoteControlClient.setPlaybackState(RemoteControlClient.PLAYSTATE_PLAYING);
403
        }
404
    }
405
 
406
    private void unregisterRemoteControlClient() {
407
        // Unregister the RCC with AudioManager and MediaRouter
408
        if (mRemoteControlClient != null) {
409
            mRemoteControlClient.setTransportControlFlags(0);
410
            mAudioManager.abandonAudioFocus(mAfChangeListener);
411
            mAudioManager.unregisterMediaButtonEventReceiver(mEventReceiver);
412
            mAudioManager.unregisterRemoteControlClient(mRemoteControlClient);
413
            mMediaRouter.removeRemoteControlClient(mRemoteControlClient);
414
            SampleMediaButtonReceiver.setActivity(null);
415
            mRemoteControlClient = null;
416
        }
417
    }
418
 
419
    public boolean handleMediaKey(KeyEvent event) {
420
        if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {
421
            switch (event.getKeyCode()) {
422
                case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: {
423
                    Log.d(TAG, "Received Play/Pause event from RemoteControlClient");
424
                    mPaused = !mPaused;
425
                    if (mPaused) {
426
                        mSessionManager.pause();
427
                    } else {
428
                        mSessionManager.resume();
429
                    }
430
                    return true;
431
                }
432
                case KeyEvent.KEYCODE_MEDIA_PLAY: {
433
                    Log.d(TAG, "Received Play event from RemoteControlClient");
434
                    if (mPaused) {
435
                        mPaused = false;
436
                        mSessionManager.resume();
437
                    }
438
                    return true;
439
                }
440
                case KeyEvent.KEYCODE_MEDIA_PAUSE: {
441
                    Log.d(TAG, "Received Pause event from RemoteControlClient");
442
                    if (!mPaused) {
443
                        mPaused = true;
444
                        mSessionManager.pause();
445
                    }
446
                    return true;
447
                }
448
                case KeyEvent.KEYCODE_MEDIA_STOP: {
449
                    Log.d(TAG, "Received Stop event from RemoteControlClient");
450
                    mPaused = false;
451
                    mSessionManager.stop();
452
                    return true;
453
                }
454
                default:
455
                    break;
456
            }
457
        }
458
        return false;
459
    }
460
 
461
    @Override
462
    public boolean onKeyDown(int keyCode, KeyEvent event) {
463
        return handleMediaKey(event) || super.onKeyDown(keyCode, event);
464
    }
465
 
466
    @Override
467
    public boolean onKeyUp(int keyCode, KeyEvent event) {
468
        return handleMediaKey(event) || super.onKeyUp(keyCode, event);
469
    }
470
 
471
    @Override