Separate MediaRouter Androidx demo to a new app.
- Remove some extra un-related work like light/dark themes, ...etc.
Bug: 257999945
Test: Manually
Change-Id: I2d3f11d39402ce9a22d452f07dc3d72cbdc7349f
diff --git a/samples/AndroidXDemos/src/main/AndroidManifest.xml b/samples/AndroidXDemos/src/main/AndroidManifest.xml
index 394fac1..549d7fc 100644
--- a/samples/AndroidXDemos/src/main/AndroidManifest.xml
+++ b/samples/AndroidXDemos/src/main/AndroidManifest.xml
@@ -39,88 +39,6 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
- <activity
- android:name=".media.SampleMediaRouterActivity"
- android:configChanges="orientation|screenSize"
- android:exported="true"
- android:label="@string/sample_media_router_activity_dark"
- android:theme="@style/Theme.SampleMediaRouter">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.example.androidx.SAMPLE_CODE" />
- </intent-filter>
- </activity>
- <!-- MediaRouter Support Samples -->
-
- <activity
- android:name=".media.SampleMediaRouterActivity$Light"
- android:configChanges="orientation|screenSize"
- android:exported="true"
- android:label="@string/sample_media_router_activity_light"
- android:theme="@style/Theme.SampleMediaRouter.Light">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.example.androidx.SAMPLE_CODE" />
- </intent-filter>
- </activity>
-
- <activity
- android:name=".media.SampleMediaRouterActivity$LightWithDarkActionBar"
- android:configChanges="orientation|screenSize"
- android:exported="true"
- android:label="@string/sample_media_router_activity_light_with_dark_action_bar"
- android:theme="@style/Theme.SampleMediaRouter.Light.DarkActionBar">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.example.androidx.SAMPLE_CODE" />
- </intent-filter>
- </activity>
-
- <activity
- android:name=".media.SampleMediaRouterActivity$DynamicGroupActivity"
- android:configChanges="orientation|screenSize"
- android:exported="true"
- android:label="@string/sample_media_router_activity_dynamic_group"
- android:theme="@style/Theme.SampleMediaRouter">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.example.androidx.SAMPLE_CODE" />
- </intent-filter>
- </activity>
-
- <activity
- android:name=".media.SampleMediaRouterActivity$OutputSwitcherActivity"
- android:configChanges="orientation|screenSize"
- android:exported="true"
- android:label="@string/sample_media_router_activity_output_switcher"
- android:theme="@style/Theme.SampleMediaRouter">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.example.androidx.SAMPLE_CODE" />
- </intent-filter>
- </activity>
-
- <activity
- android:name=".media.SampleMediaRouterActivity$LegacyMediaRouterActivity"
- android:configChanges="orientation|screenSize"
- android:exported="true"
- android:label="@string/sample_media_router_activity_legacy"
- android:theme="@style/Theme.SampleMediaRouter">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.example.androidx.SAMPLE_CODE" />
- </intent-filter>
- </activity>
-
- <activity
- android:name=".media.SampleMediaRouteSettingsActivity"
- android:exported="true"
- android:label="@string/sample_media_route_settings_activity"
- android:theme="@style/Theme.AppCompat.Light">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- </intent-filter>
- </activity>
<activity
android:name=".view.GridLayout1"
@@ -925,48 +843,12 @@
android:name=".app.RecentSuggestionsProvider"
android:authorities="com.example.androidx.RecentSuggestionsProvider" />
- <!-- Selection helper single selection demo activity -->
- <receiver android:name=".media.SampleMediaButtonReceiver"
- android:exported="true">
- <intent-filter>
- <action android:name="android.intent.action.MEDIA_BUTTON" />
- </intent-filter>
- </receiver>
-
- <!-- Selection helper rudimentary demo activity -->
- <receiver android:name="androidx.mediarouter.media.MediaTransferReceiver"
- android:exported="true" />
-
- <!-- Selection helper "the whole kit and caboodle" demo activity -->
- <service
- android:name=".media.SampleMediaRouteProviderService"
- android:exported="true"
- android:label="@string/sample_media_route_provider_service"
- android:process=":mrp">
- <intent-filter>
- <action android:name="android.media.MediaRouteProviderService" />
- <action android:name="android.media.MediaRoute2ProviderService" />
- </intent-filter>
- </service>
-
- <!-- Custom drawable activity -->
- <service
- android:name=".media.SampleDynamicGroupMrpService"
- android:label="@string/sample_media_route_provider_service"
- android:exported="true"
- android:process=":dynamic_mrp">
- <intent-filter>
- <action android:name="android.media.MediaRouteProviderService" />
- <action android:name="android.media.MediaRoute2ProviderService" />
- </intent-filter>
- </service>
-
</application>
- <!-- Permission for SYSTEM_ALERT_WINDOW is only required for emulating
- remote display using system alert window. -->
+
<supports-screens
android:compatibleWidthLimitDp="480"
android:requiresSmallestWidthDp="320" />
+
<!-- Permission for READ_EXTERNAL_STORAGE is explicitly required for
reading images from the media store from API v19+. -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
@@ -980,6 +862,4 @@
this is just convenient for testing). -->
<uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
-
</manifest>
diff --git a/samples/AndroidXDemos/src/main/res/values/arrays.xml b/samples/AndroidXDemos/src/main/res/values/arrays.xml
index 5c0b352..cc37fb7 100644
--- a/samples/AndroidXDemos/src/main/res/values/arrays.xml
+++ b/samples/AndroidXDemos/src/main/res/values/arrays.xml
@@ -15,30 +15,6 @@
-->
<resources>
- <string-array name="media_names">
- <item>Big Buck Bunny</item>
- <item>Elephants Dream</item>
- <item>Sintel</item>
- <item>Tears of Steel</item>
- <item>(Music) Let\'s Dance</item>
- </string-array>
-
- <string-array name="media_uris">
- <item>https://archive.org/download/BigBuckBunny_328/BigBuckBunny_512kb.mp4</item>
- <item>https://archive.org/download/ElephantsDream_277/elephant_dreams_640_512kb.mp4</item>
- <item>https://archive.org/download/Sintel/sintel-2048-stereo_512kb.mp4</item>
- <item>https://archive.org/download/Tears-of-Steel/tears_of_steel_720p.mp4</item>
- <item>https://archive.org/download/78_lets-dance-theme-song_baldridge-stone-bonime-benny-goodman-and-his-orchestra_gbia0000390b/Let%27s%20Dance%20%28Theme%20Song%29%20-%20Baldridge%20-%20Stone.mp3</item>
- </string-array>
-
- <string-array name="media_mimes">
- <item>video/mp4</item>
- <item>video/mp4</item>
- <item>video/mp4</item>
- <item>video/mp4</item>
- <item>audio/mp3</item>
- </string-array>
-
<string-array name="dialog_types">
<item>Simple</item>
<item>Button bar</item>
diff --git a/samples/AndroidXDemos/src/main/res/values/strings.xml b/samples/AndroidXDemos/src/main/res/values/strings.xml
index 5844c3d..9953f125 100644
--- a/samples/AndroidXDemos/src/main/res/values/strings.xml
+++ b/samples/AndroidXDemos/src/main/res/values/strings.xml
@@ -17,44 +17,6 @@
<resources>
<string name="activity_sample_code">AndroidX Demos</string>
- <!-- MediaRouter -->
-
- <string name="sample_media_router_activity_dark">MediaRouter/Dark Theme</string>
- <string name="sample_media_router_activity_light">MediaRouter/Light Theme</string>
- <string name="sample_media_router_activity_light_with_dark_action_bar">MediaRouter/Light Theme, Dark Action Bar</string>
- <string name="sample_media_router_activity_dynamic_group">MediaRouter/Dynamic Group
- Dialog</string>
- <string name="sample_media_router_activity_output_switcher">MediaRouter/Output Switcher</string>
- <string name="sample_media_router_activity_legacy">MediaRouter/Disable MediaRouter2</string>
- <string name="sample_media_router_text">This activity demonstrates how to
- use MediaRouter from the support library. Select a route from the action bar.</string>
- <string name="media_route_menu_title">Play on...</string>
- <string name="sample_media_route_settings_activity">Sample route settings</string>
-
- <string name="use_default_media_control">Use default media control</string>
- <string name="my_media_control_text">My Media Control</string>
-
- <string name="library_tab_text">Library</string>
- <string name="playlist_tab_text">Playlist</string>
- <string name="info_tab_text">Route Info</string>
-
- <string name="sample_media_route_provider_service">Media Route Provider Service Support Library Sample</string>
- <string name="fixed_volume_route_name">Fixed Volume Remote Playback Route</string>
- <string name="variable_volume_basic_route_name">Variable Volume (Basic) Remote Playback Route</string>
- <string name="variable_volume_queuing_route_name">Variable Volume (Queuing) Remote Playback Route</string>
- <string name="variable_volume_session_route_name">Variable Volume (Session) Remote Playback Route</string>
- <string name="variable_volume_route_group_name">Variable Volume Route Group</string>
- <string name="mixed_volume_route_group_name">Mixed Volume Route Group</string>
- <string name="sample_route_description">Sample route from AndroidXDemos</string>
-
- <string name="sample_dynamic_group_mrp_service">Media Route Provider Service Support Library Sample (supporting dynamic group)</string>
- <string name="dg_tv_route_name1">Dynamic Route 1 - TV</string>
- <string name="dg_tv_route_name2">Dynamic Route 2 - TV</string>
- <string name="dg_speaker_route_name3">Dynamic Route 3 - Speaker</string>
- <string name="dg_speaker_route_name4">Dynamic Route 4 - Speaker</string>
- <string name="dg_not_unselectable_route_name5"> Dynamic Route 5 - Not unselectable</string>
- <string name="dg_static_group_route_name6"> Dynamic Route 6 - Static Group</string>
-
<!-- GridLayout -->
<string name="grid_layout_1">GridLayout/1. Simple Form</string>
diff --git a/samples/MediaRoutingDemo/OWNERS b/samples/MediaRoutingDemo/OWNERS
new file mode 100644
index 0000000..834477b
--- /dev/null
+++ b/samples/MediaRoutingDemo/OWNERS
@@ -0,0 +1 @@
+file: ../../mediarouter/OWNERS
diff --git a/samples/MediaRoutingDemo/build.gradle b/samples/MediaRoutingDemo/build.gradle
new file mode 100644
index 0000000..5aff7c8
--- /dev/null
+++ b/samples/MediaRoutingDemo/build.gradle
@@ -0,0 +1,23 @@
+plugins {
+ id("AndroidXPlugin")
+ id("com.android.application")
+}
+
+dependencies {
+ implementation(project(":appcompat:appcompat"))
+ implementation(project(":mediarouter:mediarouter"))
+ implementation("androidx.concurrent:concurrent-futures:1.1.0")
+}
+
+android {
+ buildTypes {
+ release {
+ minifyEnabled = true
+ proguardFiles getDefaultProguardFile("proguard-android-optimize.txt")
+ }
+ }
+ defaultConfig {
+ vectorDrawables.useSupportLibrary = true
+ }
+ namespace "com.example.androidx.mediarouting"
+}
diff --git a/samples/MediaRoutingDemo/lint-baseline.xml b/samples/MediaRoutingDemo/lint-baseline.xml
new file mode 100644
index 0000000..a9df457
--- /dev/null
+++ b/samples/MediaRoutingDemo/lint-baseline.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<issues format="6" by="lint 7.4.0-alpha08" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha08)" variant="all" version="7.4.0-alpha08">
+
+</issues>
diff --git a/samples/MediaRoutingDemo/src/main/AndroidManifest.xml b/samples/MediaRoutingDemo/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..d3910e3
--- /dev/null
+++ b/samples/MediaRoutingDemo/src/main/AndroidManifest.xml
@@ -0,0 +1,163 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- Declare the contents of this Android application. The namespace
+ attribute brings in the Android platform namespace, and the package
+ supplies a unique name for the application. When writing your
+ own application, the package name must be changed from "com.example.*"
+ to come from a domain that you own or have control over. -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android">
+ <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
+
+ <application
+ android:hardwareAccelerated="true"
+ android:icon="@drawable/app_sample_code"
+ android:label="@string/activity_sample_code"
+ android:supportsRtl="true">
+
+ <activity
+ android:name=".SampleMediaRouterActivity"
+ android:configChanges="orientation|screenSize"
+ android:exported="true"
+ android:label="@string/sample_media_router_activity_dark"
+ android:theme="@style/Theme.SampleMediaRouter">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.example.androidx.SAMPLE_CODE" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ <!-- MediaRouter Support Samples -->
+ <activity
+ android:name=".SampleMediaRouterActivity$Light"
+ android:configChanges="orientation|screenSize"
+ android:exported="true"
+ android:label="@string/sample_media_router_activity_light"
+ android:theme="@style/Theme.SampleMediaRouter.Light">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.example.androidx.SAMPLE_CODE" />
+ </intent-filter>
+ </activity>
+
+ <activity
+ android:name=".SampleMediaRouterActivity$LightWithDarkActionBar"
+ android:configChanges="orientation|screenSize"
+ android:exported="true"
+ android:label="@string/sample_media_router_activity_light_with_dark_action_bar"
+ android:theme="@style/Theme.SampleMediaRouter.Light.DarkActionBar">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.example.androidx.SAMPLE_CODE" />
+ </intent-filter>
+ </activity>
+
+ <activity
+ android:name=".SampleMediaRouterActivity$DynamicGroupActivity"
+ android:configChanges="orientation|screenSize"
+ android:exported="true"
+ android:label="@string/sample_media_router_activity_dynamic_group"
+ android:theme="@style/Theme.SampleMediaRouter">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.example.androidx.SAMPLE_CODE" />
+ </intent-filter>
+ </activity>
+
+ <activity
+ android:name=".SampleMediaRouterActivity$OutputSwitcherActivity"
+ android:configChanges="orientation|screenSize"
+ android:exported="true"
+ android:label="@string/sample_media_router_activity_output_switcher"
+ android:theme="@style/Theme.SampleMediaRouter">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.example.androidx.SAMPLE_CODE" />
+ </intent-filter>
+ </activity>
+
+ <activity
+ android:name=".SampleMediaRouterActivity$LegacyMediaRouterActivity"
+ android:configChanges="orientation|screenSize"
+ android:exported="true"
+ android:label="@string/sample_media_router_activity_legacy"
+ android:theme="@style/Theme.SampleMediaRouter">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.example.androidx.SAMPLE_CODE" />
+ </intent-filter>
+ </activity>
+
+ <activity
+ android:name=".SampleMediaRouteSettingsActivity"
+ android:exported="true"
+ android:label="@string/sample_media_route_settings_activity"
+ android:theme="@style/Theme.AppCompat.Light">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ </intent-filter>
+ </activity>
+
+ <receiver android:name="androidx.mediarouter.media.MediaTransferReceiver"
+ android:exported="true" />
+
+ <service
+ android:name=".SampleMediaRouteProviderService"
+ android:exported="true"
+ android:label="@string/sample_media_route_provider_service"
+ android:process=":mrp">
+ <intent-filter>
+ <action android:name="android.media.MediaRouteProviderService" />
+ <action android:name="android.media.MediaRoute2ProviderService" />
+ </intent-filter>
+ </service>
+
+ <service
+ android:name=".SampleDynamicGroupMrpService"
+ android:label="@string/sample_media_route_provider_service"
+ android:exported="true"
+ android:process=":dynamic_mrp">
+ <intent-filter>
+ <action android:name="android.media.MediaRouteProviderService" />
+ <action android:name="android.media.MediaRoute2ProviderService" />
+ </intent-filter>
+ </service>
+
+ </application>
+
+ <!-- The smallest screen this app works on is a phone. The app will
+ scale its UI to larger screens but doesn't make good use of them
+ so allow the compatibility mode button to be shown (mostly because
+ this is just convenient for testing). -->
+ <supports-screens
+ android:compatibleWidthLimitDp="480"
+ android:requiresSmallestWidthDp="320" />
+
+ <!-- Permission for SYSTEM_ALERT_WINDOW is only required for emulating
+ remote display using system alert window. -->
+ <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+
+ <!-- Permission for READ_EXTERNAL_STORAGE is explicitly required for
+ reading images from the media store from API v19+. -->
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+
+ <!-- Permission for INTERNET is required for streaming video content
+ from the web, it's not required otherwise. -->
+ <uses-permission android:name="android.permission.INTERNET" />
+
+</manifest>
diff --git a/samples/AndroidXDemos/src/main/java/com/example/androidx/media/LocalPlayer.java b/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/LocalPlayer.java
similarity index 86%
rename from samples/AndroidXDemos/src/main/java/com/example/androidx/media/LocalPlayer.java
rename to samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/LocalPlayer.java
index ec022f6..36a7b77 100644
--- a/samples/AndroidXDemos/src/main/java/com/example/androidx/media/LocalPlayer.java
+++ b/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/LocalPlayer.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright 2022 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.example.androidx.media;
+package com.example.androidx.mediarouting;
import android.app.Activity;
import android.app.Presentation;
@@ -37,21 +37,19 @@
import android.view.WindowManager;
import android.widget.FrameLayout;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.mediarouter.media.MediaItemStatus;
import androidx.mediarouter.media.MediaRouter.RouteInfo;
-import com.example.androidx.R;
-
import java.io.IOException;
/**
* Handles playback of a single media item using MediaPlayer.
*/
-public abstract class LocalPlayer extends Player implements
- MediaPlayer.OnPreparedListener,
- MediaPlayer.OnCompletionListener,
- MediaPlayer.OnErrorListener,
+public abstract class LocalPlayer extends Player implements MediaPlayer.OnPreparedListener,
+ MediaPlayer.OnCompletionListener, MediaPlayer.OnErrorListener,
MediaPlayer.OnSeekCompleteListener {
private static final String TAG = "LocalPlayer";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -67,7 +65,7 @@
private Surface mSurface;
private SurfaceHolder mSurfaceHolder;
- public LocalPlayer(Context context) {
+ public LocalPlayer(@NonNull Context context) {
mContext = context;
// reset media player
@@ -85,7 +83,7 @@
}
@Override
- public void connect(RouteInfo route) {
+ public void connect(@NonNull RouteInfo route) {
if (DEBUG) {
Log.d(TAG, "connecting to: " + route);
}
@@ -106,12 +104,12 @@
// Player
@Override
- public void play(final PlaylistItem item) {
+ public void play(@NonNull final PlaylistItem item) {
if (DEBUG) {
Log.d(TAG, "play: item=" + item);
}
reset();
- mSeekToPos = (int)item.getPosition();
+ mSeekToPos = (int) item.getPosition();
try {
mMediaPlayer.setDataSource(mContext, item.getUri());
mMediaPlayer.prepareAsync();
@@ -132,11 +130,11 @@
}
@Override
- public void seek(final PlaylistItem item) {
+ public void seek(@NonNull final PlaylistItem item) {
if (DEBUG) {
Log.d(TAG, "seek: item=" + item);
}
- int pos = (int)item.getPosition();
+ int pos = (int) item.getPosition();
if (mState == STATE_PLAYING || mState == STATE_PAUSED) {
mMediaPlayer.seekTo(pos);
mSeekToPos = pos;
@@ -149,13 +147,12 @@
}
@Override
- public void getStatus(final PlaylistItem item, final boolean update) {
+ public void getStatus(@NonNull final PlaylistItem item, final boolean update) {
if (mState == STATE_PLAYING || mState == STATE_PAUSED) {
// use mSeekToPos if we're currently seeking (mSeekToPos is reset
// when seeking is completed)
item.setDuration(mMediaPlayer.getDuration());
- item.setPosition(mSeekToPos > 0 ?
- mSeekToPos : mMediaPlayer.getCurrentPosition());
+ item.setPosition(mSeekToPos > 0 ? mSeekToPos : mMediaPlayer.getCurrentPosition());
item.setTimestamp(SystemClock.elapsedRealtime());
}
if (update && mCallback != null) {
@@ -201,12 +198,13 @@
}
@Override
- public void enqueue(final PlaylistItem item) {
+ public void enqueue(@NonNull final PlaylistItem item) {
throw new UnsupportedOperationException("LocalPlayer doesn't support enqueue!");
}
+ @NonNull
@Override
- public PlaylistItem remove(String iid) {
+ public PlaylistItem remove(@NonNull String iid) {
throw new UnsupportedOperationException("LocalPlayer doesn't support remove!");
}
@@ -292,26 +290,43 @@
});
}
- protected Context getContext() { return mContext; }
- protected MediaPlayer getMediaPlayer() { return mMediaPlayer; }
- protected int getVideoWidth() { return mVideoWidth; }
- protected int getVideoHeight() { return mVideoHeight; }
- protected int getState() { return mState; }
- protected void setSurface(Surface surface) {
+ @NonNull
+ protected Context getContext() {
+ return mContext;
+ }
+
+ @NonNull
+ protected MediaPlayer getMediaPlayer() {
+ return mMediaPlayer;
+ }
+
+ protected int getVideoWidth() {
+ return mVideoWidth;
+ }
+
+ protected int getVideoHeight() {
+ return mVideoHeight;
+ }
+
+ protected int getState() {
+ return mState;
+ }
+
+ protected void setSurface(@NonNull Surface surface) {
mSurface = surface;
mSurfaceHolder = null;
updateSurface();
}
- protected void setSurface(SurfaceHolder surfaceHolder) {
+ protected void setSurface(@Nullable SurfaceHolder surfaceHolder) {
mSurface = null;
mSurfaceHolder = surfaceHolder;
updateSurface();
}
- protected void removeSurface(SurfaceHolder surfaceHolder) {
+ protected void removeSurface(@NonNull SurfaceHolder surfaceHolder) {
if (surfaceHolder == mSurfaceHolder) {
- setSurface((SurfaceHolder)null);
+ setSurface((SurfaceHolder) null);
}
}
@@ -378,19 +393,19 @@
/**
* Handles playback of a single media item using MediaPlayer in SurfaceView
*/
- public static class SurfaceViewPlayer extends LocalPlayer implements
- SurfaceHolder.Callback {
+ @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
+ public static class SurfaceViewPlayer extends LocalPlayer implements SurfaceHolder.Callback {
private static final String TAG = "SurfaceViewPlayer";
private RouteInfo mRoute;
private final SurfaceView mSurfaceView;
private final FrameLayout mLayout;
private DemoPresentation mPresentation;
- public SurfaceViewPlayer(Context context) {
+ public SurfaceViewPlayer(@NonNull Context context) {
super(context);
- mLayout = (FrameLayout)((Activity)context).findViewById(R.id.player);
- mSurfaceView = (SurfaceView)((Activity)context).findViewById(R.id.surface_view);
+ mLayout = (FrameLayout) ((Activity) context).findViewById(R.id.player);
+ mSurfaceView = (SurfaceView) ((Activity) context).findViewById(R.id.surface_view);
// add surface holder callback
SurfaceHolder holder = mSurfaceView.getHolder();
@@ -398,7 +413,7 @@
}
@Override
- public void connect(RouteInfo route) {
+ public void connect(@NonNull RouteInfo route) {
super.connect(route);
mRoute = route;
}
@@ -443,7 +458,7 @@
mPresentation.show();
} catch (WindowManager.InvalidDisplayException ex) {
Log.w(TAG, "Couldn't show presentation! Display was removed in "
- + "the meantime.", ex);
+ + "the meantime.", ex);
mPresentation = null;
}
}
@@ -453,8 +468,8 @@
// SurfaceHolder.Callback
@Override
- public void surfaceChanged(SurfaceHolder holder, int format,
- int width, int height) {
+ public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width,
+ int height) {
if (DEBUG) {
Log.d(TAG, "surfaceChanged: " + width + "x" + height);
}
@@ -462,7 +477,7 @@
}
@Override
- public void surfaceCreated(SurfaceHolder holder) {
+ public void surfaceCreated(@NonNull SurfaceHolder holder) {
if (DEBUG) {
Log.d(TAG, "surfaceCreated");
}
@@ -471,7 +486,7 @@
}
@Override
- public void surfaceDestroyed(SurfaceHolder holder) {
+ public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
if (DEBUG) {
Log.d(TAG, "surfaceDestroyed");
}
@@ -524,15 +539,15 @@
// Listens for when presentations are dismissed.
private final DialogInterface.OnDismissListener mOnDismissListener =
new DialogInterface.OnDismissListener() {
- @Override
- public void onDismiss(DialogInterface dialog) {
- if (dialog == mPresentation) {
- Log.i(TAG, "Presentation dismissed.");
- mPresentation = null;
- updateContents();
- }
- }
- };
+ @Override
+ public void onDismiss(DialogInterface dialog) {
+ if (dialog == mPresentation) {
+ Log.i(TAG, "Presentation dismissed.");
+ mPresentation = null;
+ updateContents();
+ }
+ }
+ };
@RequiresApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
private void releasePresentation() {
@@ -549,7 +564,7 @@
private final class DemoPresentation extends Presentation {
private SurfaceView mPresentationSurfaceView;
- public DemoPresentation(Context context, Display display) {
+ DemoPresentation(Context context, Display display) {
super(context, display);
}
@@ -594,19 +609,19 @@
private static final String TAG = "OverlayPlayer";
private final OverlayDisplayWindow mOverlay;
- public OverlayPlayer(Context context) {
+ public OverlayPlayer(@NonNull Context context) {
super(context);
mOverlay = OverlayDisplayWindow.create(getContext(),
getContext().getResources().getString(
- R.string.sample_media_route_provider_remote),
- 1024, 768, Gravity.CENTER);
+ R.string.sample_media_route_provider_remote), 1024, 768,
+ Gravity.CENTER);
mOverlay.setOverlayWindowListener(this);
}
@Override
- public void connect(RouteInfo route) {
+ public void connect(@NonNull RouteInfo route) {
super.connect(route);
mOverlay.show();
}
@@ -628,20 +643,21 @@
// OverlayDisplayWindow.OverlayWindowListener
@Override
- public void onWindowCreated(Surface surface) {
+ public void onWindowCreated(@NonNull Surface surface) {
setSurface(surface);
}
@Override
- public void onWindowCreated(SurfaceHolder surfaceHolder) {
+ public void onWindowCreated(@NonNull SurfaceHolder surfaceHolder) {
setSurface(surfaceHolder);
}
@Override
public void onWindowDestroyed() {
- setSurface((SurfaceHolder)null);
+ setSurface((SurfaceHolder) null);
}
+ @Nullable
@Override
public Bitmap getSnapshot() {
if (getState() == STATE_PLAYING || getState() == STATE_PAUSED) {
diff --git a/samples/AndroidXDemos/src/main/java/com/example/androidx/media/MyMediaRouteControllerDialog.java b/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/MyMediaRouteControllerDialog.java
similarity index 80%
rename from samples/AndroidXDemos/src/main/java/com/example/androidx/media/MyMediaRouteControllerDialog.java
rename to samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/MyMediaRouteControllerDialog.java
index efdf6fd..8051d4a7 100644
--- a/samples/AndroidXDemos/src/main/java/com/example/androidx/media/MyMediaRouteControllerDialog.java
+++ b/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/MyMediaRouteControllerDialog.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright 2022 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.example.androidx.media;
+package com.example.androidx.mediarouting;
import android.content.Context;
import android.graphics.Color;
@@ -22,21 +22,21 @@
import android.view.View;
import android.widget.TextView;
+import androidx.annotation.NonNull;
import androidx.mediarouter.app.MediaRouteControllerDialog;
-import com.example.androidx.R;
-
/**
* An example MediaRouteControllerDialog for demonstrating
* {@link androidx.mediarouter.app.MediaRouteControllerDialog#onCreateMediaControlView}.
*/
public class MyMediaRouteControllerDialog extends MediaRouteControllerDialog {
- public MyMediaRouteControllerDialog(Context context) {
+ public MyMediaRouteControllerDialog(@NonNull Context context) {
super(context);
}
+ @NonNull
@Override
- public View onCreateMediaControlView(Bundle savedInstanceState) {
+ public View onCreateMediaControlView(@NonNull Bundle savedInstanceState) {
TextView view = new TextView(getContext());
view.setText(R.string.my_media_control_text);
view.setBackgroundColor(Color.GRAY);
diff --git a/samples/AndroidXDemos/src/main/java/com/example/androidx/media/OverlayDisplayWindow.java b/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/OverlayDisplayWindow.java
similarity index 70%
rename from samples/AndroidXDemos/src/main/java/com/example/androidx/media/OverlayDisplayWindow.java
rename to samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/OverlayDisplayWindow.java
index 199046f..acee983 100644
--- a/samples/AndroidXDemos/src/main/java/com/example/androidx/media/OverlayDisplayWindow.java
+++ b/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/OverlayDisplayWindow.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright 2022 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.example.androidx.media;
+package com.example.androidx.mediarouting;
import android.content.Context;
import android.graphics.Bitmap;
@@ -38,10 +38,10 @@
import android.view.WindowManager;
import android.widget.TextView;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
-import com.example.androidx.R;
-
/**
* Manages an overlay display window, used for simulating remote playback.
*/
@@ -59,10 +59,11 @@
protected final int mWidth;
protected final int mHeight;
protected final int mGravity;
+ @Nullable
protected OverlayWindowListener mListener;
- protected OverlayDisplayWindow(Context context, String name,
- int width, int height, int gravity) {
+ protected OverlayDisplayWindow(@NonNull Context context, @NonNull String name, int width,
+ int height, int gravity) {
mContext = context;
mName = name;
mWidth = width;
@@ -70,7 +71,13 @@
mGravity = gravity;
}
- public static OverlayDisplayWindow create(Context context, String name,
+ /**
+ * Factory methd to create the overlay window.
+ *
+ * @return the created overlay window.
+ */
+ @NonNull
+ public static OverlayDisplayWindow create(@NonNull Context context, @NonNull String name,
int width, int height, int gravity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
return new JellybeanMr1Impl(context, name, width, height, gravity);
@@ -79,26 +86,55 @@
}
}
- public void setOverlayWindowListener(OverlayWindowListener listener) {
+ public void setOverlayWindowListener(@NonNull OverlayWindowListener listener) {
mListener = listener;
}
+ @NonNull
public Context getContext() {
return mContext;
}
+ /**
+ * Shows the overlay window.
+ */
public abstract void show();
+ /**
+ * Dismisses the overlay window.
+ */
public abstract void dismiss();
+ /**
+ * Change the view aspect ration to a new ratio.
+ */
public abstract void updateAspectRatio(int width, int height);
+ /**
+ * Gets a bitmap representing the snapshot of the window.
+ *
+ * @return a bitmap representing the snapshot of the window.
+ */
+ @Nullable
public abstract Bitmap getSnapshot();
- // Watches for significant changes in the overlay display window lifecycle.
+ /**
+ * Watches for significant changes in the overlay display window lifecycle.
+ */
public interface OverlayWindowListener {
- void onWindowCreated(Surface surface);
- void onWindowCreated(SurfaceHolder surfaceHolder);
+ /**
+ * Called when the window is created.
+ */
+ void onWindowCreated(@NonNull Surface surface);
+
+ /**
+ * Called when the window is created.
+ */
+ void onWindowCreated(@NonNull SurfaceHolder surfaceHolder);
+
+ /**
+ * Called when the window is destroyed.
+ */
void onWindowDestroyed();
}
@@ -112,17 +148,14 @@
private boolean mWindowVisible;
private SurfaceView mSurfaceView;
- public LegacyImpl(Context context, String name,
- int width, int height, int gravity) {
+ LegacyImpl(Context context, String name, int width, int height, int gravity) {
super(context, name, width, height, gravity);
- mWindowManager = (WindowManager)context.getSystemService(
- Context.WINDOW_SERVICE);
+ mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
}
@Override
- @SuppressWarnings("deprecation") /* getDefaultDisplay */
- public void show() {
+ @SuppressWarnings("deprecation") /* getDefaultDisplay */ public void show() {
if (!mWindowVisible) {
mSurfaceView = new SurfaceView(mContext);
@@ -146,8 +179,8 @@
params.gravity = Gravity.LEFT | Gravity.BOTTOM;
params.setTitle(mName);
- int width = (int)(display.getWidth() * INITIAL_SCALE);
- int height = (int)(display.getHeight() * INITIAL_SCALE);
+ int width = (int) (display.getWidth() * INITIAL_SCALE);
+ int height = (int) (display.getHeight() * INITIAL_SCALE);
if (mWidth > mHeight) {
height = mHeight * width / mWidth;
} else {
@@ -179,6 +212,7 @@
public void updateAspectRatio(int width, int height) {
}
+ @Nullable
@Override
public Bitmap getSnapshot() {
return null;
@@ -189,8 +223,9 @@
* Implementation for API version 17+.
*/
@RequiresApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
- @SuppressWarnings("deprecation") /* getDefaultDisplay */
- private static final class JellybeanMr1Impl extends OverlayDisplayWindow {
+ @SuppressWarnings("deprecation")
+ /* getDefaultDisplay */ private static final class JellybeanMr1Impl extends
+ OverlayDisplayWindow {
// When true, disables support for moving and resizing the overlay.
// The window is made non-touchable, which makes it possible to
// directly interact with the content underneath.
@@ -219,15 +254,12 @@
private float mLiveTranslationY;
private float mLiveScale = 1.0f;
- @SuppressWarnings("deprecation") /* defaultDisplay */
- public JellybeanMr1Impl(Context context, String name,
- int width, int height, int gravity) {
+ @SuppressWarnings("deprecation") /* defaultDisplay */ JellybeanMr1Impl(
+ Context context, String name, int width, int height, int gravity) {
super(context, name, width, height, gravity);
- mDisplayManager = (DisplayManager)context.getSystemService(
- Context.DISPLAY_SERVICE);
- mWindowManager = (WindowManager)context.getSystemService(
- Context.WINDOW_SERVICE);
+ mDisplayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
+ mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
mDefaultDisplay = mWindowManager.getDefaultDisplay();
updateDefaultDisplayInfo();
@@ -272,6 +304,7 @@
relayout();
}
+ @NonNull
@Override
public Bitmap getSnapshot() {
return mTextureView.getBitmap();
@@ -292,11 +325,10 @@
private void createWindow() {
LayoutInflater inflater = LayoutInflater.from(mContext);
- mWindowContent = inflater.inflate(
- R.layout.overlay_display_window, null);
+ mWindowContent = inflater.inflate(R.layout.overlay_display_window, null);
mWindowContent.setOnTouchListener(mOnTouchListener);
- mTextureView = (TextureView)mWindowContent.findViewById(
+ mTextureView = (TextureView) mWindowContent.findViewById(
R.id.overlay_display_window_texture);
mTextureView.setPivotX(0);
mTextureView.setPivotY(0);
@@ -305,7 +337,7 @@
mTextureView.setOpaque(false);
mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
- mNameTextView = (TextView)mWindowContent.findViewById(
+ mNameTextView = (TextView) mWindowContent.findViewById(
R.id.overlay_display_window_title);
mNameTextView.setText(mName);
@@ -334,10 +366,10 @@
// Set the initial position and scale.
// The position and scale will be clamped when the display is first shown.
- mWindowX = (mGravity & Gravity.LEFT) == Gravity.LEFT ?
- 0 : mDefaultDisplayMetrics.widthPixels;
- mWindowY = (mGravity & Gravity.TOP) == Gravity.TOP ?
- 0 : mDefaultDisplayMetrics.heightPixels;
+ mWindowX = (mGravity & Gravity.LEFT) == Gravity.LEFT
+ ? 0 : mDefaultDisplayMetrics.widthPixels;
+ mWindowY = (mGravity & Gravity.TOP) == Gravity.TOP
+ ? 0 : mDefaultDisplayMetrics.heightPixels;
Log.d(TAG, mDefaultDisplayMetrics.toString());
mWindowScale = INITIAL_SCALE;
@@ -348,23 +380,21 @@
private void updateWindowParams() {
float scale = mWindowScale * mLiveScale;
- scale = Math.min(scale, (float)mDefaultDisplayMetrics.widthPixels / mWidth);
- scale = Math.min(scale, (float)mDefaultDisplayMetrics.heightPixels / mHeight);
+ scale = Math.min(scale, (float) mDefaultDisplayMetrics.widthPixels / mWidth);
+ scale = Math.min(scale, (float) mDefaultDisplayMetrics.heightPixels / mHeight);
scale = Math.max(MIN_SCALE, Math.min(MAX_SCALE, scale));
float offsetScale = (scale / mWindowScale - 1.0f) * 0.5f;
- int width = (int)(mWidth * scale);
- int height = (int)(mHeight * scale);
- int x = (int)(mWindowX + mLiveTranslationX - width * offsetScale);
- int y = (int)(mWindowY + mLiveTranslationY - height * offsetScale);
+ int width = (int) (mWidth * scale);
+ int height = (int) (mHeight * scale);
+ int x = (int) (mWindowX + mLiveTranslationX - width * offsetScale);
+ int y = (int) (mWindowY + mLiveTranslationY - height * offsetScale);
x = Math.max(0, Math.min(x, mDefaultDisplayMetrics.widthPixels - width));
y = Math.max(0, Math.min(y, mDefaultDisplayMetrics.heightPixels - height));
if (DEBUG) {
- Log.d(TAG, "updateWindowParams: scale=" + scale
- + ", offsetScale=" + offsetScale
- + ", x=" + x + ", y=" + y
- + ", width=" + width + ", height=" + height);
+ Log.d(TAG, "updateWindowParams: scale=" + scale + ", offsetScale=" + offsetScale
+ + ", x=" + x + ", y=" + y + ", width=" + width + ", height=" + height);
}
mTextureView.setScaleX(scale);
@@ -396,56 +426,56 @@
private final DisplayManager.DisplayListener mDisplayListener =
new DisplayManager.DisplayListener() {
- @Override
- public void onDisplayAdded(int displayId) {
- }
-
- @Override
- public void onDisplayChanged(int displayId) {
- if (displayId == mDefaultDisplay.getDisplayId()) {
- if (updateDefaultDisplayInfo()) {
- relayout();
- } else {
- dismiss();
+ @Override
+ public void onDisplayAdded(int displayId) {
}
- }
- }
- @Override
- public void onDisplayRemoved(int displayId) {
- if (displayId == mDefaultDisplay.getDisplayId()) {
- dismiss();
- }
- }
- };
+ @Override
+ public void onDisplayChanged(int displayId) {
+ if (displayId == mDefaultDisplay.getDisplayId()) {
+ if (updateDefaultDisplayInfo()) {
+ relayout();
+ } else {
+ dismiss();
+ }
+ }
+ }
+
+ @Override
+ public void onDisplayRemoved(int displayId) {
+ if (displayId == mDefaultDisplay.getDisplayId()) {
+ dismiss();
+ }
+ }
+ };
private final SurfaceTextureListener mSurfaceTextureListener =
new SurfaceTextureListener() {
- @Override
- public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture,
- int width, int height) {
- if (mListener != null) {
- mListener.onWindowCreated(new Surface(surfaceTexture));
- }
- }
+ @Override
+ public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width,
+ int height) {
+ if (mListener != null) {
+ mListener.onWindowCreated(new Surface(surfaceTexture));
+ }
+ }
- @Override
- public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
- if (mListener != null) {
- mListener.onWindowDestroyed();
- }
- return true;
- }
+ @Override
+ public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
+ if (mListener != null) {
+ mListener.onWindowDestroyed();
+ }
+ return true;
+ }
- @Override
- public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture,
- int width, int height) {
- }
+ @Override
+ public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture,
+ int width, int height) {
+ }
- @Override
- public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
- }
- };
+ @Override
+ public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
+ }
+ };
private final View.OnTouchListener mOnTouchListener = new View.OnTouchListener() {
@Override
@@ -473,24 +503,24 @@
private final GestureDetector.OnGestureListener mOnGestureListener =
new GestureDetector.SimpleOnGestureListener() {
- @Override
- public boolean onScroll(MotionEvent e1, MotionEvent e2,
- float distanceX, float distanceY) {
- mLiveTranslationX -= distanceX;
- mLiveTranslationY -= distanceY;
- relayout();
- return true;
- }
- };
+ @Override
+ public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
+ float distanceY) {
+ mLiveTranslationX -= distanceX;
+ mLiveTranslationY -= distanceY;
+ relayout();
+ return true;
+ }
+ };
private final ScaleGestureDetector.OnScaleGestureListener mOnScaleGestureListener =
new ScaleGestureDetector.SimpleOnScaleGestureListener() {
- @Override
- public boolean onScale(ScaleGestureDetector detector) {
- mLiveScale *= detector.getScaleFactor();
- relayout();
- return true;
- }
- };
+ @Override
+ public boolean onScale(ScaleGestureDetector detector) {
+ mLiveScale *= detector.getScaleFactor();
+ relayout();
+ return true;
+ }
+ };
}
}
diff --git a/samples/AndroidXDemos/src/main/java/com/example/androidx/media/Player.java b/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/Player.java
similarity index 63%
rename from samples/AndroidXDemos/src/main/java/com/example/androidx/media/Player.java
rename to samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/Player.java
index 3ccd49d..d98da84 100644
--- a/samples/AndroidXDemos/src/main/java/com/example/androidx/media/Player.java
+++ b/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/Player.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright 2022 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.
@@ -14,11 +14,12 @@
* limitations under the License.
*/
-package com.example.androidx.media;
+package com.example.androidx.mediarouting;
import static android.support.v4.media.session.PlaybackStateCompat.ACTION_PAUSE;
import static android.support.v4.media.session.PlaybackStateCompat.ACTION_PLAY;
+import android.Manifest;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
@@ -26,6 +27,7 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.os.Build;
import android.support.v4.media.MediaMetadataCompat;
@@ -34,13 +36,17 @@
import android.util.Log;
import android.view.KeyEvent;
+import androidx.annotation.DoNotInline;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
+import androidx.core.app.ActivityCompat;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
+import androidx.media.session.MediaButtonReceiver;
import androidx.mediarouter.media.MediaControlIntent;
import androidx.mediarouter.media.MediaRouter.RouteInfo;
-import com.example.androidx.R;
/**
* Abstraction of common playback operations of media items, such as play,
* seek, etc. Used by PlaybackManager as a backend to handle actual playback
@@ -51,68 +57,147 @@
public abstract class Player {
private static final String TAG = "SampleMediaRoutePlayer";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
- protected static final int STATE_IDLE = 0;
- protected static final int STATE_PREPARING_FOR_PLAY = 1;
- protected static final int STATE_PREPARING_FOR_PAUSE = 2;
- protected static final int STATE_READY = 3;
- protected static final int STATE_PLAYING = 4;
- protected static final int STATE_PAUSED = 5;
+ public static final int STATE_IDLE = 0;
+ public static final int STATE_PREPARING_FOR_PLAY = 1;
+ public static final int STATE_PREPARING_FOR_PAUSE = 2;
+ public static final int STATE_READY = 3;
+ public static final int STATE_PLAYING = 4;
+ public static final int STATE_PAUSED = 5;
protected static final String NOTIFICATION_CHANNEL_ID =
"com.example.androidx.media.channel";
protected static final int NOTIFICATION_ID = 1;
- private static final long PLAYBACK_ACTIONS = PlaybackStateCompat.ACTION_PAUSE
- | PlaybackStateCompat.ACTION_PLAY;
+ private static final long PLAYBACK_ACTIONS = ACTION_PAUSE
+ | ACTION_PLAY;
private static final PlaybackStateCompat INIT_PLAYBACK_STATE = new PlaybackStateCompat.Builder()
.setState(PlaybackStateCompat.STATE_NONE, 0, .0f).build();
+ @NonNull
protected Context mContext;
+ @NonNull
protected Callback mCallback;
+ @NonNull
protected MediaSessionCompat mMediaSession;
+ @NonNull
protected String mNotificationChannelId;
private NotificationCompat.Action mPlayAction;
private NotificationCompat.Action mPauseAction;
+ /**
+ * Check if player is playing a remote playback.
+ * @return
+ */
public abstract boolean isRemotePlayback();
+
+ /**
+ * Returns whether the queuing is supported.
+ * @return
+ */
public abstract boolean isQueuingSupported();
- public abstract void connect(RouteInfo route);
+ /**
+ * Connects the player with a route info.
+ * @param route
+ */
+ public abstract void connect(@NonNull RouteInfo route);
+
+ /**
+ * Release the player resources.
+ */
public abstract void release();
// basic operations that are always supported
- public abstract void play(final PlaylistItem item);
- public abstract void seek(final PlaylistItem item);
- public abstract void getStatus(final PlaylistItem item, final boolean update);
+
+ /**
+ * Player play operation
+ * @param item
+ */
+ public abstract void play(@NonNull PlaylistItem item);
+
+ /**
+ * Player seek operation.
+ * @param item
+ */
+ public abstract void seek(@NonNull PlaylistItem item);
+
+ /**
+ * Get player status of an item.
+ * @param item
+ * @param update
+ */
+ public abstract void getStatus(@NonNull PlaylistItem item, boolean update);
+
+ /**
+ * Player pause operation.
+ */
public abstract void pause();
+
+ /**
+ * Player resume operation.
+ */
public abstract void resume();
+
+ /**
+ * Player step operation.
+ */
public abstract void stop();
// advanced queuing (enqueue & remove) are only supported
// if isQueuingSupported() returns true
- public abstract void enqueue(final PlaylistItem item);
- public abstract PlaylistItem remove(String iid);
- public void takeSnapshot() {}
- public Bitmap getSnapshot() { return null; }
+ /**
+ * Enqueue an item in the playlist.
+ * @param item
+ */
+ public abstract void enqueue(@NonNull PlaylistItem item);
+
+ /**
+ * Remove an item for the playlist.
+ * @param iid
+ * @return
+ */
+ @NonNull
+ public abstract PlaylistItem remove(@NonNull String iid);
+
+ /**
+ * Takes player snapshot.
+ */
+ public void takeSnapshot() {
+ }
+
+ @Nullable
+ public Bitmap getSnapshot() {
+ return null;
+ }
/**
* presentation display
*/
@RequiresApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
- public void updatePresentation() {}
+ public void updatePresentation() {
+ }
- public void setCallback(Callback callback) {
+ public void setCallback(@NonNull Callback callback) {
mCallback = callback;
}
- public static Player create(Context context, RouteInfo route, MediaSessionCompat session) {
+ /**
+ * Factory method for creating the suitable player.
+ * @param context
+ * @param route
+ * @param session
+ * @return
+ */
+ @NonNull
+ public static Player create(@NonNull Context context, @NonNull RouteInfo route,
+ @NonNull MediaSessionCompat session) {
Player player;
if (route != null && route.supportsControlCategory(
MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)) {
player = new RemotePlayer(context);
- } else if (route != null) {
+ } else if (route != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
player = new LocalPlayer.SurfaceViewPlayer(context);
} else {
player = new LocalPlayer.OverlayPlayer(context);
@@ -124,7 +209,10 @@
return player;
}
- protected void initMediaSession() {
+ /**
+ * Initialize the media session.
+ */
+ public void initMediaSession() {
if (mMediaSession == null) {
return;
}
@@ -132,7 +220,11 @@
mMediaSession.setPlaybackState(INIT_PLAYBACK_STATE);
}
- protected void updateMetadata(PlaylistItem currentItem) {
+ /**
+ * Update the player metadata.
+ * @param currentItem
+ */
+ public void updateMetadata(@NonNull PlaylistItem currentItem) {
if (mMediaSession == null) {
return;
}
@@ -167,6 +259,11 @@
.build();
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(mContext);
+ if (ActivityCompat.checkSelfPermission(mContext,
+ Manifest.permission.POST_NOTIFICATIONS)
+ != PackageManager.PERMISSION_GRANTED) {
+ return;
+ }
notificationManager.notify(NOTIFICATION_ID, notification);
}
@@ -181,14 +278,15 @@
CharSequence name = "Channel";
String description = "Description";
int importance = NotificationManager.IMPORTANCE_LOW;
- NotificationChannel channel = new NotificationChannel(
- mNotificationChannelId, name, importance);
- channel.setDescription(description);
+ NotificationChannel channel = Api26Impl.createNotificationChannel(
+ mNotificationChannelId, name.toString(), importance);
+
+ Api26Impl.setDescription(channel, description);
// Register the channel with the system; you can't change the importance
// or other notification behaviors after this
NotificationManager notificationManager =
- mContext.getSystemService(NotificationManager.class);
- notificationManager.createNotificationChannel(channel);
+ Api26Impl.getSystemServiceReturnsNotificationManager(mContext);
+ Api26Impl.createNotificationChannel(notificationManager, channel);
}
}
@@ -201,13 +299,18 @@
int keyCode = PlaybackStateCompat.toKeyCode(action);
Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
intent.setComponent(new ComponentName(mContext.getPackageName(),
- SampleMediaButtonReceiver.class.getName()));
+ MediaButtonReceiver.class.getName()));
intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, keyCode));
return PendingIntent.getBroadcast(mContext, keyCode, intent,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
}
- protected void publishState(int state) {
+
+ /**
+ * Publish the player state.
+ * @param state
+ */
+ public void publishState(int state) {
if (mMediaSession == null) {
return;
}
@@ -239,7 +342,7 @@
}
}
- private void setMediaSession(MediaSessionCompat session) {
+ private void setMediaSession(@NonNull MediaSessionCompat session) {
mMediaSession = session;
}
@@ -250,10 +353,56 @@
R.drawable.ic_media_pause, "pause", ACTION_PAUSE);
}
+ /**
+ * The player callback
+ */
public interface Callback {
+ /**
+ * On player error.
+ */
void onError();
+
+ /**
+ * On Playlist play completed.
+ */
void onCompletion();
+
+ /**
+ * On Playlist changed.
+ */
void onPlaylistChanged();
+
+ /**
+ * On playlist ready.
+ */
void onPlaylistReady();
}
+ @RequiresApi(26)
+ static class Api26Impl {
+ private Api26Impl() {
+ // This class is not instantiable.
+ }
+
+ @DoNotInline
+ static NotificationChannel createNotificationChannel(String notificationChannelId,
+ String name, int importance) {
+ return new NotificationChannel(notificationChannelId, name, importance);
+ }
+
+ @DoNotInline
+ static void createNotificationChannel(NotificationManager notificationManager,
+ NotificationChannel channel) {
+ notificationManager.createNotificationChannel(channel);
+ }
+
+ @DoNotInline
+ static void setDescription(NotificationChannel notificationChannel, String description) {
+ notificationChannel.setDescription(description);
+ }
+
+ @DoNotInline
+ static NotificationManager getSystemServiceReturnsNotificationManager(Context context) {
+ return context.getSystemService(NotificationManager.class);
+ }
+ }
}
diff --git a/samples/AndroidXDemos/src/main/java/com/example/androidx/media/PlaylistItem.java b/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/PlaylistItem.java
similarity index 73%
rename from samples/AndroidXDemos/src/main/java/com/example/androidx/media/PlaylistItem.java
rename to samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/PlaylistItem.java
index b5c50b1d..29f68eb 100644
--- a/samples/AndroidXDemos/src/main/java/com/example/androidx/media/PlaylistItem.java
+++ b/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/PlaylistItem.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright 2022 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.
@@ -14,18 +14,19 @@
* limitations under the License.
*/
-package com.example.androidx.media;
+package com.example.androidx.mediarouting;
import android.app.PendingIntent;
import android.net.Uri;
import android.os.SystemClock;
+import androidx.annotation.NonNull;
import androidx.mediarouter.media.MediaItemStatus;
/**
* PlaylistItem helps keep track of the current status of an media item.
*/
-final class PlaylistItem {
+public final class PlaylistItem {
// immutables
private final String mSessionId;
private final String mItemId;
@@ -40,7 +41,7 @@
private long mTimestamp;
private String mRemoteItemId;
- PlaylistItem(PlaylistItem item) {
+ public PlaylistItem(@NonNull PlaylistItem item) {
mSessionId = item.mSessionId;
mItemId = item.mItemId;
mTitle = item.mTitle;
@@ -55,8 +56,8 @@
mRemoteItemId = item.mRemoteItemId;
}
- public PlaylistItem(String qid, String iid, String title, Uri uri, String mime,
- PendingIntent pi) {
+ public PlaylistItem(@NonNull String qid, @NonNull String iid, @NonNull String title,
+ @NonNull Uri uri, @NonNull String mime, @NonNull PendingIntent pi) {
mSessionId = qid;
mItemId = iid;
mTitle = title;
@@ -66,7 +67,7 @@
setTimestamp(SystemClock.elapsedRealtime());
}
- public void setRemoteItemId(String riid) {
+ public void setRemoteItemId(@NonNull String riid) {
mRemoteItemId = riid;
}
@@ -86,30 +87,37 @@
mContentDuration = duration;
}
+ @NonNull
public String getSessionId() {
return mSessionId;
}
+ @NonNull
public String getItemId() {
return mItemId;
}
+ @NonNull
public String getRemoteItemId() {
return mRemoteItemId;
}
+ @NonNull
public String getTitle() {
return mTitle;
}
+ @NonNull
public Uri getUri() {
return mUri;
}
+ @NonNull
public String getMime() {
return mMime;
}
+ @NonNull
public PendingIntent getUpdateReceiver() {
return mUpdateReceiver;
}
@@ -130,28 +138,30 @@
return mTimestamp;
}
+ @NonNull
public MediaItemStatus getStatus() {
return new MediaItemStatus.Builder(mPlaybackState)
- .setContentPosition(mContentPosition)
- .setContentDuration(mContentDuration)
- .setTimestamp(mTimestamp)
- .build();
+ .setContentPosition(mContentPosition)
+ .setContentDuration(mContentDuration)
+ .setTimestamp(mTimestamp)
+ .build();
}
+ @NonNull
@Override
public String toString() {
- String state[] = {
- "PENDING",
- "PLAYING",
- "PAUSED",
- "BUFFERING",
- "FINISHED",
- "CANCELED",
- "INVALIDATED",
- "ERROR"
+ String[] state = {
+ "PENDING",
+ "PLAYING",
+ "PAUSED",
+ "BUFFERING",
+ "FINISHED",
+ "CANCELED",
+ "INVALIDATED",
+ "ERROR"
};
return "[" + mSessionId + "|" + mItemId + "|"
- + (mRemoteItemId != null ? mRemoteItemId : "-") + "|"
- + state[mPlaybackState] + "] " + mTitle + ": " + mUri.toString();
+ + (mRemoteItemId != null ? mRemoteItemId : "-") + "|"
+ + state[mPlaybackState] + "] " + mTitle + ": " + mUri.toString();
}
}
diff --git a/samples/AndroidXDemos/src/main/java/com/example/androidx/media/RemotePlayer.java b/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/RemotePlayer.java
similarity index 79%
rename from samples/AndroidXDemos/src/main/java/com/example/androidx/media/RemotePlayer.java
rename to samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/RemotePlayer.java
index db07e51..2990d44 100644
--- a/samples/AndroidXDemos/src/main/java/com/example/androidx/media/RemotePlayer.java
+++ b/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/RemotePlayer.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright 2022 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.example.androidx.media;
+package com.example.androidx.mediarouting;
import android.content.Context;
import android.content.Intent;
@@ -22,6 +22,7 @@
import android.os.Bundle;
import android.util.Log;
+import androidx.annotation.NonNull;
import androidx.mediarouter.media.MediaItemStatus;
import androidx.mediarouter.media.MediaRouter.ControlRequestCallback;
import androidx.mediarouter.media.MediaRouter.RouteInfo;
@@ -53,8 +54,8 @@
private StatusCallback mStatusCallback = new StatusCallback() {
@Override
public void onItemStatusChanged(Bundle data,
- String sessionId, MediaSessionStatus sessionStatus,
- String itemId, MediaItemStatus itemStatus) {
+ @NonNull String sessionId, MediaSessionStatus sessionStatus,
+ @NonNull String itemId, @NonNull MediaItemStatus itemStatus) {
logStatus("onItemStatusChanged", sessionId, sessionStatus, itemId, itemStatus);
if (mCallback != null) {
mCallback.onPlaylistChanged();
@@ -69,7 +70,7 @@
@Override
public void onSessionStatusChanged(Bundle data,
- String sessionId, MediaSessionStatus sessionStatus) {
+ @NonNull String sessionId, MediaSessionStatus sessionStatus) {
logStatus("onSessionStatusChanged", sessionId, sessionStatus, null, null);
if (mCallback != null) {
mCallback.onPlaylistChanged();
@@ -84,7 +85,7 @@
}
};
- public RemotePlayer(Context context) {
+ public RemotePlayer(@NonNull Context context) {
mContext = context;
}
@@ -99,7 +100,7 @@
}
@Override
- public void connect(RouteInfo route) {
+ public void connect(@NonNull RouteInfo route) {
mRoute = route;
mClient = new RemotePlaybackClient(mContext, route);
mClient.setStatusCallback(mStatusCallback);
@@ -107,7 +108,7 @@
if (DEBUG) {
Log.d(TAG, "connected to: " + route
+ ", isRemotePlaybackSupported: " + mClient.isRemotePlaybackSupported()
- + ", isQueuingSupported: "+ mClient.isQueuingSupported());
+ + ", isQueuingSupported: " + mClient.isQueuingSupported());
}
}
@@ -122,41 +123,42 @@
// basic playback operations that are always supported
@Override
- public void play(final PlaylistItem item) {
+ public void play(final @NonNull PlaylistItem item) {
if (DEBUG) {
Log.d(TAG, "play: item=" + item);
}
mClient.play(item.getUri(), item.getMime(), null, item.getPosition(), null,
new ItemActionCallback() {
- @Override
- public void onResult(Bundle data, String sessionId, MediaSessionStatus sessionStatus,
- String itemId, MediaItemStatus itemStatus) {
- logStatus("play: succeeded", sessionId, sessionStatus, itemId, itemStatus);
- item.setRemoteItemId(itemId);
- if (item.getState() == MediaItemStatus.PLAYBACK_STATE_PAUSED) {
- pause();
- } else {
- publishState(STATE_PLAYING);
- }
- if (mCallback != null) {
- mCallback.onPlaylistChanged();
- }
- }
+ @Override
+ public void onResult(@NonNull Bundle data, @NonNull String sessionId,
+ MediaSessionStatus sessionStatus,
+ @NonNull String itemId, @NonNull MediaItemStatus itemStatus) {
+ logStatus("play: succeeded", sessionId, sessionStatus, itemId, itemStatus);
+ item.setRemoteItemId(itemId);
+ if (item.getState() == MediaItemStatus.PLAYBACK_STATE_PAUSED) {
+ pause();
+ } else {
+ publishState(STATE_PLAYING);
+ }
+ if (mCallback != null) {
+ mCallback.onPlaylistChanged();
+ }
+ }
- @Override
- public void onError(String error, int code, Bundle data) {
- logError("play: failed", error, code);
- }
- });
+ @Override
+ public void onError(String error, int code, Bundle data) {
+ logError("play: failed", error, code);
+ }
+ });
}
@Override
- public void seek(final PlaylistItem item) {
+ public void seek(final @NonNull PlaylistItem item) {
seekInternal(item);
}
@Override
- public void getStatus(final PlaylistItem item, final boolean update) {
+ public void getStatus(final @NonNull PlaylistItem item, final boolean update) {
if (!mClient.hasSession() || item.getRemoteItemId() == null) {
// if session is not valid or item id not assigend yet.
// just return, it's not fatal
@@ -168,8 +170,9 @@
}
mClient.getStatus(item.getRemoteItemId(), null, new ItemActionCallback() {
@Override
- public void onResult(Bundle data, String sessionId, MediaSessionStatus sessionStatus,
- String itemId, MediaItemStatus itemStatus) {
+ public void onResult(@NonNull Bundle data, @NonNull String sessionId,
+ MediaSessionStatus sessionStatus, @NonNull String itemId,
+ @NonNull MediaItemStatus itemStatus) {
logStatus("getStatus: succeeded", sessionId, sessionStatus, itemId, itemStatus);
int state = itemStatus.getPlaybackState();
if (state == MediaItemStatus.PLAYBACK_STATE_PLAYING
@@ -206,7 +209,8 @@
}
mClient.pause(null, new SessionActionCallback() {
@Override
- public void onResult(Bundle data, String sessionId, MediaSessionStatus sessionStatus) {
+ public void onResult(@NonNull Bundle data, @NonNull String sessionId,
+ MediaSessionStatus sessionStatus) {
logStatus("pause: succeeded", sessionId, sessionStatus, null, null);
if (mCallback != null) {
mCallback.onPlaylistChanged();
@@ -232,7 +236,8 @@
}
mClient.resume(null, new SessionActionCallback() {
@Override
- public void onResult(Bundle data, String sessionId, MediaSessionStatus sessionStatus) {
+ public void onResult(@NonNull Bundle data, @NonNull String sessionId,
+ MediaSessionStatus sessionStatus) {
logStatus("resume: succeeded", sessionId, sessionStatus, null, null);
if (mCallback != null) {
mCallback.onPlaylistChanged();
@@ -259,7 +264,8 @@
}
mClient.stop(null, new SessionActionCallback() {
@Override
- public void onResult(Bundle data, String sessionId, MediaSessionStatus sessionStatus) {
+ public void onResult(@NonNull Bundle data, @NonNull String sessionId,
+ MediaSessionStatus sessionStatus) {
logStatus("stop: succeeded", sessionId, sessionStatus, null, null);
if (mClient.isSessionManagementSupported()) {
endSession();
@@ -278,7 +284,7 @@
// enqueue & remove are only supported if isQueuingSupported() returns true
@Override
- public void enqueue(final PlaylistItem item) {
+ public void enqueue(final @NonNull PlaylistItem item) {
throwIfQueuingUnsupported();
if (!mClient.hasSession() && !mEnqueuePending) {
@@ -288,15 +294,16 @@
} else {
enqueueInternal(item);
}
- } else if (mEnqueuePending){
+ } else if (mEnqueuePending) {
mTempQueue.add(item);
} else {
enqueueInternal(item);
}
}
+ @NonNull
@Override
- public PlaylistItem remove(String itemId) {
+ public PlaylistItem remove(@NonNull String itemId) {
throwIfNoSession();
throwIfQueuingUnsupported();
@@ -305,8 +312,9 @@
}
mClient.remove(itemId, null, new ItemActionCallback() {
@Override
- public void onResult(Bundle data, String sessionId, MediaSessionStatus sessionStatus,
- String itemId, MediaItemStatus itemStatus) {
+ public void onResult(@NonNull Bundle data, @NonNull String sessionId,
+ MediaSessionStatus sessionStatus, @NonNull String itemId,
+ @NonNull MediaItemStatus itemStatus) {
logStatus("remove: succeeded", sessionId, sessionStatus, itemId, itemStatus);
}
@@ -349,6 +357,7 @@
}
}
+ @NonNull
@Override
public Bitmap getSnapshot() {
return mSnapshot;
@@ -362,8 +371,9 @@
}
mClient.enqueue(item.getUri(), item.getMime(), null, 0, null, new ItemActionCallback() {
@Override
- public void onResult(Bundle data, String sessionId, MediaSessionStatus sessionStatus,
- String itemId, MediaItemStatus itemStatus) {
+ public void onResult(@NonNull Bundle data, @NonNull String sessionId,
+ MediaSessionStatus sessionStatus, @NonNull String itemId,
+ @NonNull MediaItemStatus itemStatus) {
logStatus("enqueue: succeeded", sessionId, sessionStatus, itemId, itemStatus);
item.setRemoteItemId(itemId);
if (item.getPosition() > 0) {
@@ -403,26 +413,28 @@
Log.d(TAG, "seek: item=" + item);
}
mClient.seek(item.getRemoteItemId(), item.getPosition(), null, new ItemActionCallback() {
- @Override
- public void onResult(Bundle data, String sessionId, MediaSessionStatus sessionStatus,
- String itemId, MediaItemStatus itemStatus) {
- logStatus("seek: succeeded", sessionId, sessionStatus, itemId, itemStatus);
- if (mCallback != null) {
- mCallback.onPlaylistChanged();
- }
- }
+ @Override
+ public void onResult(@NonNull Bundle data, @NonNull String sessionId,
+ MediaSessionStatus sessionStatus, @NonNull String itemId,
+ @NonNull MediaItemStatus itemStatus) {
+ logStatus("seek: succeeded", sessionId, sessionStatus, itemId, itemStatus);
+ if (mCallback != null) {
+ mCallback.onPlaylistChanged();
+ }
+ }
- @Override
- public void onError(String error, int code, Bundle data) {
- logError("seek: failed", error, code);
- }
+ @Override
+ public void onError(String error, int code, Bundle data) {
+ logError("seek: failed", error, code);
+ }
});
}
private void startSession(final PlaylistItem item) {
mClient.startSession(null, new SessionActionCallback() {
@Override
- public void onResult(Bundle data, String sessionId, MediaSessionStatus sessionStatus) {
+ public void onResult(@NonNull Bundle data, @NonNull String sessionId,
+ MediaSessionStatus sessionStatus) {
logStatus("startSession: succeeded", sessionId, sessionStatus, null, null);
enqueueInternal(item);
}
@@ -437,7 +449,8 @@
private void endSession() {
mClient.endSession(null, new SessionActionCallback() {
@Override
- public void onResult(Bundle data, String sessionId, MediaSessionStatus sessionStatus) {
+ public void onResult(@NonNull Bundle data, @NonNull String sessionId,
+ MediaSessionStatus sessionStatus) {
logStatus("endSession: succeeded", sessionId, sessionStatus, null, null);
}
diff --git a/samples/AndroidXDemos/src/main/java/com/example/androidx/media/SampleDynamicGroupMrp.java b/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/SampleDynamicGroupMrp.java
similarity index 98%
rename from samples/AndroidXDemos/src/main/java/com/example/androidx/media/SampleDynamicGroupMrp.java
rename to samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/SampleDynamicGroupMrp.java
index 81ab7a8..28c53cd7 100644
--- a/samples/AndroidXDemos/src/main/java/com/example/androidx/media/SampleDynamicGroupMrp.java
+++ b/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/SampleDynamicGroupMrp.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018 The Android Open Source Project
+ * Copyright 2022 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.example.androidx.media;
+package com.example.androidx.mediarouting;
import android.app.PendingIntent;
import android.content.Context;
@@ -33,8 +33,6 @@
import androidx.mediarouter.media.MediaRouter.ControlRequestCallback;
import androidx.mediarouter.media.MediaRouter.RouteInfo;
-import com.example.androidx.R;
-
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Iterator;
@@ -63,7 +61,7 @@
}
@Override
- public RouteController onCreateRouteController(String routeId) {
+ public RouteController onCreateRouteController(@NonNull String routeId) {
if (!checkDrawOverlay()) return null;
MediaRouteDescriptor routeDescriptor = mRouteDescriptors.get(routeId);
@@ -484,7 +482,7 @@
}
@Override
- public boolean onControlRequest(Intent intent, ControlRequestCallback callback) {
+ public boolean onControlRequest(@NonNull Intent intent, ControlRequestCallback callback) {
Log.d(TAG, mRouteId + ": Received control request " + intent);
for (RouteController controller : getValidMemberControllers()) {
controller.onControlRequest(intent, callback);
diff --git a/samples/AndroidXDemos/src/main/java/com/example/androidx/media/SampleDynamicGroupMrpService.java b/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/SampleDynamicGroupMrpService.java
similarity index 87%
rename from samples/AndroidXDemos/src/main/java/com/example/androidx/media/SampleDynamicGroupMrpService.java
rename to samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/SampleDynamicGroupMrpService.java
index 89698ea..0cb3ce8 100644
--- a/samples/AndroidXDemos/src/main/java/com/example/androidx/media/SampleDynamicGroupMrpService.java
+++ b/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/SampleDynamicGroupMrpService.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018 The Android Open Source Project
+ * Copyright 2022 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.
@@ -14,8 +14,9 @@
* limitations under the License.
*/
-package com.example.androidx.media;
+package com.example.androidx.mediarouting;
+import androidx.annotation.NonNull;
import androidx.mediarouter.media.MediaRouteProvider;
import androidx.mediarouter.media.MediaRouteProviderService;
@@ -26,6 +27,7 @@
* @see SampleDynamicGroupMrp
*/
public class SampleDynamicGroupMrpService extends MediaRouteProviderService {
+ @NonNull
@Override
public MediaRouteProvider onCreateMediaRouteProvider() {
return new SampleDynamicGroupMrp(this);
diff --git a/samples/AndroidXDemos/src/main/java/com/example/androidx/media/SampleMediaButtonReceiver.java b/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/SampleMediaButtonReceiver.java
similarity index 72%
rename from samples/AndroidXDemos/src/main/java/com/example/androidx/media/SampleMediaButtonReceiver.java
rename to samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/SampleMediaButtonReceiver.java
index b8f236a..c019bf8 100644
--- a/samples/AndroidXDemos/src/main/java/com/example/androidx/media/SampleMediaButtonReceiver.java
+++ b/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/SampleMediaButtonReceiver.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright 2022 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.
@@ -14,12 +14,13 @@
* limitations under the License.
*/
-package com.example.androidx.media;
+package com.example.androidx.mediarouting;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
-import android.view.KeyEvent;
+
+import androidx.annotation.NonNull;
/**
* Broadcast receiver for handling ACTION_MEDIA_BUTTON.
@@ -31,17 +32,16 @@
@SuppressWarnings("deprecation")
public class SampleMediaButtonReceiver extends BroadcastReceiver {
private static final String TAG = "SampleMediaButtonReceiver";
- private static SampleMediaRouterActivity mActivity;
+ private static SampleMediaRouterActivity sActivity;
- public static void setActivity(SampleMediaRouterActivity activity) {
- mActivity = activity;
+ public static void setActivity(@NonNull SampleMediaRouterActivity activity) {
+ sActivity = activity;
}
@Override
public void onReceive(Context context, Intent intent) {
- if (mActivity != null && Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())) {
- mActivity.handleMediaKey(
- (KeyEvent)intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT));
+ if (sActivity != null && Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())) {
+ sActivity.handleMediaKey(intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT));
}
}
}
diff --git a/samples/AndroidXDemos/src/main/java/com/example/androidx/media/SampleMediaRouteProvider.java b/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/SampleMediaRouteProvider.java
similarity index 96%
rename from samples/AndroidXDemos/src/main/java/com/example/androidx/media/SampleMediaRouteProvider.java
rename to samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/SampleMediaRouteProvider.java
index 98abca4e..69a14bd 100644
--- a/samples/AndroidXDemos/src/main/java/com/example/androidx/media/SampleMediaRouteProvider.java
+++ b/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/SampleMediaRouteProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright 2022 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.example.androidx.media;
+package com.example.androidx.mediarouting;
import android.app.PendingIntent;
import android.content.Context;
@@ -31,6 +31,9 @@
import android.provider.Settings;
import android.util.Log;
+import androidx.annotation.DoNotInline;
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
import androidx.collection.ArrayMap;
import androidx.mediarouter.media.MediaControlIntent;
import androidx.mediarouter.media.MediaRouteDescriptor;
@@ -40,8 +43,6 @@
import androidx.mediarouter.media.MediaRouter.RouteInfo;
import androidx.mediarouter.media.MediaSessionStatus;
-import com.example.androidx.R;
-
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
@@ -155,14 +156,14 @@
protected Map<String, Integer> mVolumes = new ArrayMap<>();
protected Map<String, MediaRouteDescriptor> mRouteDescriptors = new HashMap<>();
- public SampleMediaRouteProvider(Context context) {
+ SampleMediaRouteProvider(Context context) {
super(context);
initializeRoutes();
publishRoutes();
}
@Override
- public RouteController onCreateRouteController(String routeId) {
+ public RouteController onCreateRouteController(@NonNull String routeId) {
if (!checkDrawOverlay()) return null;
return new SampleRouteController(routeId);
}
@@ -250,7 +251,7 @@
}
boolean checkDrawOverlay() {
- if (Build.VERSION.SDK_INT >= 23 && !Settings.canDrawOverlays(getContext())) {
+ if (Build.VERSION.SDK_INT >= 23 && !Api23Impl.canDrawOverlays(getContext())) {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getContext().getPackageName()));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
@@ -268,7 +269,7 @@
return volume;
}
- final class SampleRouteController extends MediaRouteProvider.RouteController {
+ final class SampleRouteController extends RouteController {
private final String mRouteId;
private RouteControlHelper mHelper;
@@ -329,7 +330,7 @@
}
@Override
- public boolean onControlRequest(Intent intent, ControlRequestCallback callback) {
+ public boolean onControlRequest(@NonNull Intent intent, ControlRequestCallback callback) {
Log.d(TAG, mRouteId + ": Received control request " + intent);
return mHelper.onControlRequest(intent, callback);
}
@@ -356,7 +357,7 @@
}
@Override
- public void onItemChanged(PlaylistItem item) {
+ public void onItemChanged(@NonNull PlaylistItem item) {
handleStatusChange(item);
}
});
@@ -716,4 +717,15 @@
}
}
}
+ @RequiresApi(23)
+ static class Api23Impl {
+ private Api23Impl() {
+ // This class is not instantiable.
+ }
+
+ @DoNotInline
+ static boolean canDrawOverlays(Context context) {
+ return Settings.canDrawOverlays(context);
+ }
+ }
}
diff --git a/samples/AndroidXDemos/src/main/java/com/example/androidx/media/SampleMediaRouteProviderService.java b/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/SampleMediaRouteProviderService.java
similarity index 87%
rename from samples/AndroidXDemos/src/main/java/com/example/androidx/media/SampleMediaRouteProviderService.java
rename to samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/SampleMediaRouteProviderService.java
index 0f17e65..4b42632 100644
--- a/samples/AndroidXDemos/src/main/java/com/example/androidx/media/SampleMediaRouteProviderService.java
+++ b/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/SampleMediaRouteProviderService.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright 2022 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.
@@ -14,8 +14,9 @@
* limitations under the License.
*/
-package com.example.androidx.media;
+package com.example.androidx.mediarouting;
+import androidx.annotation.NonNull;
import androidx.mediarouter.media.MediaRouteProvider;
import androidx.mediarouter.media.MediaRouteProviderService;
@@ -26,6 +27,7 @@
* @see SampleMediaRouteProvider
*/
public class SampleMediaRouteProviderService extends MediaRouteProviderService {
+ @NonNull
@Override
public MediaRouteProvider onCreateMediaRouteProvider() {
return new SampleMediaRouteProvider(this);
diff --git a/samples/AndroidXDemos/src/main/java/com/example/androidx/media/SampleMediaRouteSettingsActivity.java b/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/SampleMediaRouteSettingsActivity.java
similarity index 89%
rename from samples/AndroidXDemos/src/main/java/com/example/androidx/media/SampleMediaRouteSettingsActivity.java
rename to samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/SampleMediaRouteSettingsActivity.java
index 4e66493..554555d 100644
--- a/samples/AndroidXDemos/src/main/java/com/example/androidx/media/SampleMediaRouteSettingsActivity.java
+++ b/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/SampleMediaRouteSettingsActivity.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright 2022 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.example.androidx.media;
+package com.example.androidx.mediarouting;
import androidx.appcompat.app.AppCompatActivity;
diff --git a/samples/AndroidXDemos/src/main/java/com/example/androidx/media/SampleMediaRouterActivity.java b/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/SampleMediaRouterActivity.java
similarity index 93%
rename from samples/AndroidXDemos/src/main/java/com/example/androidx/media/SampleMediaRouterActivity.java
rename to samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/SampleMediaRouterActivity.java
index e51f9b7..1177d9f9 100644
--- a/samples/AndroidXDemos/src/main/java/com/example/androidx/media/SampleMediaRouterActivity.java
+++ b/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/SampleMediaRouterActivity.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright 2022 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.example.androidx.media;
+package com.example.androidx.mediarouting;
import android.app.PendingIntent;
import android.content.ComponentName;
@@ -65,8 +65,6 @@
import androidx.mediarouter.media.MediaRouter.RouteInfo;
import androidx.mediarouter.media.MediaRouterParams;
-import com.example.androidx.R;
-
import java.io.File;
/**
@@ -78,7 +76,6 @@
* targets.
* </p>
*/
-@SuppressWarnings("deprecation")
public class SampleMediaRouterActivity extends AppCompatActivity {
private static final String TAG = "SampleMediaRouter";
private static final String DISCOVERY_FRAGMENT_TAG = "DiscoveryFragment";
@@ -145,16 +142,16 @@
updateUi();
}
- @SuppressWarnings("deprecation")
@Override
- public void onRouteUnselected(@NonNull MediaRouter router, @NonNull RouteInfo route) {
+ public void onRouteUnselected(@NonNull MediaRouter router, @NonNull RouteInfo route,
+ int reason) {
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()));
+ long pos = item.getPosition() + (mSessionManager.isPaused()
+ ? 0 : (SystemClock.elapsedRealtime() - item.getTimestamp()));
mSessionManager.suspend(pos);
}
if (isPresentationApiSupported()) {
@@ -201,7 +198,6 @@
private ComponentName mEventReceiver;
private PendingIntent mMediaPendingIntent;
- @SuppressWarnings("deprecation")
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
// Be sure to call the super class.
@@ -283,17 +279,17 @@
TabHost tabHost = findViewById(R.id.tabHost);
tabHost.setup();
String tabName = getResources().getString(R.string.library_tab_text);
- TabSpec spec1=tabHost.newTabSpec(tabName);
+ 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);
+ 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);
+ TabSpec spec3 = tabHost.newTabSpec(tabName);
spec3.setIndicator(tabName);
spec3.setContent(R.id.tab3);
@@ -344,7 +340,8 @@
}
@Override
- public void onStartTrackingTouch(SeekBar seekBar) { }
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ }
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
@@ -361,7 +358,7 @@
Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
mediaButtonIntent.setComponent(mEventReceiver);
mMediaPendingIntent = PendingIntent.getBroadcast(this, /* requestCode = */0,
- mediaButtonIntent, PendingIntent.FLAG_IMMUTABLE);
+ mediaButtonIntent, PendingIntent.FLAG_IMMUTABLE);
// Create and register the remote control client
createMediaSession();
@@ -379,7 +376,8 @@
}
@Override
- public void onItemChanged(PlaylistItem item) { }
+ public void onItemChanged(@NonNull PlaylistItem item) {
+ }
});
updateUi();
@@ -421,8 +419,7 @@
&& event.getRepeatCount() == 0) {
switch (event.getKeyCode()) {
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
- case KeyEvent.KEYCODE_HEADSETHOOK:
- {
+ case KeyEvent.KEYCODE_HEADSETHOOK: {
Log.d(TAG, "Received Play/Pause event from RemoteControlClient");
if (mSessionManager.isPaused()) {
mSessionManager.resume();
@@ -431,24 +428,21 @@
}
return true;
}
- case KeyEvent.KEYCODE_MEDIA_PLAY:
- {
+ 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:
- {
+ 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:
- {
+ case KeyEvent.KEYCODE_MEDIA_STOP: {
Log.d(TAG, "Received Stop event from RemoteControlClient");
mSessionManager.stop();
return true;
@@ -503,7 +497,7 @@
@Override
public MediaRouteControllerDialogFragment onCreateControllerDialogFragment() {
return new ControllerDialogFragment(SampleMediaRouterActivity.this,
- mUseDefaultControlCheckBox);
+ mUseDefaultControlCheckBox);
}
});
}
@@ -534,9 +528,9 @@
}
} else {
long position = item.getPosition();
- long timeDelta = mSessionManager.isPaused() ? 0 :
- (SystemClock.elapsedRealtime() - item.getTimestamp());
- progress = (int)(100.0 * (position + timeDelta) / duration);
+ long timeDelta = mSessionManager.isPaused()
+ ? 0 : (SystemClock.elapsedRealtime() - item.getTimestamp());
+ progress = (int) (100.0 * (position + timeDelta) / duration);
}
}
mSeekBar.setProgress(progress);
@@ -551,7 +545,7 @@
if (currentItem != null) {
mPlayer.updateMetadata(currentItem);
int currentItemState = Player.STATE_IDLE;
- switch(currentItem.getState()) {
+ switch (currentItem.getState()) {
case MediaItemStatus.PLAYBACK_STATE_PLAYING:
currentItemState = Player.STATE_PLAYING;
break;
@@ -585,8 +579,8 @@
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);
+ 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);
@@ -640,7 +634,7 @@
public final Uri mUri;
public final String mMime;
- public MediaItem(String name, Uri uri, String mime) {
+ MediaItem(String name, Uri uri, String mime) {
mName = name;
mUri = uri;
mMime = mime;
@@ -654,7 +648,7 @@
}
private final class LibraryAdapter extends ArrayAdapter<MediaItem> {
- public LibraryAdapter() {
+ LibraryAdapter() {
super(SampleMediaRouterActivity.this, R.layout.media_item);
}
@@ -682,7 +676,7 @@
}
private final class PlaylistAdapter extends ArrayAdapter<PlaylistItem> {
- public PlaylistAdapter() {
+ PlaylistAdapter() {
super(SampleMediaRouterActivity.this, R.layout.media_item);
}
@@ -724,7 +718,7 @@
}
/**
- * This will show dynamic group dialog when ther user clicks the media route button.
+ * This will show dynamic group dialog when the user clicks the media route button.
*/
public static class DynamicGroupActivity extends SampleMediaRouterActivity {
@NonNull
@@ -762,6 +756,9 @@
}
}
+ /**
+ * Controller Dialog Fragment for the media router dialog.
+ */
public static class ControllerDialogFragment extends MediaRouteControllerDialogFragment {
private SampleMediaRouterActivity mSampleMediaRouterActivity;
private MediaRouteControllerDialog mControllerDialog;
@@ -784,8 +781,8 @@
mSampleMediaRouterActivity.updateStatusFromSessionManager();
mControllerDialog =
mUseDefaultControlCheckBox != null && mUseDefaultControlCheckBox.isChecked()
- ? super.onCreateControllerDialog(context, savedInstanceState)
- : new MyMediaRouteControllerDialog(context);
+ ? super.onCreateControllerDialog(context, savedInstanceState)
+ : new MyMediaRouteControllerDialog(context);
mControllerDialog.setOnDismissListener(dialog -> mControllerDialog = null);
return mControllerDialog;
}
diff --git a/samples/AndroidXDemos/src/main/java/com/example/androidx/media/SessionManager.java b/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/SessionManager.java
similarity index 80%
rename from samples/AndroidXDemos/src/main/java/com/example/androidx/media/SessionManager.java
rename to samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/SessionManager.java
index e7d706f..cfa9cd6 100644
--- a/samples/AndroidXDemos/src/main/java/com/example/androidx/media/SessionManager.java
+++ b/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/SessionManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright 2022 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.
@@ -14,12 +14,14 @@
* limitations under the License.
*/
-package com.example.androidx.media;
+package com.example.androidx.mediarouting;
import android.app.PendingIntent;
import android.net.Uri;
import android.util.Log;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.mediarouter.media.MediaItemStatus;
import androidx.mediarouter.media.MediaSessionStatus;
@@ -47,7 +49,7 @@
private Callback mCallback;
private List<PlaylistItem> mPlaylist = new ArrayList<PlaylistItem>();
- public SessionManager(String name) {
+ public SessionManager(@NonNull String name) {
mName = name;
}
@@ -55,24 +57,34 @@
return hasSession() && mPaused;
}
+ /**
+ * Returns if the session manager has a session or not.
+ */
public boolean hasSession() {
return mSessionValid;
}
+ @Nullable
public String getSessionId() {
return mSessionValid ? Integer.toString(mSessionId) : null;
}
+ @Nullable
public PlaylistItem getCurrentItem() {
return mPlaylist.isEmpty() ? null : mPlaylist.get(0);
}
// Returns the cached playlist (note this is not responsible for updating it)
+ @Nullable
public List<PlaylistItem> getPlaylist() {
return mPlaylist;
}
// Updates the playlist asynchronously, calls onPlaylistReady() when finished.
+
+ /**
+ * Updates the session status.
+ */
public void updateStatus() {
if (DEBUG) {
log("updateStatus");
@@ -100,12 +112,20 @@
}
}
- public PlaylistItem add(String title, Uri uri, String mime) {
+ /**
+ * Adds an item to the playlist.
+ */
+ @NonNull
+ public PlaylistItem add(@NonNull String title, @NonNull Uri uri, @NonNull String mime) {
return add(title, uri, mime, 0, null);
}
- public PlaylistItem add(String title, Uri uri, String mime, long startPosition,
- PendingIntent receiver) {
+ /**
+ * Adds an item to the playlist.
+ */
+ @NonNull
+ public PlaylistItem add(@NonNull String title, @NonNull Uri uri, @NonNull String mime,
+ long startPosition, @Nullable PendingIntent receiver) {
if (DEBUG) {
log("add: title=" + title + ", uri=" + uri + ", receiver=" + receiver);
}
@@ -128,7 +148,11 @@
return item;
}
- public PlaylistItem remove(String iid) {
+ /**
+ * Removes an item from the playlist.
+ */
+ @NonNull
+ public PlaylistItem remove(@NonNull String iid) {
if (DEBUG) {
log("remove: iid=" + iid);
}
@@ -136,9 +160,13 @@
return removeItem(iid, MediaItemStatus.PLAYBACK_STATE_CANCELED);
}
- public PlaylistItem seek(String iid, long pos) {
+ /**
+ * Seeks a specific position for the current item.
+ */
+ @NonNull
+ public PlaylistItem seek(@NonNull String iid, long pos) {
if (DEBUG) {
- log("seek: iid=" + iid +", pos=" + pos);
+ log("seek: iid=" + iid + ", pos=" + pos);
}
checkPlayerAndSession();
// seeking on pending items are not yet supported
@@ -155,7 +183,11 @@
return item;
}
- public PlaylistItem getStatus(String iid) {
+ /**
+ * Returns the status for the current item.
+ */
+ @NonNull
+ public PlaylistItem getStatus(@NonNull String iid) {
checkPlayerAndSession();
// This should only be called for local player. Remote player is
@@ -176,6 +208,9 @@
return null;
}
+ /**
+ * Pauses the current session.
+ */
public void pause() {
if (DEBUG) {
log("pause");
@@ -188,6 +223,9 @@
updatePlaybackState();
}
+ /**
+ * Resumes the current session.
+ */
public void resume() {
if (DEBUG) {
log("resume");
@@ -200,6 +238,9 @@
updatePlaybackState();
}
+ /**
+ * Stops the current session.
+ */
public void stop() {
if (DEBUG) {
log("stop");
@@ -214,6 +255,10 @@
updateStatus();
}
+ /**
+ * Starts the current session.
+ */
+ @Nullable
public String startSession() {
if (!mSessionValid) {
mSessionId++;
@@ -225,6 +270,9 @@
return null;
}
+ /**
+ * Ends the current session.
+ */
public boolean endSession() {
if (mSessionValid) {
mSessionValid = false;
@@ -233,7 +281,10 @@
return false;
}
- void syncWithManager(SessionManager manager) {
+ /**
+ * Syncs the current session with manager.
+ */
+ public void syncWithManager(@NonNull SessionManager manager) {
manager.updateStatus();
mSessionId = manager.mSessionId;
mItemId = manager.mItemId;
@@ -250,19 +301,25 @@
updatePlaybackState();
}
- MediaSessionStatus getSessionStatus(String sid) {
- int sessionState = (sid != null && sid.equals(Integer.toString(mSessionId))) ?
- MediaSessionStatus.SESSION_STATE_ACTIVE :
- MediaSessionStatus.SESSION_STATE_INVALIDATED;
+ /**
+ * Returns the current session status.
+ */
+ @NonNull
+ public MediaSessionStatus getSessionStatus(@NonNull String sid) {
+ int sessionState = (sid != null && sid.equals(Integer.toString(mSessionId)))
+ ? MediaSessionStatus.SESSION_STATE_ACTIVE
+ : MediaSessionStatus.SESSION_STATE_INVALIDATED;
return new MediaSessionStatus.Builder(sessionState)
.setQueuePaused(mPaused)
.build();
}
- // Suspend the playback manager. Put the current item back into PENDING
- // state, and remember the current playback position. Called when switching
- // to a different player (route).
+ /**
+ * Suspends the playback manager. Puts the current item back into PENDING
+ * state, and remembers the current playback position. Called when switching
+ * to a different player (route).
+ */
public void suspend(long pos) {
for (PlaylistItem item : mPlaylist) {
item.setRemoteItemId(null);
@@ -281,9 +338,11 @@
}
}
- // Unsuspend the playback manager. Restart playback on new player (route).
- // This will resume playback of current item. Furthermore, if the new player
- // supports queuing, playlist will be re-established on the remote player.
+ /**
+ * Unsuspends the playback manager. Restarts playback on new player (route).
+ * This will resumes playback of current item. Furthermore, if the new player
+ * supports queuing, playlist will be re-established on the remote player.
+ */
public void unsuspend() {
if (DEBUG) {
log("unsuspend");
@@ -385,7 +444,7 @@
if (mPlayer.isQueuingSupported()) {
mPlayer.remove(item.getRemoteItemId());
} else if (item.getState() == MediaItemStatus.PLAYBACK_STATE_PLAYING
- || item.getState() == MediaItemStatus.PLAYBACK_STATE_PAUSED){
+ || item.getState() == MediaItemStatus.PLAYBACK_STATE_PAUSED) {
mPlayer.stop();
}
item.setState(state);
@@ -410,25 +469,28 @@
private void finishItem(boolean error) {
PlaylistItem item = getCurrentItem();
if (item != null) {
- removeItem(item.getItemId(), error ?
- MediaItemStatus.PLAYBACK_STATE_ERROR :
- MediaItemStatus.PLAYBACK_STATE_FINISHED);
+ removeItem(item.getItemId(), error
+ ? MediaItemStatus.PLAYBACK_STATE_ERROR
+ : MediaItemStatus.PLAYBACK_STATE_FINISHED);
updateStatus();
}
}
- // set the Player that this playback manager will interact with
- public void setPlayer(Player player) {
+ /**
+ * Set the Player that this playback manager will interact with.
+ */
+ public void setPlayer(@NonNull Player player) {
mPlayer = player;
checkPlayer();
mPlayer.setCallback(this);
}
// provide a callback interface to tell the UI when significant state changes occur
- public void setCallback(Callback callback) {
+ public void setCallback(@NonNull Callback callback) {
mCallback = callback;
}
+ @NonNull
@Override
public String toString() {
String result = "Media Queue: ";
@@ -442,8 +504,18 @@
return result;
}
+ /**
+ * Session Manager callback.
+ */
public interface Callback {
+ /**
+ * Called when the status of the manager is changed.
+ */
void onStatusChanged();
- void onItemChanged(PlaylistItem item);
+
+ /**
+ * Called when the current active item is changed.
+ */
+ void onItemChanged(@NonNull PlaylistItem item);
}
}
diff --git a/samples/AndroidXDemos/src/main/java/com/example/androidx/media/_index.html b/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/_index.html
similarity index 100%
rename from samples/AndroidXDemos/src/main/java/com/example/androidx/media/_index.html
rename to samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/_index.html
diff --git a/samples/MediaRoutingDemo/src/main/res/drawable-hdpi/app_sample_code.png b/samples/MediaRoutingDemo/src/main/res/drawable-hdpi/app_sample_code.png
new file mode 100755
index 0000000..66a1984
--- /dev/null
+++ b/samples/MediaRoutingDemo/src/main/res/drawable-hdpi/app_sample_code.png
Binary files differ
diff --git a/samples/MediaRoutingDemo/src/main/res/drawable-hdpi/ic_android.png b/samples/MediaRoutingDemo/src/main/res/drawable-hdpi/ic_android.png
new file mode 100755
index 0000000..94b8fb1
--- /dev/null
+++ b/samples/MediaRoutingDemo/src/main/res/drawable-hdpi/ic_android.png
Binary files differ
diff --git a/samples/MediaRoutingDemo/src/main/res/drawable-hdpi/ic_media_pause.png b/samples/MediaRoutingDemo/src/main/res/drawable-hdpi/ic_media_pause.png
new file mode 100644
index 0000000..1d465a4
--- /dev/null
+++ b/samples/MediaRoutingDemo/src/main/res/drawable-hdpi/ic_media_pause.png
Binary files differ
diff --git a/samples/MediaRoutingDemo/src/main/res/drawable-hdpi/ic_media_play.png b/samples/MediaRoutingDemo/src/main/res/drawable-hdpi/ic_media_play.png
new file mode 100644
index 0000000..2746d17
--- /dev/null
+++ b/samples/MediaRoutingDemo/src/main/res/drawable-hdpi/ic_media_play.png
Binary files differ
diff --git a/samples/MediaRoutingDemo/src/main/res/drawable-hdpi/ic_media_stop.png b/samples/MediaRoutingDemo/src/main/res/drawable-hdpi/ic_media_stop.png
new file mode 100644
index 0000000..a0ff136
--- /dev/null
+++ b/samples/MediaRoutingDemo/src/main/res/drawable-hdpi/ic_media_stop.png
Binary files differ
diff --git a/samples/MediaRoutingDemo/src/main/res/drawable-hdpi/ic_menu_add.png b/samples/MediaRoutingDemo/src/main/res/drawable-hdpi/ic_menu_add.png
new file mode 100644
index 0000000..444e8a5
--- /dev/null
+++ b/samples/MediaRoutingDemo/src/main/res/drawable-hdpi/ic_menu_add.png
Binary files differ
diff --git a/samples/MediaRoutingDemo/src/main/res/drawable-hdpi/ic_menu_delete.png b/samples/MediaRoutingDemo/src/main/res/drawable-hdpi/ic_menu_delete.png
new file mode 100644
index 0000000..24d8f6a
--- /dev/null
+++ b/samples/MediaRoutingDemo/src/main/res/drawable-hdpi/ic_menu_delete.png
Binary files differ
diff --git a/samples/MediaRoutingDemo/src/main/res/drawable-mdpi/app_sample_code.png b/samples/MediaRoutingDemo/src/main/res/drawable-mdpi/app_sample_code.png
new file mode 100644
index 0000000..5ae7701
--- /dev/null
+++ b/samples/MediaRoutingDemo/src/main/res/drawable-mdpi/app_sample_code.png
Binary files differ
diff --git a/samples/MediaRoutingDemo/src/main/res/drawable-mdpi/ic_android.png b/samples/MediaRoutingDemo/src/main/res/drawable-mdpi/ic_android.png
new file mode 100755
index 0000000..afc43db
--- /dev/null
+++ b/samples/MediaRoutingDemo/src/main/res/drawable-mdpi/ic_android.png
Binary files differ
diff --git a/samples/MediaRoutingDemo/src/main/res/drawable-mdpi/ic_media_pause.png b/samples/MediaRoutingDemo/src/main/res/drawable-mdpi/ic_media_pause.png
new file mode 100644
index 0000000..3e6b2a1
--- /dev/null
+++ b/samples/MediaRoutingDemo/src/main/res/drawable-mdpi/ic_media_pause.png
Binary files differ
diff --git a/samples/MediaRoutingDemo/src/main/res/drawable-mdpi/ic_media_play.png b/samples/MediaRoutingDemo/src/main/res/drawable-mdpi/ic_media_play.png
new file mode 100644
index 0000000..7966bbc
--- /dev/null
+++ b/samples/MediaRoutingDemo/src/main/res/drawable-mdpi/ic_media_play.png
Binary files differ
diff --git a/samples/MediaRoutingDemo/src/main/res/drawable-mdpi/ic_media_stop.png b/samples/MediaRoutingDemo/src/main/res/drawable-mdpi/ic_media_stop.png
new file mode 100644
index 0000000..8ea7efe
--- /dev/null
+++ b/samples/MediaRoutingDemo/src/main/res/drawable-mdpi/ic_media_stop.png
Binary files differ
diff --git a/samples/MediaRoutingDemo/src/main/res/drawable-mdpi/ic_menu_add.png b/samples/MediaRoutingDemo/src/main/res/drawable-mdpi/ic_menu_add.png
new file mode 100644
index 0000000..361c7c4
--- /dev/null
+++ b/samples/MediaRoutingDemo/src/main/res/drawable-mdpi/ic_menu_add.png
Binary files differ
diff --git a/samples/MediaRoutingDemo/src/main/res/drawable-mdpi/ic_menu_delete.png b/samples/MediaRoutingDemo/src/main/res/drawable-mdpi/ic_menu_delete.png
new file mode 100644
index 0000000..e2c8700
--- /dev/null
+++ b/samples/MediaRoutingDemo/src/main/res/drawable-mdpi/ic_menu_delete.png
Binary files differ
diff --git a/samples/AndroidXDemos/src/main/res/layout/media_item.xml b/samples/MediaRoutingDemo/src/main/res/layout/media_item.xml
similarity index 100%
rename from samples/AndroidXDemos/src/main/res/layout/media_item.xml
rename to samples/MediaRoutingDemo/src/main/res/layout/media_item.xml
diff --git a/samples/MediaRoutingDemo/src/main/res/layout/overlay_display_window.xml b/samples/MediaRoutingDemo/src/main/res/layout/overlay_display_window.xml
new file mode 100644
index 0000000..1f026fe
--- /dev/null
+++ b/samples/MediaRoutingDemo/src/main/res/layout/overlay_display_window.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="#000000">
+ <TextureView tools:ignore="NewApi"
+ android:id="@+id/overlay_display_window_texture"
+ android:layout_width="0px"
+ android:layout_height="0px" />
+ <TextView android:id="@+id/overlay_display_window_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top|center_horizontal" />
+</FrameLayout>
diff --git a/samples/AndroidXDemos/src/main/res/layout/sample_media_controller.xml b/samples/MediaRoutingDemo/src/main/res/layout/sample_media_controller.xml
similarity index 100%
rename from samples/AndroidXDemos/src/main/res/layout/sample_media_controller.xml
rename to samples/MediaRoutingDemo/src/main/res/layout/sample_media_controller.xml
diff --git a/samples/AndroidXDemos/src/main/res/layout/sample_media_router.xml b/samples/MediaRoutingDemo/src/main/res/layout/sample_media_router.xml
similarity index 100%
rename from samples/AndroidXDemos/src/main/res/layout/sample_media_router.xml
rename to samples/MediaRoutingDemo/src/main/res/layout/sample_media_router.xml
diff --git a/samples/AndroidXDemos/src/main/res/layout/sample_media_router_presentation.xml b/samples/MediaRoutingDemo/src/main/res/layout/sample_media_router_presentation.xml
similarity index 100%
rename from samples/AndroidXDemos/src/main/res/layout/sample_media_router_presentation.xml
rename to samples/MediaRoutingDemo/src/main/res/layout/sample_media_router_presentation.xml
diff --git a/samples/AndroidXDemos/src/main/res/menu/sample_media_router_menu.xml b/samples/MediaRoutingDemo/src/main/res/menu/sample_media_router_menu.xml
similarity index 100%
rename from samples/AndroidXDemos/src/main/res/menu/sample_media_router_menu.xml
rename to samples/MediaRoutingDemo/src/main/res/menu/sample_media_router_menu.xml
diff --git a/samples/MediaRoutingDemo/src/main/res/values-v18/bools.xml b/samples/MediaRoutingDemo/src/main/res/values-v18/bools.xml
new file mode 100644
index 0000000..438733c
--- /dev/null
+++ b/samples/MediaRoutingDemo/src/main/res/values-v18/bools.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2019 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.
+ -->
+
+<resources>
+ <!-- True if running under JellyBean MR2 or later. -->
+ <bool name="atLeastJellyBeanMR2">true</bool>
+</resources>
\ No newline at end of file
diff --git a/samples/MediaRoutingDemo/src/main/res/values/arrays.xml b/samples/MediaRoutingDemo/src/main/res/values/arrays.xml
new file mode 100644
index 0000000..3e87f3a
--- /dev/null
+++ b/samples/MediaRoutingDemo/src/main/res/values/arrays.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<resources>
+ <string-array name="media_names">
+ <item>Big Buck Bunny</item>
+ <item>Elephants Dream</item>
+ <item>Sintel</item>
+ <item>Tears of Steel</item>
+ <item>(Music) Let\'s Dance</item>
+ </string-array>
+
+ <string-array name="media_uris">
+ <item>https://archive.org/download/BigBuckBunny_328/BigBuckBunny_512kb.mp4</item>
+ <item>https://archive.org/download/ElephantsDream_277/elephant_dreams_640_512kb.mp4</item>
+ <item>https://archive.org/download/Sintel/sintel-2048-stereo_512kb.mp4</item>
+ <item>https://archive.org/download/Tears-of-Steel/tears_of_steel_720p.mp4</item>
+ <item>https://archive.org/download/78_lets-dance-theme-song_baldridge-stone-bonime-benny-goodman-and-his-orchestra_gbia0000390b/Let%27s%20Dance%20%28Theme%20Song%29%20-%20Baldridge%20-%20Stone.mp3</item>
+ </string-array>
+
+ <string-array name="media_mimes">
+ <item>video/mp4</item>
+ <item>video/mp4</item>
+ <item>video/mp4</item>
+ <item>video/mp4</item>
+ <item>audio/mp3</item>
+ </string-array>
+</resources>
diff --git a/samples/MediaRoutingDemo/src/main/res/values/bools.xml b/samples/MediaRoutingDemo/src/main/res/values/bools.xml
new file mode 100644
index 0000000..c10c13e
--- /dev/null
+++ b/samples/MediaRoutingDemo/src/main/res/values/bools.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2019 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.
+ -->
+
+<resources>
+ <!-- This resource is true if running under at least JellyBean MR2
+ API level. The default value is false; an alternative value
+ for JellyBean MR 2 is true. -->
+ <bool name="atLeastJellyBeanMR2">false</bool>
+</resources>
diff --git a/samples/MediaRoutingDemo/src/main/res/values/strings.xml b/samples/MediaRoutingDemo/src/main/res/values/strings.xml
new file mode 100644
index 0000000..664c28a
--- /dev/null
+++ b/samples/MediaRoutingDemo/src/main/res/values/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<resources>
+ <string name="activity_sample_code">Media Routing Demo</string>
+
+ <!-- MediaRouter -->
+
+ <string name="sample_media_router_activity_dark">MediaRouter/Dark Theme</string>
+ <string name="sample_media_router_activity_light">MediaRouter/Light Theme</string>
+ <string name="sample_media_router_activity_light_with_dark_action_bar">MediaRouter/Light Theme, Dark Action Bar</string>
+ <string name="sample_media_router_activity_dynamic_group">MediaRouter/Dynamic Group
+ Dialog</string>
+ <string name="sample_media_router_activity_output_switcher">MediaRouter/Output Switcher</string>
+ <string name="sample_media_router_activity_legacy">MediaRouter/Disable MediaRouter2</string>
+ <string name="sample_media_router_text">This activity demonstrates how to
+ use MediaRouter from the support library. Select a route from the action bar.</string>
+ <string name="media_route_menu_title">Play on...</string>
+ <string name="sample_media_route_settings_activity">Sample route settings</string>
+
+ <string name="use_default_media_control">Use default media control</string>
+ <string name="my_media_control_text">My Media Control</string>
+
+ <string name="library_tab_text">Library</string>
+ <string name="playlist_tab_text">Playlist</string>
+ <string name="info_tab_text">Route Info</string>
+
+ <string name="sample_media_route_provider_service">Media Route Provider Service Support Library Sample</string>
+ <string name="fixed_volume_route_name">Fixed Volume Remote Playback Route</string>
+ <string name="variable_volume_basic_route_name">Variable Volume (Basic) Remote Playback Route</string>
+ <string name="variable_volume_queuing_route_name">Variable Volume (Queuing) Remote Playback Route</string>
+ <string name="variable_volume_session_route_name">Variable Volume (Session) Remote Playback Route</string>
+ <string name="variable_volume_route_group_name">Variable Volume Route Group</string>
+ <string name="mixed_volume_route_group_name">Mixed Volume Route Group</string>
+ <string name="sample_route_description">Sample route from AndroidXDemos</string>
+
+ <string name="sample_dynamic_group_mrp_service">Media Route Provider Service Support Library Sample (supporting dynamic group)</string>
+ <string name="dg_tv_route_name1">Dynamic Route 1 - TV</string>
+ <string name="dg_tv_route_name2">Dynamic Route 2 - TV</string>
+ <string name="dg_speaker_route_name3">Dynamic Route 3 - Speaker</string>
+ <string name="dg_speaker_route_name4">Dynamic Route 4 - Speaker</string>
+ <string name="dg_not_unselectable_route_name5"> Dynamic Route 5 - Not unselectable</string>
+ <string name="dg_static_group_route_name6"> Dynamic Route 6 - Static Group</string>
+
+ <string name="sample_media_route_provider_remote">Remote Playback (Simulated)</string>
+ <string name="sample_media_route_activity_local">Local Playback</string>
+ <string name="sample_media_route_activity_presentation">Local Playback on Presentation Display</string>
+
+ <string name="action_mode_done_content_description">Cancel</string>
+</resources>
diff --git a/samples/MediaRoutingDemo/src/main/res/values/styles.xml b/samples/MediaRoutingDemo/src/main/res/values/styles.xml
new file mode 100644
index 0000000..c914ac3
--- /dev/null
+++ b/samples/MediaRoutingDemo/src/main/res/values/styles.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+
+<resources>
+ <style name="Theme.SampleMediaRouter" parent="Theme.AppCompat">
+ <item name="colorPrimary">#fff44336</item>
+ <item name="colorPrimaryDark">#d32f2f</item>
+ </style>
+
+ <style name="Theme.SampleMediaRouter.Light" parent="Theme.AppCompat.Light">
+ <item name="colorPrimary">#ffff9800</item>
+ <item name="colorPrimaryDark">#f57c00</item>
+ </style>
+
+ <style name="Theme.SampleMediaRouter.Light.DarkActionBar" parent="Theme.AppCompat.Light.DarkActionBar">
+ <item name="colorPrimary">#ff2196f3</item>
+ <item name="colorPrimaryDark">#1976d2</item>
+ </style>
+</resources>
diff --git a/settings.gradle b/settings.gradle
index afcd43e..4e3b1e2 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -982,6 +982,7 @@
// Note: don't add new samples/ apps. Instead, Create
// <module>/integration-tests/testapp in the "Libraries" section above.
includeProject(":androidx-demos", new File(samplesRoot, "AndroidXDemos"), [BuildType.MAIN])
+includeProject(":media-routing-demo", new File(samplesRoot, "MediaRoutingDemo"), [BuildType.MAIN])
includeProject(":support-animation-demos", new File(samplesRoot, "SupportAnimationDemos"), [BuildType.MAIN])
includeProject(":support-content-demos", new File(samplesRoot, "SupportContentDemos"), [BuildType.MAIN])
includeProject(":support-emoji-demos", new File(samplesRoot, "SupportEmojiDemos"), [BuildType.MAIN])