项目需要,有个背景透明的应用后台需要播放TV,之前是使用LiveTv在后台播放,由于严重依赖于LiveTV,使用起来很不方便,如果能直接在这个应用中播放TV,那就好了。于是,尝试在后台添加TvView,现记录使用过程。应用起来比较简单。
一、原菜单不变,仅仅添加TvView控件。
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:ctvui="http://schemas.android.com/apk/res-auto"
android:id="@+id/main_bg"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black_six" >
<android.media.tv.TvView
android:id="@+id/tv_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
....
FrameLayout>
二、代码部分,仅TvView相关部分
public class MainActivity extends Activity {
import android.database.IContentObserver;
import android.media.tv.TvContract;
import android.media.tv.TvContract.Channels;
import android.media.tv.TvInputInfo;
import android.media.tv.TvInputManager;
import android.media.tv.TvTrackInfo;
import android.media.tv.TvView;
import com.cultraview.launcher.view.BlockScreenView;
//import com.droidlogic.app.SystemControlManager;
import com.droidlogic.app.tv.ChannelInfo;
import com.droidlogic.app.tv.DroidLogicTvUtils;
import com.droidlogic.app.tv.TvControlManager;
import com.droidlogic.app.tv.TvDataBaseManager;
...
private TvView mTvView;
private String mTvInputId;
private Uri mChannelUri;
private boolean isRadioChannel = false;
private TvInputManager mTvInputManager;
private TvInputChangeCallback mTvInputChangeCallback;
private TvDataBaseManager mTvDataBaseManager;
private ChannelObserver mChannelObserver;
private static final int TV_MSG_PLAY_TV = 0;
private static final int TV_MSG_RUN_STOP = 1;
private static final int TV_MSG_RUN_START = 2;
//private SystemControlManager mSystemControlManager;
private boolean isFirst = false;
mTvView = (TvView)findViewById(R.id.tv_view);
@Override
protected void onStart() {
// TODO 自动生成的方法存根
super.onStart();
mTvInputManager = (TvInputManager) getSystemService(Context.TV_INPUT_SERVICE);
mTvInputChangeCallback = new TvInputChangeCallback();
mTvInputManager.registerCallback(mTvInputChangeCallback, new Handler());
mChannelObserver = new ChannelObserver();
getContentResolver().registerContentObserver(Channels.CONTENT_URI, true, mChannelObserver);
mTvView.setVisibility(View.VISIBLE);
//mTvHandler.sendEmptyMessage(TV_MSG_PLAY_TV);
mTvHandler.sendEmptyMessageDelayed(TV_MSG_PLAY_TV, 1000);
}
@Override
protected void onStop() {
// TODO 自动生成的方法存根
super.onStop();
releaseTvView();
}
private void releaseTvView() {
mTvView.setVisibility(View.GONE);
mTvView.reset();
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.i(TAG, "--onDestroy --Tools.isThemeChange:" + Tools.isThemeChange);
mTvHandler.sendEmptyMessageDelayed(TV_MSG_RUN_STOP, 1);
...
}
private void tuneTvView() {
mTvInputId = null;
mChannelUri = null;
int device_id, index_atv, index_adtv;
device_id = Settings.System.getInt(getContentResolver(), DroidLogicTvUtils.TV_CURRENT_DEVICE_ID, 0);
index_adtv = Settings.System.getInt(getContentResolver(), DroidLogicTvUtils.TV_DTV_CHANNEL_INDEX, -1);
isRadioChannel = Settings.System.getInt(getContentResolver(), DroidLogicTvUtils.TV_CURRENT_CHANNEL_IS_RADIO, 0) == 1 ? true : false;
Log.d(TAG, "TV get device_id=" + device_id +" adtv=" + index_adtv + " is_radio="+isRadioChannel);
List
for (TvInputInfo info : input_list) {
if (parseDeviceId(info.getId()) == device_id) {
mTvInputId = info.getId();
}
}
mTvDataBaseManager = new TvDataBaseManager(this);
if (TextUtils.isEmpty(mTvInputId)) {
Log.d(TAG, "device" + device_id + " is not exist");
return;
} else {
if (device_id == DroidLogicTvUtils.DEVICE_ID_ADTV) {
ArrayList
Log.d(TAG, "channelList.size:" + channelList.size());
if(index_adtv == -1){
mChannelUri = null;
}else{
setChannelUri(channelList, index_adtv);
}
}else {
mChannelUri = TvContract.buildChannelUriForPassthroughInput(mTvInputId);
}
}
Log.d(TAG, "TV play tune inputId=" + mTvInputId + " uri=" + mChannelUri);
if(mChannelUri != null){
mTVNoDataBlockScreenView.setVisibility(View.GONE);
mTVNoDataBlockScreenView.HideNoDataBaseTint();
mTvView.tune(mTvInputId, mChannelUri);
}else{
Log.d(TAG, "show no database");
TvControlManager mTvControlManager = TvControlManager.getInstance();
int blueModeIndex = mTvControlManager.GetBlueScreenEnable();
if(blueModeIndex==1)
mTVNoDataBlockScreenView.setBackgroundResource(R.color.blue_screen);
else
mTVNoDataBlockScreenView.setBackgroundResource(R.color.black);
mTVNoDataBlockScreenView.setVisibility(View.VISIBLE);
mTVNoDataBlockScreenView.setNoDataBaseHint();
}
}
private final class TvInputChangeCallback extends TvInputManager.TvInputCallback {
@Override
public void onInputAdded(String inputId) {
Log.d(TAG, "==== onInputAdded, inputId=" + inputId + " curent inputid=" + mTvInputId);
int device_id = Settings.System.getInt(getContentResolver(), DroidLogicTvUtils.TV_CURRENT_DEVICE_ID, 0);
if (device_id == parseDeviceId(inputId)) {
switch (device_id) {
case DroidLogicTvUtils.DEVICE_ID_AV1:
case DroidLogicTvUtils.DEVICE_ID_AV2:
case DroidLogicTvUtils.DEVICE_ID_HDMI1:
case DroidLogicTvUtils.DEVICE_ID_HDMI2:
case DroidLogicTvUtils.DEVICE_ID_HDMI3:
mTvView.reset();
mTvInputId = inputId;
mChannelUri = TvContract.buildChannelUriForPassthroughInput(mTvInputId);
mTvView.tune(mTvInputId, mChannelUri);
break;
}
}
}
@Override
public void onInputRemoved(String inputId) {
Log.d(TAG, "==== onInputRemoved, inputId=" + inputId + " curent inputid=" + mTvInputId);
if (TextUtils.equals(inputId, mTvInputId)) {
Log.d(TAG, "==== current input device removed");
mTvInputId = null;
}
}
}
private int parseDeviceId(String inputId) {
String[] temp = inputId.split("/");
if (temp.length == 3) {
/* ignore for HDMI CEC device */
if (temp[2].contains("HDMI"))
return -1;
return Integer.parseInt(temp[2].substring(2));
} else {
return -1;
}
}
private void setChannelUri (ArrayList
Log.d(TAG, "===channelList.size() = "+channelList.size()+" ,index = "+index);
if (channelList.size() > 0) {
if (index > 0) {
for (ChannelInfo channelInfo : channelList) {
if (index == channelInfo.getNumber()) {
mChannelUri = channelInfo.getUri();
//setTvPrompt(TV_PROMPT_GOT_SIGNAL);
return;
}
}
}
ChannelInfo channel = channelList.get(0);
mChannelUri = channel.getUri();
Settings.System.putInt(getContentResolver(), DroidLogicTvUtils.TV_ATV_CHANNEL_INDEX, 1);
Settings.System.putInt(getContentResolver(), DroidLogicTvUtils.TV_CURRENT_CHANNEL_IS_RADIO,
ChannelInfo.isRadioChannel(channel) ? 1 : 0);
//setTvPrompt(TV_PROMPT_GOT_SIGNAL);
} else {
mChannelUri = TvContract.buildChannelUri(-1);
}
}
private final class ChannelObserver extends ContentObserver {
public ChannelObserver() {
super(new Handler());
}
@Override
public void onChange(boolean selfChange, Uri uri) {
Log.d(TAG, "detect channel changed =" + uri);
if (DroidLogicTvUtils.matchsWhich(mChannelUri) == DroidLogicTvUtils.NO_MATCH) {
ChannelInfo changedChannel = mTvDataBaseManager.getChannelInfo(uri);
if (TextUtils.equals(changedChannel.getInputId(), mTvInputId)) {
Log.d(TAG, "current channel is null, so tune to a new channel");
mChannelUri = uri;
mTvView.tune(mTvInputId, mChannelUri);
}
}
}
@Override
public IContentObserver releaseContentObserver() {
// TODO Auto-generated method stub
return super.releaseContentObserver();
}
}
private Handler mTvHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case TV_MSG_PLAY_TV:
if (true) {
Log.d(TAG, "======== bootvideo is stopped, start tv play");
tuneTvView();
if(isFirst == true)
{
isFirst = false;
mTvHandler.sendEmptyMessageDelayed(TV_MSG_RUN_STOP, 500);
}
} else {
Log.d(TAG, "======== bootvideo is not stopped, wait it");
mTvHandler.sendEmptyMessageDelayed(TV_MSG_PLAY_TV, 200);
}
break;
case TV_MSG_RUN_STOP:
{
if (true) {
releaseTvView();
if (mTvInputChangeCallback != null) {
mTvInputManager.unregisterCallback(mTvInputChangeCallback);
mTvInputChangeCallback = null;
}
if (mChannelObserver != null) {
getContentResolver().unregisterContentObserver(mChannelObserver);
mChannelObserver = null;
}
}
mTvHandler.sendEmptyMessageDelayed(TV_MSG_RUN_START, 500);
}
break;
case TV_MSG_RUN_START:
{
mTvView.setVisibility(View.VISIBLE);
Log.d(TAG, "------onStart");
if (true) {
mTvInputManager = (TvInputManager) getSystemService(Context.TV_INPUT_SERVICE);
mTvInputChangeCallback = new TvInputChangeCallback();
mTvInputManager.registerCallback(mTvInputChangeCallback, new Handler());
mChannelObserver = new ChannelObserver();
getContentResolver().registerContentObserver(Channels.CONTENT_URI, true, mChannelObserver);
mTvView.setVisibility(View.VISIBLE);
mTvHandler.sendEmptyMessageDelayed(TV_MSG_PLAY_TV, 100);
}
}
break;
default:
break;
}
}
};
...
}
注意AndroidManifest.xml中需要设置以下几点:否则会出现无法读写TV 节目及设置当前通道的问题。
android:sharedUserId="android.uid.system"
三、后记
从使用上看来,关键部分是TvView,及TvView.tune(),其他类似TvInputChangeCallback此处没意义。