aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDongwon Kang <dwkang@google.com>2014-08-06 00:26:00 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2014-08-04 23:56:40 +0000
commit333d3ee2cde4eebf4cf86e841cd7e844ad0da94c (patch)
treeeb84f02db0119f7faee46d1a86843e1c92418da3
parentec9bd88036279df7421321b2e9945adf8f89db4b (diff)
parent5642ac621a38ef0b69bfb42514d28d78b9569d11 (diff)
downloadTV-333d3ee2cde4eebf4cf86e841cd7e844ad0da94c.tar.gz
Merge "Add sample TV input for 2way pairing use case." into lmp-dev
-rw-r--r--sample/AndroidManifest.xml26
-rw-r--r--sample/res/values/strings.xml2
-rw-r--r--sample/res/xml/sampleproxyservice.xml21
-rw-r--r--sample/src/com/example/android/sampleproxyservice/ExternalSettopBox.java75
-rw-r--r--sample/src/com/example/android/sampleproxyservice/FakeHdmiTvInputService.java61
-rw-r--r--sample/src/com/example/android/sampleproxyservice/SampleProxyService.java113
-rw-r--r--sample/src/com/example/android/sampleproxyservice/SampleProxySetupActivity.java86
-rw-r--r--sample/src/com/example/sampletvinput/BaseTvInputService.java2
-rw-r--r--sample/src/com/example/sampletvinput/LocalTvInputService.java4
9 files changed, 387 insertions, 3 deletions
diff --git a/sample/AndroidManifest.xml b/sample/AndroidManifest.xml
index add8d7fc..d1a95872 100644
--- a/sample/AndroidManifest.xml
+++ b/sample/AndroidManifest.xml
@@ -73,5 +73,31 @@
<meta-data android:name="android.media.tv.input"
android:resource="@xml/externalfiletvinputservice" />
</service>
+ <activity
+ android:name="com.example.android.sampleproxyservice.SampleProxySetupActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ </intent-filter>
+ </activity>
+ <service android:name="com.example.android.sampleproxyservice.FakeHdmiTvInputService"
+ android:permission="android.permission.BIND_TV_INPUT"
+ android:label="@string/fake_hdmi_input_label"
+ android:process=":remoteProxyTvInput">
+ <intent-filter>
+ <action android:name="android.media.tv.TvInputService" />
+ </intent-filter>
+ <meta-data android:name="android.media.tv.input"
+ android:resource="@xml/sampleproxyservice" />
+ </service>
+ <service android:name="com.example.android.sampleproxyservice.SampleProxyService"
+ android:permission="android.permission.BIND_TV_INPUT"
+ android:label="@string/proxy_input_label"
+ android:process=":remoteProxyTvInput">
+ <intent-filter>
+ <action android:name="android.media.tv.TvInputService" />
+ </intent-filter>
+ <meta-data android:name="android.media.tv.input"
+ android:resource="@xml/sampleproxyservice" />
+ </service>
</application>
</manifest>
diff --git a/sample/res/values/strings.xml b/sample/res/values/strings.xml
index 64add5d1..60bda09d 100644
--- a/sample/res/values/strings.xml
+++ b/sample/res/values/strings.xml
@@ -19,6 +19,8 @@
<string name="local_input_label">Sample Input 1: Overlay View Test</string>
<string name="hls_input_label">Sample Input 2: HLS Streaming</string>
<string name="external_input_label">Sample Input 3: External Files</string>
+ <string name="fake_hdmi_input_label">Sample Input 4: Fake HDMI</string>
+ <string name="proxy_input_label">Sample Input 5: Hardware Proxy </string>
<string name="overlay_view_test">Overlay View Test: press U to toggle the menu</string>
<string name="webview_toggle_button">Toggle WebView</string>
<string name="overlay_view_close_button">Close OverlayView</string>
diff --git a/sample/res/xml/sampleproxyservice.xml b/sample/res/xml/sampleproxyservice.xml
new file mode 100644
index 00000000..c728426b
--- /dev/null
+++ b/sample/res/xml/sampleproxyservice.xml
@@ -0,0 +1,21 @@
+<?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.
+ */
+-->
+
+<tv-input xmlns:android="http://schemas.android.com/apk/res/android"
+ android:setupActivity="com.example.android.sampleproxyservice.SampleProxySetupActivity" />
diff --git a/sample/src/com/example/android/sampleproxyservice/ExternalSettopBox.java b/sample/src/com/example/android/sampleproxyservice/ExternalSettopBox.java
new file mode 100644
index 00000000..f8591f4e
--- /dev/null
+++ b/sample/src/com/example/android/sampleproxyservice/ExternalSettopBox.java
@@ -0,0 +1,75 @@
+package com.example.android.sampleproxyservice;
+
+import android.media.MediaPlayer;
+import android.util.Log;
+import android.view.Surface;
+
+import java.io.IOException;
+
+/**
+ * Represents a external set-top box connected to a pass-through TV input.
+ */
+public class ExternalSettopBox {
+ private static final String TAG = ExternalSettopBox.class.getSimpleName();
+ private static final boolean DEBUG = true;
+
+ private static final String DEFAULT_URL =
+ "http://devimages.apple.com/iphone/samples/bipbop/gear1/prog_index.m3u8";
+ private static ExternalSettopBox sInstance;
+
+ private MediaPlayer mPlayer;
+ private String mUrl;
+ private Surface mSurface;
+
+ private ExternalSettopBox() {
+ mUrl = DEFAULT_URL;
+ }
+
+ public synchronized static ExternalSettopBox getInstance() {
+ if (sInstance == null) {
+ sInstance = new ExternalSettopBox();
+ }
+ return sInstance;
+ }
+
+ public synchronized void setSurface(Surface surface) {
+ if (DEBUG) Log.d(TAG, "setSurface(" + surface + ")");
+ mSurface = surface;
+ resetPlayback();
+ }
+
+ public synchronized void setVolume(float volume) {
+ if (DEBUG) Log.d(TAG, "setVolume(" + volume + ")");
+ mPlayer.setVolume(volume, volume);
+ }
+
+ public synchronized void tune(String url) {
+ if (DEBUG) Log.d(TAG, "tune(" + url + ")");
+ mUrl = url;
+ resetPlayback();
+ }
+
+ private void resetPlayback() {
+ if (DEBUG) Log.d(TAG, "resetPlayback(" + mUrl + ")");
+ if (mPlayer != null) {
+ if (DEBUG) Log.d(TAG, "Stopping");
+ mPlayer.stop();
+ mPlayer.release();
+ mPlayer = null;
+ }
+ try {
+ if (mSurface != null) {
+ if (DEBUG) Log.d(TAG, "Starting " + mUrl);
+ mPlayer = new MediaPlayer();
+ mPlayer.setSurface(mSurface);
+ mPlayer.setDataSource(mUrl);
+ mPlayer.prepare();
+ mPlayer.setLooping(true);
+ mPlayer.start();
+ }
+ } catch (IllegalArgumentException | SecurityException | IllegalStateException
+ | IOException e) {
+ Log.e(TAG, "Failed to play: " + mUrl);
+ }
+ }
+}
diff --git a/sample/src/com/example/android/sampleproxyservice/FakeHdmiTvInputService.java b/sample/src/com/example/android/sampleproxyservice/FakeHdmiTvInputService.java
new file mode 100644
index 00000000..04acbea3
--- /dev/null
+++ b/sample/src/com/example/android/sampleproxyservice/FakeHdmiTvInputService.java
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+package com.example.android.sampleproxyservice;
+
+import android.media.tv.TvInputService;
+import android.net.Uri;
+import android.view.Surface;
+
+/**
+ * Represents a simple HDMI input.
+ */
+public class FakeHdmiTvInputService extends TvInputService {
+ private ExternalSettopBox mExternalSettopBox = ExternalSettopBox.getInstance();
+
+ @Override
+ public Session onCreateSession(String inputId) {
+ return new FakeHdmiSession();
+ }
+
+ private class FakeHdmiSession extends Session {
+ @Override
+ public void onRelease() {
+ }
+
+ @Override
+ public void onSetCaptionEnabled(boolean enabled) {
+ // No-op.
+ }
+
+ @Override
+ public void onSetStreamVolume(float volume) {
+ mExternalSettopBox.setVolume(volume);
+ }
+
+ @Override
+ public boolean onSetSurface(Surface surface) {
+ mExternalSettopBox.setSurface(surface);
+ return true;
+ }
+
+ @Override
+ public boolean onTune(Uri channel) {
+ // No-op.
+ return false;
+ }
+ }
+}
diff --git a/sample/src/com/example/android/sampleproxyservice/SampleProxyService.java b/sample/src/com/example/android/sampleproxyservice/SampleProxyService.java
new file mode 100644
index 00000000..e0914ab0
--- /dev/null
+++ b/sample/src/com/example/android/sampleproxyservice/SampleProxyService.java
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+package com.example.android.sampleproxyservice;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.media.tv.TvContract;
+import android.media.tv.TvInputInfo;
+import android.media.tv.TvInputManager;
+import android.media.tv.TvInputService;
+import android.net.Uri;
+import android.util.Log;
+
+import java.util.List;
+
+/**
+ * Demonstrates how to implement a TV input service which represents a external device connected to
+ * a hardware TV input.
+ */
+public class SampleProxyService extends TvInputService {
+ private static final String TAG = SampleProxyService.class.getSimpleName();
+ private static final boolean DEBUG = true;
+
+ private String mHardwareTvInputId;
+ private TvInputManager mTvInputManager;
+
+ @Override
+ public void onCreate() {
+ if (DEBUG) Log.d(TAG, "onCreate()");
+ super.onCreate();
+ mTvInputManager = (TvInputManager) getSystemService(Context.TV_INPUT_SERVICE);
+ }
+
+ @Override
+ public Session onCreateSession(String inputId) {
+ return new SampleSession();
+ }
+
+ private class SampleSession extends HardwareSession {
+ private ExternalSettopBox mExternalSettopBox = ExternalSettopBox.getInstance();
+
+ @Override
+ public boolean onTune(Uri channel) {
+ if (DEBUG) Log.d(TAG, "onTune(" + channel + ")");
+ String[] projection = { TvContract.Channels.COLUMN_INTERNAL_PROVIDER_DATA };
+
+ Cursor cursor = null;
+ try {
+ cursor = getContentResolver().query(channel, projection, null, null, null);
+ if (cursor == null || cursor.getCount() == 0) {
+ if (DEBUG) Log.d(TAG, "Can't find channel in TvProvider.");
+ return false;
+ }
+ cursor.moveToNext();
+ String url = cursor.getString(0);
+ if (DEBUG) Log.d(TAG, "Tuning to: " + url);
+ mExternalSettopBox.tune(url);
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public void onRelease() {
+ // Do nothing.
+ }
+
+ @Override
+ public void onSetCaptionEnabled(boolean enabled) {
+ // Do nothing.
+ }
+
+ @Override
+ public void onSetStreamVolume(float volume) {
+ // Do Nothing.
+ }
+
+ @Override
+ public String getHardwareInputId() {
+ if (mHardwareTvInputId != null) {
+ return mHardwareTvInputId;
+ }
+ List<TvInputInfo> inputs = mTvInputManager.getTvInputList();
+ // TODO: This should be set in the setup phase.
+ String hdmiServiceName = FakeHdmiTvInputService.class.getSimpleName();
+ for (TvInputInfo info : inputs) {
+ if (info.getComponent().toString().contains(hdmiServiceName)) {
+ mHardwareTvInputId = info.getId();
+ return mHardwareTvInputId;
+ }
+ }
+ if (DEBUG) Log.e(TAG, "Cannot find input for: " + hdmiServiceName);
+ return null;
+ }
+ }
+}
diff --git a/sample/src/com/example/android/sampleproxyservice/SampleProxySetupActivity.java b/sample/src/com/example/android/sampleproxyservice/SampleProxySetupActivity.java
new file mode 100644
index 00000000..4d1e7ca1
--- /dev/null
+++ b/sample/src/com/example/android/sampleproxyservice/SampleProxySetupActivity.java
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ */
+
+package com.example.android.sampleproxyservice;
+
+import android.app.Activity;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.media.tv.TvContract;
+import android.media.tv.TvContract.Channels;
+import android.media.tv.TvInputInfo;
+import android.net.Uri;
+import android.os.Bundle;
+
+public class SampleProxySetupActivity extends Activity {
+ private static final String TAG = SampleProxySetupActivity.class.getSimpleName();
+ private static final boolean DEBUG = true;
+
+ private static final String CHANNEL_NUMBER_1 = "1";
+ private static final String CHANNEL_NAME_1 = "BIPBOP";
+ private static final String CHANNEL_URL_1 =
+ "http://devimages.apple.com/iphone/samples/bipbop/gear1/prog_index.m3u8";
+
+ private static final String CHANNEL_NUMBER_2 = "2";
+ private static final String CHANNEL_NAME_2 = "BUNNY";
+ private static final String CHANNEL_URL_2 =
+ "http://playertest.longtailvideo.com/adaptive/bbbfull/bbbfull.m3u8";
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ String inputId = getIntent().getStringExtra(TvInputInfo.EXTRA_INPUT_ID);
+ createSampleChannels(inputId);
+ setResult(Activity.RESULT_OK);
+ finish();
+ }
+
+ private void createSampleChannels(String inputId) {
+ Uri uri = TvContract.buildChannelsUriForInput(inputId);
+ String[] projection = { TvContract.Channels._ID };
+
+ Cursor cursor = null;
+ try {
+ while (true) {
+ cursor = getContentResolver().query(uri, projection, null, null, null);
+ if (cursor != null && cursor.getCount() > 0) {
+ return;
+ }
+ if (cursor != null) {
+ cursor.close();
+ cursor = null;
+ }
+ ContentValues values = new ContentValues();
+ values.put(Channels.COLUMN_INPUT_ID, inputId);
+
+ values.put(Channels.COLUMN_DISPLAY_NUMBER, CHANNEL_NUMBER_1);
+ values.put(Channels.COLUMN_DISPLAY_NAME, CHANNEL_NAME_1);
+ values.put(Channels.COLUMN_INTERNAL_PROVIDER_DATA, CHANNEL_URL_1);
+ getContentResolver().insert(TvContract.Channels.CONTENT_URI, values);
+
+ values.put(Channels.COLUMN_DISPLAY_NUMBER, CHANNEL_NUMBER_2);
+ values.put(Channels.COLUMN_DISPLAY_NAME, CHANNEL_NAME_2);
+ values.put(Channels.COLUMN_INTERNAL_PROVIDER_DATA, CHANNEL_URL_2);
+ getContentResolver().insert(TvContract.Channels.CONTENT_URI, values);
+ }
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+ }
+}
diff --git a/sample/src/com/example/sampletvinput/BaseTvInputService.java b/sample/src/com/example/sampletvinput/BaseTvInputService.java
index 14711749..39d79e67 100644
--- a/sample/src/com/example/sampletvinput/BaseTvInputService.java
+++ b/sample/src/com/example/sampletvinput/BaseTvInputService.java
@@ -76,7 +76,7 @@ abstract public class BaseTvInputService extends TvInputService {
}
@Override
- public TvInputService.Session onCreateSession(String inputId) {
+ public Session onCreateSession(String inputId) {
if (DEBUG) Log.d(TAG, "onCreateSession(inputId=" + inputId + ")");
return new BaseTvInputSessionImpl();
}
diff --git a/sample/src/com/example/sampletvinput/LocalTvInputService.java b/sample/src/com/example/sampletvinput/LocalTvInputService.java
index 7e2fbefb..0a69c77f 100644
--- a/sample/src/com/example/sampletvinput/LocalTvInputService.java
+++ b/sample/src/com/example/sampletvinput/LocalTvInputService.java
@@ -16,8 +16,8 @@
package com.example.sampletvinput;
-import android.media.tv.TvInputService;
import android.media.tv.TvContentRating;
+import android.media.tv.TvInputService;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
@@ -52,7 +52,7 @@ public class LocalTvInputService extends BaseTvInputService {
private static final String WEBVIEW_SITE = "http://www.android.com";
@Override
- public TvInputService.Session onCreateSession(String inputId) {
+ public Session onCreateSession(String inputId) {
if (DEBUG) Log.d(TAG, "onCreateSession(inputId=" + inputId + ")");
TvInputService.Session impl = new LocalTvInputSessionImpl();
impl.setOverlayViewEnabled(true);