VideoView2: Add custom actions support

Test: Using VideoViewTest application
Change-Id: Idf471a663e989feb2a2cb41648edfeaf8c6f146d
diff --git a/packages/MediaComponents/res/layout/media_controller.xml b/packages/MediaComponents/res/layout/media_controller.xml
index 4d05546..74a8306 100644
--- a/packages/MediaComponents/res/layout/media_controller.xml
+++ b/packages/MediaComponents/res/layout/media_controller.xml
@@ -136,7 +136,13 @@
             android:layout_height="wrap_content"
             android:layout_centerVertical="true"
             android:visibility="gone"
-            android:orientation="horizontal" >
+            android:orientation="horizontal"
+            android:gravity="center">
+
+            <LinearLayout
+                android:id="@+id/custom_buttons"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content" />
 
             <ImageButton
                 android:id="@+id/mute"
diff --git a/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java b/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java
index bc370d8..b5c9456 100644
--- a/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java
+++ b/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java
@@ -29,6 +29,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityManager;
+import android.widget.Button;
 import android.widget.ImageButton;
 import android.widget.MediaControlView2;
 import android.widget.ProgressBar;
@@ -40,6 +41,7 @@
 import com.android.media.update.R;
 
 import java.util.Formatter;
+import java.util.List;
 import java.util.Locale;
 
 public class MediaControlView2Impl implements MediaControlView2Provider {
@@ -97,6 +99,7 @@
     private ImageButton mOverflowButtonRight;
 
     private ViewGroup mExtraControls;
+    private ViewGroup mCustomButtons;
     private ImageButton mOverflowButtonLeft;
     private ImageButton mMuteButton;
     private ImageButton mAspectRationButton;
@@ -501,6 +504,7 @@
 
         // TODO: should these buttons be shown as default?
         mExtraControls = v.findViewById(R.id.extra_controls);
+        mCustomButtons = v.findViewById(R.id.custom_buttons);
         mOverflowButtonLeft = v.findViewById(R.id.overflow_left);
         if (mOverflowButtonLeft != null) {
             mOverflowButtonLeft.setOnClickListener(mOverflowLeftListener);
@@ -875,6 +879,31 @@
                 }
                 mPlaybackActions = newActions;
             }
+
+            // Add buttons if custom actions are present.
+            List<PlaybackState.CustomAction> customActions = mPlaybackState.getCustomActions();
+            mCustomButtons.removeAllViews();
+            if (customActions.size() > 0) {
+                for (PlaybackState.CustomAction action : customActions) {
+                    ImageButton button = new ImageButton(mInstance.getContext(),
+                            null /* AttributeSet */, 0 /* Style */);
+                    // TODO: Apply R.style.BottomBarButton to this button using library context.
+                    // Refer Constructor with argument (int defStyleRes) of View.java
+                    button.setImageResource(action.getIcon());
+                    button.setTooltipText(action.getName());
+                    final String actionString = action.getAction().toString();
+                    button.setOnClickListener(new View.OnClickListener() {
+                        @Override
+                        public void onClick(View v) {
+                            // TODO: Currently, we are just sending extras that came from session.
+                            // Is it the right behavior?
+                            mControls.sendCustomAction(actionString, action.getExtras());
+                            mInstance.show(DEFAULT_TIMEOUT_MS);
+                        }
+                    });
+                    mCustomButtons.addView(button);
+                }
+            }
         }
 
         @Override
diff --git a/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java b/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
index 09f3cda..eb236f0 100644
--- a/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
+++ b/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
@@ -28,8 +28,6 @@
 import android.media.MediaPlayerBase;
 import android.media.Cea708CaptionRenderer;
 import android.media.ClosedCaptionRenderer;
-import android.media.MediaMetadata;
-import android.media.MediaPlayer;
 import android.media.Metadata;
 import android.media.PlaybackParams;
 import android.media.SubtitleController;
@@ -82,6 +80,7 @@
     private int mAudioFocusType = AudioManager.AUDIOFOCUS_GAIN; // legacy focus gain
     private int mAudioSession;
 
+    private VideoView2.OnCustomActionListener mOnCustomActionListener;
     private VideoView2.OnPreparedListener mOnPreparedListener;
     private VideoView2.OnCompletionListener mOnCompletionListener;
     private VideoView2.OnErrorListener mOnErrorListener;
@@ -101,6 +100,7 @@
     private String mTitle;
 
     private PlaybackState.Builder mStateBuilder;
+    private List<PlaybackState.CustomAction> mCustomActionList;
     private int mTargetState = STATE_IDLE;
     private int mCurrentState = STATE_IDLE;
     private int mCurrentBufferPercentage;
@@ -319,6 +319,17 @@
     }
 
     @Override
+    public void setCustomActions_impl(List<PlaybackState.CustomAction> actionList,
+            VideoView2.OnCustomActionListener listener) {
+        mCustomActionList = actionList;
+        mOnCustomActionListener = listener;
+
+        // Create a new playback builder in order to clear existing the custom actions.
+        mStateBuilder = null;
+        updatePlaybackState();
+    }
+
+    @Override
     public void setOnPreparedListener_impl(VideoView2.OnPreparedListener l) {
         mOnPreparedListener = l;
     }
@@ -660,8 +671,12 @@
             }
             mStateBuilder = new PlaybackState.Builder();
             mStateBuilder.setActions(playbackActions);
-            mStateBuilder.addCustomAction(MediaControlView2Impl.COMMAND_SHOW_SUBTITLE, null, -1);
-            mStateBuilder.addCustomAction(MediaControlView2Impl.COMMAND_HIDE_SUBTITLE, null, -1);
+
+            if (mCustomActionList != null) {
+                for (PlaybackState.CustomAction action : mCustomActionList) {
+                    mStateBuilder.addCustomAction(action);
+                }
+            }
         }
         mStateBuilder.setState(getCorrespondingPlaybackState(),
                 mMediaPlayer.getCurrentPosition(), mSpeed);
@@ -931,6 +946,11 @@
         }
 
         @Override
+        public void onCustomAction(String action, Bundle extras) {
+            mOnCustomActionListener.onCustomAction(action, extras);
+        }
+
+        @Override
         public void onPlay() {
             if (isInPlaybackState() && mCurrentView.hasAvailableSurface()) {
                 applySpeed();