blob: 9f21e16a705dd18539a1c4311a8ea5e1fd6176b9 [file] [log] [blame]
/*
* Copyright (C) 2015 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.android.tv.tuner.tvinput;
import android.content.Context;
import android.media.tv.TvInputService.Session;
import android.os.Handler;
import android.os.Message;
import android.text.Html;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
import com.android.tv.common.util.SystemPropertiesProxy;
import com.android.tv.tuner.R;
import com.android.tv.tuner.cc.CaptionLayout;
import com.android.tv.tuner.cc.CaptionTrackRenderer;
import com.android.tv.tuner.data.Cea708Data.CaptionEvent;
import com.android.tv.tuner.data.nano.Track.AtscCaptionTrack;
import com.android.tv.tuner.util.GlobalSettingsUtils;
import com.android.tv.tuner.util.StatusTextUtils;
/** Executes {@link Session} overlay changes on the main thread. */
/* package */ final class TunerSessionOverlay implements Handler.Callback {
/** Displays the given {@link String} message object in the message view. */
public static final int MSG_UI_SHOW_MESSAGE = 1;
/** Hides the message view. Does not expect a message object. */
public static final int MSG_UI_HIDE_MESSAGE = 2;
/**
* Displays a message in the audio status view to signal audio is not supported. Does not expect
* a message object.
*/
public static final int MSG_UI_SHOW_AUDIO_UNPLAYABLE = 3;
/** Hides the audio status view. Does not expect a message object. */
public static final int MSG_UI_HIDE_AUDIO_UNPLAYABLE = 4;
/** Feeds the given {@link CaptionEvent} message object to the {@link CaptionTrackRenderer}. */
public static final int MSG_UI_PROCESS_CAPTION_TRACK = 5;
/**
* Invokes {@link CaptionTrackRenderer#start(AtscCaptionTrack)} passing the given {@link
* AtscCaptionTrack} message object as argument.
*/
public static final int MSG_UI_START_CAPTION_TRACK = 6;
/** Invokes {@link CaptionTrackRenderer#stop()}. Does not expect a message object. */
public static final int MSG_UI_STOP_CAPTION_TRACK = 7;
/** Invokes {@link CaptionTrackRenderer#reset()}. Does not expect a message object. */
public static final int MSG_UI_RESET_CAPTION_TRACK = 8;
/** Invokes {@link CaptionTrackRenderer#clear()}. Does not expect a message object. */
public static final int MSG_UI_CLEAR_CAPTION_RENDERER = 9;
/** Displays the given {@link CharSequence} message object in the status view. */
public static final int MSG_UI_SET_STATUS_TEXT = 10;
/** Displays a toast signalling that a re-scan is required. Does not expect a message object. */
public static final int MSG_UI_TOAST_RESCAN_NEEDED = 11;
private static final String USBTUNER_SHOW_DEBUG = "persist.tv.tuner.show_debug";
private final Context mContext;
private final Handler mHandler;
private final View mOverlayView;
private final TextView mMessageView;
private final TextView mStatusView;
private final TextView mAudioStatusView;
private final ViewGroup mMessageLayout;
private final CaptionTrackRenderer mCaptionTrackRenderer;
/**
* Creates and inflates a {@link Session} overlay from the given context.
*
* @param context The {@link Context} of the {@link Session}.
*/
public TunerSessionOverlay(Context context) {
mContext = context;
mHandler = new Handler(this);
LayoutInflater inflater =
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
boolean showDebug = SystemPropertiesProxy.getBoolean(USBTUNER_SHOW_DEBUG, false);
mOverlayView = inflater.inflate(R.layout.ut_overlay_view, null);
mMessageLayout = mOverlayView.findViewById(R.id.message_layout);
mMessageLayout.setVisibility(View.INVISIBLE);
mMessageView = mOverlayView.findViewById(R.id.message);
mStatusView = mOverlayView.findViewById(R.id.tuner_status);
mStatusView.setVisibility(showDebug ? View.VISIBLE : View.INVISIBLE);
mAudioStatusView = mOverlayView.findViewById(R.id.audio_status);
mAudioStatusView.setVisibility(View.INVISIBLE);
CaptionLayout captionLayout = mOverlayView.findViewById(R.id.caption);
mCaptionTrackRenderer = new CaptionTrackRenderer(captionLayout);
}
/** Clears any pending messages in the message queue. */
public void release() {
mHandler.removeCallbacksAndMessages(null);
}
/** Returns a {@link View} representation of the overlay. */
public View getOverlayView() {
return mOverlayView;
}
/**
* Posts a message to be handled on the main thread. Only messages that do not expect a message
* object may be posted through this method.
*
* @param message One of the {@code MSG_UI_*} constants.
*/
public void sendUiMessage(int message) {
mHandler.sendEmptyMessage(message);
}
/**
* Posts a message to be handled on the main thread.
*
* @param message One of the {@code MSG_UI_*} constants.
* @param object The object of the message. The required message object type depends on the
* message being posted.
*/
public void sendUiMessage(int message, Object object) {
mHandler.obtainMessage(message, object).sendToTarget();
}
@Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
case MSG_UI_SHOW_MESSAGE:
mMessageView.setText((String) msg.obj);
mMessageLayout.setVisibility(View.VISIBLE);
return true;
case MSG_UI_HIDE_MESSAGE:
mMessageLayout.setVisibility(View.INVISIBLE);
return true;
case MSG_UI_SHOW_AUDIO_UNPLAYABLE:
// Showing message of enabling surround sound only when global surround sound
// setting is "never".
final int value = GlobalSettingsUtils.getEncodedSurroundOutputSettings(mContext);
if (value == GlobalSettingsUtils.ENCODED_SURROUND_OUTPUT_NEVER) {
mAudioStatusView.setText(
Html.fromHtml(
StatusTextUtils.getAudioWarningInHTML(
mContext.getString(
R.string.ut_surround_sound_disabled))));
} else {
mAudioStatusView.setText(
Html.fromHtml(
StatusTextUtils.getAudioWarningInHTML(
mContext.getString(
R.string.audio_passthrough_not_supported))));
}
mAudioStatusView.setVisibility(View.VISIBLE);
return true;
case MSG_UI_HIDE_AUDIO_UNPLAYABLE:
mAudioStatusView.setVisibility(View.INVISIBLE);
return true;
case MSG_UI_PROCESS_CAPTION_TRACK:
mCaptionTrackRenderer.processCaptionEvent((CaptionEvent) msg.obj);
return true;
case MSG_UI_START_CAPTION_TRACK:
mCaptionTrackRenderer.start((AtscCaptionTrack) msg.obj);
return true;
case MSG_UI_STOP_CAPTION_TRACK:
mCaptionTrackRenderer.stop();
return true;
case MSG_UI_RESET_CAPTION_TRACK:
mCaptionTrackRenderer.reset();
return true;
case MSG_UI_CLEAR_CAPTION_RENDERER:
mCaptionTrackRenderer.clear();
return true;
case MSG_UI_SET_STATUS_TEXT:
mStatusView.setText((CharSequence) msg.obj);
return true;
case MSG_UI_TOAST_RESCAN_NEEDED:
Toast.makeText(mContext, R.string.ut_rescan_needed, Toast.LENGTH_LONG).show();
return true;
default:
return false;
}
}
}