Merge "Codec2: fix API style for some helpers"
diff --git a/packages/MediaComponents/res/layout/media_controller.xml b/packages/MediaComponents/res/layout/media_controller.xml
index f9ebd44..73c1b38 100644
--- a/packages/MediaComponents/res/layout/media_controller.xml
+++ b/packages/MediaComponents/res/layout/media_controller.xml
@@ -71,7 +71,7 @@
android:orientation="horizontal">
<LinearLayout
- android:id="@+id/ad"
+ android:id="@+id/ad_external_link"
android:clickable="true"
android:gravity="center"
android:layout_width="wrap_content"
@@ -80,7 +80,8 @@
android:layout_centerVertical="true"
android:paddingLeft="5dip"
android:paddingRight="10dip"
- android:orientation="horizontal">
+ android:orientation="horizontal"
+ android:visibility="gone">
<TextView
android:id="@+id/ad_text"
@@ -88,7 +89,7 @@
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:paddingRight="5dip"
- android:text="Visit Advertiser"
+ android:text="@string/MediaControlView2_ad_text"
android:textSize="10sp"
android:textColor="#FFFFFFFF" />
@@ -163,14 +164,35 @@
android:textStyle="bold"
android:textColor="#BBBBBB" />
+ <TextView
+ android:id="@+id/ad_skip_time"
+ android:gravity="center"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:textSize="12sp"
+ android:textColor="#FFFFFF"
+ android:visibility="gone" />
+
<LinearLayout
android:id="@+id/basic_controls"
+ android:gravity="center"
android:layout_alignParentRight="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:orientation="horizontal" >
+ <TextView
+ android:id="@+id/ad_remaining"
+ android:gravity="center"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:textSize="12sp"
+ android:textColor="#FFFFFF"
+ android:visibility="gone" />
+
<ImageButton
android:id="@+id/subtitle"
android:scaleType="fitCenter"
diff --git a/packages/MediaComponents/res/values/strings.xml b/packages/MediaComponents/res/values/strings.xml
index 35db0e5..333d400 100644
--- a/packages/MediaComponents/res/values/strings.xml
+++ b/packages/MediaComponents/res/values/strings.xml
@@ -14,7 +14,9 @@
limitations under the License.
-->
-<resources>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
<!-- Name for the default system route prior to Jellybean. [CHAR LIMIT=30] -->
<string name="mr_system_route_name">System</string>
@@ -92,4 +94,15 @@
<string name="VideoView2_error_text_unknown">Can\'t play this video.</string>
<!-- Button to close error alert when a video cannot be played. -->
<string name="VideoView2_error_button">OK</string>
+
+ <!-- Text for displaying ad skip wait time. -->
+ <string name="MediaControlView2_ad_skip_wait_time">
+ You can skip Ad in <xliff:g id="wait_time" example="5">%1$d</xliff:g>s
+ </string>
+ <!-- Text for displaying ad total remaining time. -->
+ <string name="MediaControlView2_ad_remaining_time">
+ Ad · <xliff:g id="remaining_time" example="1:15">%1$s</xliff:g> remaining
+ </string>
+ <!-- Placeholder text indicating that the user can press the button to go to an external website. -->
+ <string name="MediaControlView2_ad_text">Visit Advertiser</string>
</resources>
diff --git a/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java b/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java
index 318cbf9..e937659 100644
--- a/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java
+++ b/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java
@@ -33,6 +33,7 @@
import android.widget.ImageButton;
import android.widget.MediaControlView2;
import android.widget.ProgressBar;
+import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
@@ -58,11 +59,15 @@
static final String KEY_STATE_CONTAINS_SUBTITLE = "StateContainsSubtitle";
static final String EVENT_UPDATE_SUBTITLE_STATUS = "UpdateSubtitleStatus";
+ // TODO: Remove this once integrating with MediaSession2 & MediaMetadata2
+ static final String KEY_STATE_IS_ADVERTISEMENT = "MediaTypeAdvertisement";
+ static final String EVENT_UPDATE_MEDIA_TYPE_STATUS = "UpdateMediaTypeStatus";
+
private static final int MAX_PROGRESS = 1000;
private static final int DEFAULT_PROGRESS_UPDATE_TIME_MS = 1000;
-
private static final int REWIND_TIME_MS = 10000;
private static final int FORWARD_TIME_MS = 30000;
+ private static final int AD_SKIP_WAIT_TIME_MS = 5000;
private MediaController mController;
private MediaController.TransportControls mControls;
@@ -71,8 +76,12 @@
private ProgressBar mProgress;
private TextView mEndTime, mCurrentTime;
private TextView mTitleView;
+ private TextView mAdSkipView, mAdRemainingView;
+ private View mAdExternalLink;
+ private View mRoot;
private int mDuration;
private int mPrevState;
+ private int mPrevLeftBarWidth;
private long mPlaybackActions;
private boolean mDragging;
private boolean mIsFullScreen;
@@ -81,6 +90,7 @@
private boolean mSubtitleIsEnabled;
private boolean mContainsSubtitle;
private boolean mSeekAvailable;
+ private boolean mIsAdvertisement;
private ImageButton mPlayPauseButton;
private ImageButton mFfwdButton;
private ImageButton mRewButton;
@@ -118,8 +128,9 @@
@Override
public void initialize(@Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
// Inflate MediaControlView2 from XML
- View root = makeControllerView();
- mInstance.addView(root);
+ mRoot = makeControllerView();
+ mRoot.addOnLayoutChangeListener(mTitleBarLayoutChangeListener);
+ mInstance.addView(mRoot);
}
@Override
@@ -140,6 +151,8 @@
@Override
public void setButtonVisibility_impl(int button, int visibility) {
+ // TODO: add member variables for Fast-Forward/Prvious/Rewind buttons to save visibility in
+ // order to prevent being overriden inside updateLayout().
switch (button) {
case MediaControlView2.BUTTON_PLAY_PAUSE:
if (mPlayPauseButton != null && canPause()) {
@@ -421,6 +434,10 @@
mCurrentTime = v.findViewById(R.id.time_current);
mFormatBuilder = new StringBuilder();
mFormatter = new Formatter(mFormatBuilder, Locale.getDefault());
+
+ mAdSkipView = v.findViewById(R.id.ad_skip_time);
+ mAdRemainingView = v.findViewById(R.id.ad_remaining);
+ mAdExternalLink = v.findViewById(R.id.ad_external_link);
}
/**
@@ -505,6 +522,36 @@
mCurrentTime.setText(stringForTime(currentPosition));
}
+ if (mIsAdvertisement) {
+ // Update the remaining number of seconds until the first 5 seconds of the
+ // advertisement.
+ if (mAdSkipView != null) {
+ if (currentPosition <= AD_SKIP_WAIT_TIME_MS) {
+ if (mAdSkipView.getVisibility() == View.GONE) {
+ mAdSkipView.setVisibility(View.VISIBLE);
+ }
+ String skipTimeText = ApiHelper.getLibResources().getString(
+ R.string.MediaControlView2_ad_skip_wait_time,
+ ((AD_SKIP_WAIT_TIME_MS - currentPosition) / 1000 + 1));
+ mAdSkipView.setText(skipTimeText);
+ } else {
+ if (mAdSkipView.getVisibility() == View.VISIBLE) {
+ mAdSkipView.setVisibility(View.GONE);
+ mNextButton.setEnabled(true);
+ mNextButton.clearColorFilter();
+ }
+ }
+ }
+ // Update the remaining number of seconds of the advertisement.
+ if (mAdRemainingView != null) {
+ int remainingTime =
+ (mDuration - currentPosition < 0) ? 0 : (mDuration - currentPosition);
+ String remainingTimeText = ApiHelper.getLibResources().getString(
+ R.string.MediaControlView2_ad_remaining_time,
+ stringForTime(remainingTime));
+ mAdRemainingView.setText(remainingTimeText);
+ }
+ }
return currentPosition;
}
@@ -693,6 +740,36 @@
}
};
+ // The title bar is made up of two separate LinearLayouts. If the sum of the two bars are
+ // greater than the length of the title bar, reduce the size of the left bar (which makes the
+ // TextView that contains the title of the media file shrink).
+ private final View.OnLayoutChangeListener mTitleBarLayoutChangeListener
+ = new View.OnLayoutChangeListener() {
+ @Override
+ public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
+ int oldTop, int oldRight, int oldBottom) {
+ if (mRoot != null) {
+ int titleBarWidth = mRoot.findViewById(R.id.title_bar).getWidth();
+
+ View leftBar = mRoot.findViewById(R.id.title_bar_left);
+ View rightBar = mRoot.findViewById(R.id.title_bar_right);
+ int leftBarWidth = leftBar.getWidth();
+ int rightBarWidth = rightBar.getWidth();
+
+ RelativeLayout.LayoutParams params =
+ (RelativeLayout.LayoutParams) leftBar.getLayoutParams();
+ if (leftBarWidth + rightBarWidth > titleBarWidth) {
+ params.width = titleBarWidth - rightBarWidth;
+ mPrevLeftBarWidth = leftBarWidth;
+ } else if (leftBarWidth + rightBarWidth < titleBarWidth && mPrevLeftBarWidth != 0) {
+ params.width = mPrevLeftBarWidth;
+ mPrevLeftBarWidth = 0;
+ }
+ leftBar.setLayoutParams(params);
+ }
+ }
+ };
+
private void updateDuration() {
if (mMetadata != null) {
if (mMetadata.containsKey(MediaMetadata.METADATA_KEY_DURATION)) {
@@ -711,6 +788,39 @@
}
}
+ private void updateLayout() {
+ if (mIsAdvertisement) {
+ mRewButton.setVisibility(View.GONE);
+ mFfwdButton.setVisibility(View.GONE);
+ mPrevButton.setVisibility(View.GONE);
+ mCurrentTime.setVisibility(View.GONE);
+ mEndTime.setVisibility(View.GONE);
+
+ mAdSkipView.setVisibility(View.VISIBLE);
+ mAdRemainingView.setVisibility(View.VISIBLE);
+ mAdExternalLink.setVisibility(View.VISIBLE);
+
+ mProgress.setEnabled(false);
+ mNextButton.setEnabled(false);
+ mNextButton.setColorFilter(R.integer.gray);
+ } else {
+ mRewButton.setVisibility(View.VISIBLE);
+ mFfwdButton.setVisibility(View.VISIBLE);
+ mPrevButton.setVisibility(View.VISIBLE);
+ mCurrentTime.setVisibility(View.VISIBLE);
+ mEndTime.setVisibility(View.VISIBLE);
+
+ mAdSkipView.setVisibility(View.GONE);
+ mAdRemainingView.setVisibility(View.GONE);
+ mAdExternalLink.setVisibility(View.GONE);
+
+ mProgress.setEnabled(true);
+ mNextButton.setEnabled(true);
+ mNextButton.clearColorFilter();
+ disableUnsupportedButtons();
+ }
+ }
+
private class MediaControllerCallback extends MediaController.Callback {
@Override
public void onPlaybackStateChanged(PlaybackState state) {
@@ -818,6 +928,12 @@
}
mContainsSubtitle = newSubtitleStatus;
}
+ } else if (event.equals(EVENT_UPDATE_MEDIA_TYPE_STATUS)) {
+ boolean newStatus = extras.getBoolean(KEY_STATE_IS_ADVERTISEMENT);
+ if (newStatus != mIsAdvertisement) {
+ mIsAdvertisement = newStatus;
+ updateLayout();
+ }
}
}
}
diff --git a/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java b/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
index a8ce18b..805c262 100644
--- a/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
+++ b/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
@@ -27,6 +27,7 @@
import android.media.MediaPlayerInterface;
import android.media.Cea708CaptionRenderer;
import android.media.ClosedCaptionRenderer;
+import android.media.MediaMetadata2;
import android.media.Metadata;
import android.media.PlaybackParams;
import android.media.SRTRenderer;
@@ -107,6 +108,9 @@
private MediaRouter mMediaRouter;
private MediaRouteSelector mRouteSelector;
private Metadata mMetadata;
+ private MediaMetadata2 mMediaMetadata;
+ private boolean mNeedUpdateMediaType;
+ private Bundle mMediaTypeData;
private String mTitle;
private PlaybackState.Builder mStateBuilder;
@@ -235,6 +239,32 @@
}
@Override
+ public MediaMetadata2 getMediaMetadata_impl() {
+ return mMediaMetadata;
+ }
+
+ @Override
+ public void setMediaMetadata_impl(MediaMetadata2 metadata) {
+ // TODO: integrate this with MediaSession2#MediaItem2
+ mMediaMetadata = metadata;
+
+ // TODO: add support for handling website link
+ mMediaTypeData = new Bundle();
+ boolean isAd = metadata == null ?
+ false : metadata.getLong(MediaMetadata2.METADATA_KEY_ADVERTISEMENT) != 0;
+ mMediaTypeData.putBoolean(
+ MediaControlView2Impl.KEY_STATE_IS_ADVERTISEMENT, isAd);
+
+ if (mMediaSession != null) {
+ mMediaSession.sendSessionEvent(
+ MediaControlView2Impl.EVENT_UPDATE_MEDIA_TYPE_STATUS, mMediaTypeData);
+ } else {
+ // Update later inside OnPreparedListener after MediaSession is initialized.
+ mNeedUpdateMediaType = true;
+ }
+ }
+
+ @Override
public void setSubtitleEnabled_impl(boolean enable) {
if (enable != mSubtitleEnabled) {
selectOrDeselectSubtitle(enable);
@@ -866,6 +896,13 @@
if (mMediaSession != null) {
mMediaSession.setMetadata(builder.build());
+
+ // TODO: merge this code with the above code when integrating with MediaSession2.
+ if (mNeedUpdateMediaType) {
+ mMediaSession.sendSessionEvent(
+ MediaControlView2Impl.EVENT_UPDATE_MEDIA_TYPE_STATUS, mMediaTypeData);
+ mNeedUpdateMediaType = false;
+ }
}
}
};