diff options
author | Christofer Ã…kersten <akersten@google.com> | 2014-07-23 17:58:11 +0900 |
---|---|---|
committer | Christofer Ã…kersten <akersten@google.com> | 2014-07-28 20:18:09 +0900 |
commit | d82ca62a0fefaed41493540df7d622cfcfb2cb6c (patch) | |
tree | 42f5ab29f99f0d6d105b82ce6c1ec2365c1f7cc4 | |
parent | 903b8cf0ae7dc7f8b037311ab28615b0a212a31d (diff) | |
download | TV-d82ca62a0fefaed41493540df7d622cfcfb2cb6c.tar.gz |
Block screen when onVideoUnavailable is received.
Bug: 16272325
Change-Id: Id3c99312099c71f1899d22579ff2dfc1b684e506
-rw-r--r-- | res/layout/activity_tv.xml | 6 | ||||
-rw-r--r-- | res/layout/tunable_tv_view.xml | 53 | ||||
-rw-r--r-- | res/values/strings.xml | 2 | ||||
-rw-r--r-- | src/com/android/tv/TvActivity.java | 13 | ||||
-rw-r--r-- | src/com/android/tv/ui/TunableTvView.java | 128 |
5 files changed, 166 insertions, 36 deletions
diff --git a/res/layout/activity_tv.xml b/res/layout/activity_tv.xml index eb9144a0..e2fd6280 100644 --- a/res/layout/activity_tv.xml +++ b/res/layout/activity_tv.xml @@ -21,13 +21,13 @@ android:foreground="@android:color/transparent" android:keepScreenOn="true" > - <com.android.tv.ui.TunableTvView android:id="@+id/tv_view" + <com.android.tv.ui.TunableTvView android:id="@+id/main_tv_view" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center" /> - <com.android.tv.ui.TunableTvView android:id="@+id/pip_view" - android:visibility="invisible" + <com.android.tv.ui.TunableTvView android:id="@+id/pip_tv_view" + android:visibility="gone" android:layout_marginLeft="56dp" android:layout_marginRight="56dp" android:layout_marginTop="27dp" diff --git a/res/layout/tunable_tv_view.xml b/res/layout/tunable_tv_view.xml new file mode 100644 index 00000000..8ffa99a2 --- /dev/null +++ b/res/layout/tunable_tv_view.xml @@ -0,0 +1,53 @@ +<?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. +--> + +<merge xmlns:android="http://schemas.android.com/apk/res/android" > + + <android.media.tv.TvView + android:id="@+id/tv_view" + android:layout_width="match_parent" + android:layout_height="match_parent" /> + + <View + android:id="@+id/block_reason_unknown" + android:visibility="gone" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@android:color/black" /> + + <View + android:id="@+id/block_reason_tune" + android:visibility="gone" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@android:color/black" /> + + <View + android:id="@+id/block_reason_weak_signal" + android:visibility="gone" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@android:color/black" /> + + <ProgressBar + android:id="@+id/block_reason_buffering" + android:visibility="gone" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:background="@android:color/transparent" + android:layout_gravity="center" /> + +</merge>
\ No newline at end of file diff --git a/res/values/strings.xml b/res/values/strings.xml index a2045b44..a8d15724 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -141,7 +141,7 @@ <!-- The text used when there is no program title. --> <string name="channel_banner_no_title">No title</string> - <!-- Debug Options --> + <!-- Debug Options --> <string name="menu_debug_options">Debug Options</string> <string name="item_tv_input">TV Input</string> <string name="item_watch_history">Watch History</string> diff --git a/src/com/android/tv/TvActivity.java b/src/com/android/tv/TvActivity.java index 04d13da8..a27942b4 100644 --- a/src/com/android/tv/TvActivity.java +++ b/src/com/android/tv/TvActivity.java @@ -32,6 +32,7 @@ import android.media.AudioManager; import android.media.tv.TvInputInfo; import android.media.tv.TvInputManager; import android.media.tv.TvTrackInfo; +import android.media.tv.TvView.OnUnhandledInputEventListener; import android.net.Uri; import android.os.Bundle; import android.os.Handler; @@ -189,8 +190,8 @@ public class TvActivity extends Activity implements AudioManager.OnAudioFocusCha super.onCreate(savedInstanceState); setContentView(R.layout.activity_tv); - mTvView = (TunableTvView) findViewById(R.id.tv_view); - mTvView.setOnUnhandledInputEventListener(new TunableTvView.OnUnhandledInputEventListener() { + mTvView = (TunableTvView) findViewById(R.id.main_tv_view); + mTvView.setOnUnhandledInputEventListener(new OnUnhandledInputEventListener() { @Override public boolean onUnhandledInputEvent(InputEvent event) { if (event instanceof KeyEvent) { @@ -214,7 +215,7 @@ public class TvActivity extends Activity implements AudioManager.OnAudioFocusCha return false; } }); - mPipView = (TunableTvView) findViewById(R.id.pip_view); + mPipView = (TunableTvView) findViewById(R.id.pip_tv_view); mPipView.setPip(true); mControlGuide = (LinearLayout) findViewById(R.id.control_guide); @@ -240,7 +241,7 @@ public class TvActivity extends Activity implements AudioManager.OnAudioFocusCha @Override public void run() { if (mPipEnabled) { - mPipView.setVisibility(View.INVISIBLE); + mPipView.setVisibility(View.GONE); } } }, @@ -385,7 +386,7 @@ public class TvActivity extends Activity implements AudioManager.OnAudioFocusCha protected void onPause() { hideOverlays(true, true, true); if (mPipEnabled) { - mPipView.setVisibility(View.INVISIBLE); + mPipView.setVisibility(View.GONE); } mActivityResumed = false; super.onPause(); @@ -864,7 +865,7 @@ public class TvActivity extends Activity implements AudioManager.OnAudioFocusCha private void stopPip() { if (DEBUG) Log.d(TAG, "stopPip"); if (mPipView.isPlaying()) { - mPipView.setVisibility(View.INVISIBLE); + mPipView.setVisibility(View.GONE); mPipView.stop(); } } diff --git a/src/com/android/tv/ui/TunableTvView.java b/src/com/android/tv/ui/TunableTvView.java index 6ff38626..09c23435 100644 --- a/src/com/android/tv/ui/TunableTvView.java +++ b/src/com/android/tv/ui/TunableTvView.java @@ -6,6 +6,8 @@ import android.media.tv.TvInputInfo; import android.media.tv.TvInputManager; import android.media.tv.TvTrackInfo; import android.media.tv.TvView; +import android.media.tv.TvView.OnUnhandledInputEventListener; +import android.media.tv.TvView.TvInputListener; import android.net.Uri; import android.util.AttributeSet; import android.util.Log; @@ -13,6 +15,8 @@ import android.view.KeyEvent; import android.view.MotionEvent; import android.view.SurfaceHolder; import android.view.SurfaceView; +import android.view.ViewGroup; +import android.widget.FrameLayout; import com.android.tv.R; import com.android.tv.data.Channel; @@ -22,7 +26,8 @@ import com.android.tv.util.Utils; import java.util.List; -public class TunableTvView extends TvView implements StreamInfo { +public class TunableTvView extends FrameLayout implements StreamInfo { + // STOPSHIP: Turn debugging off private static final boolean DEBUG = true; private static final String TAG = "TunableTvView"; @@ -30,6 +35,8 @@ public class TunableTvView extends TvView implements StreamInfo { public static final String PERMISSION_RECEIVE_INPUT_EVENT = "android.permission.RECEIVE_INPUT_EVENT"; + private final TvView mTvView; + private final SurfaceView mSurfaceView; private long mChannelId = Channel.INVALID_ID; private TvInputManagerHelper mInputManagerHelper; private boolean mStarted; @@ -42,8 +49,9 @@ public class TunableTvView extends TvView implements StreamInfo { private boolean mHasClosedCaption = false; private boolean mIsVideoAvailable; private int mVideoUnavailableReason; - private SurfaceView mSurface; private boolean mCanReceiveInputEvent; + private boolean mIsMuted; + private float mVolume; private final SurfaceHolder.Callback mSurfaceHolderCallback = new SurfaceHolder.Callback() { @Override @@ -129,6 +137,7 @@ public class TunableTvView extends TvView implements StreamInfo { @Override public void onVideoAvailable(String inputId) { mIsVideoAvailable = true; + unblock(); if (mOnTuneListener != null) { mOnTuneListener.onStreamInfoChanged(TunableTvView.this); } @@ -138,6 +147,7 @@ public class TunableTvView extends TvView implements StreamInfo { public void onVideoUnavailable(String inputId, int reason) { mIsVideoAvailable = false; mVideoUnavailableReason = reason; + block(reason); if (mOnTuneListener != null) { mOnTuneListener.onStreamInfoChanged(TunableTvView.this); } @@ -145,7 +155,7 @@ public class TunableTvView extends TvView implements StreamInfo { }; public TunableTvView(Context context) { - this(context, null, 0); + this(context, null); } public TunableTvView(Context context, AttributeSet attrs) { @@ -153,15 +163,15 @@ public class TunableTvView extends TvView implements StreamInfo { } public TunableTvView(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - for (int i = 0; i < getChildCount(); ++i) { - if (getChildAt(i) instanceof SurfaceView) { - mSurface = (SurfaceView) getChildAt(i); - mSurface.getHolder().addCallback(mSurfaceHolderCallback); - return; - } - } - throw new RuntimeException("TvView does not have SurfaceView."); + this(context, attrs, defStyleAttr, 0); + } + + public TunableTvView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + inflate(getContext(), R.layout.tunable_tv_view, this); + + mTvView = (TvView) findViewById(R.id.tv_view); + mSurfaceView = findSurfaceView(mTvView); } public void start(TvInputManagerHelper tvInputManagerHelper) { @@ -177,7 +187,7 @@ public class TunableTvView extends TvView implements StreamInfo { return; } mStarted = false; - reset(); + mTvView.reset(); mChannelId = Channel.INVALID_ID; mInputInfo = null; mCanReceiveInputEvent = false; @@ -208,7 +218,7 @@ public class TunableTvView extends TvView implements StreamInfo { mOnTuneListener = listener; mChannelId = channelId; if (!inputInfo.equals(mInputInfo)) { - reset(); + mTvView.reset(); // TODO: It is a hack to wait to release a surface at TIS. If there is a way to // know when the surface is released at TIS, we don't need this hack. try { @@ -217,12 +227,12 @@ public class TunableTvView extends TvView implements StreamInfo { e.printStackTrace(); } mInputInfo = inputInfo; - mCanReceiveInputEvent = mContext.getPackageManager().checkPermission( + mCanReceiveInputEvent = getContext().getPackageManager().checkPermission( PERMISSION_RECEIVE_INPUT_EVENT, mInputInfo.getComponent().getPackageName()) == PackageManager.PERMISSION_GRANTED; } - setTvInputListener(mListener); - tune(mInputInfo.getId(), Utils.getChannelUri(mChannelId)); + mTvView.setTvInputListener(mListener); + mTvView.tune(mInputInfo.getId(), Utils.getChannelUri(mChannelId)); if (mOnTuneListener != null) { // TODO: Add a callback for tune complete and call onTuned when it was successful. mOnTuneListener.onTuned(true, mChannelId); @@ -240,37 +250,38 @@ public class TunableTvView extends TvView implements StreamInfo { } public void setPip(boolean isPip) { - mSurface.setZOrderMediaOverlay(isPip); + mSurfaceView.setZOrderMediaOverlay(isPip); } - @Override public void setStreamVolume(float volume) { if (!mStarted) { throw new IllegalStateException("TvView isn't started"); } - if (DEBUG) - Log.d(TAG, "setStreamVolume " + volume); - super.setStreamVolume(volume); + if (DEBUG) Log.d(TAG, "setStreamVolume " + volume); + mVolume = volume; + if (!mIsMuted) { + mTvView.setStreamVolume(volume); + } } @Override public boolean dispatchKeyEvent(KeyEvent event) { - return mCanReceiveInputEvent && super.dispatchKeyEvent(event); + return mCanReceiveInputEvent && mTvView.dispatchKeyEvent(event); } @Override public boolean dispatchTouchEvent(MotionEvent event) { - return mCanReceiveInputEvent && super.dispatchTouchEvent(event); + return mCanReceiveInputEvent && mTvView.dispatchTouchEvent(event); } @Override public boolean dispatchTrackballEvent(MotionEvent event) { - return mCanReceiveInputEvent && super.dispatchTrackballEvent(event); + return mCanReceiveInputEvent && mTvView.dispatchTrackballEvent(event); } @Override public boolean dispatchGenericMotionEvent(MotionEvent event) { - return mCanReceiveInputEvent && super.dispatchGenericMotionEvent(event); + return mCanReceiveInputEvent && mTvView.dispatchGenericMotionEvent(event); } public interface OnTuneListener { @@ -314,4 +325,69 @@ public class TunableTvView extends TvView implements StreamInfo { public int getVideoUnavailableReason() { return mVideoUnavailableReason; } + + public void setOnUnhandledInputEventListener(OnUnhandledInputEventListener listener) { + mTvView.setOnUnhandledInputEventListener(listener); + } + + public List<TvTrackInfo> getTracks() { + return mTvView.getTracks(); + } + + public void selectTrack(TvTrackInfo track) { + mTvView.selectTrack(track); + } + + private void block(int reason) { + hideBlock(); + switch (reason) { + case TvInputManager.VIDEO_UNAVAILABLE_REASON_UNKNOWN: + default: + findViewById(R.id.block_reason_unknown).setVisibility(VISIBLE); + break; + case TvInputManager.VIDEO_UNAVAILABLE_REASON_TUNE: + findViewById(R.id.block_reason_tune).setVisibility(VISIBLE); + break; + case TvInputManager.VIDEO_UNAVAILABLE_REASON_WEAK_SIGNAL: + findViewById(R.id.block_reason_weak_signal).setVisibility(VISIBLE); + break; + case TvInputManager.VIDEO_UNAVAILABLE_REASON_BUFFERING: + findViewById(R.id.block_reason_buffering).setVisibility(VISIBLE); + break; + } + mute(); + } + + private void unblock() { + hideBlock(); + unmute(); + } + + private void mute() { + mIsMuted = true; + mTvView.setStreamVolume(0); + } + + private void unmute() { + mIsMuted = false; + mTvView.setStreamVolume(mVolume); + } + + private SurfaceView findSurfaceView(ViewGroup view) { + for (int i = 0; i < view.getChildCount(); ++i) { + if (view.getChildAt(i) instanceof SurfaceView) { + SurfaceView surfaceView = (SurfaceView) mTvView.getChildAt(i); + surfaceView.getHolder().addCallback(mSurfaceHolderCallback); + return surfaceView; + } + } + throw new RuntimeException("TvView does not have SurfaceView."); + } + + private void hideBlock() { + findViewById(R.id.block_reason_unknown).setVisibility(GONE); + findViewById(R.id.block_reason_tune).setVisibility(GONE); + findViewById(R.id.block_reason_weak_signal).setVisibility(GONE); + findViewById(R.id.block_reason_buffering).setVisibility(GONE); + } } |