MediaController Positioning - bind to VideoView - android

There have been a lot of discussions about how to position a MediaController and most answers are to use the setAnchorView-Method. At the first glance this solution seems to work but in my case it doesn't.
According to this Post setAnchorView only acts as a reference for initial positioning of the MediaController, but actually creates a new floating Window on top.
So what I want is a MediaController that is really bound to a parent View (e.g. VideoView).
For example if you have a LinearLayout within a ScrollView and you have to scroll down to your VideoView where the MediaController is attached to, the MediaController should really be attached to this VideoView so that the MediaController scrolls along with the VideoView.
Another Use-Case where this problem accurs is discussed here, where the MediaController is used within a ViewPager.
So how to achieve such a behavior for a MediaController?

I ended up by doing a dirty hack... i just manually attached the view to my videoView to achieve the wanted behavior:
public void onPrepared(MediaPlayer mp) {
MediaController mc = new MediaController(videoView.getContext(), false);
// set correct height
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) videoView.getLayoutParams();
params.height = mp.getVideoHeight();
videoView.setLayoutParams(params);
videoView.setMediaController(mc);
pBar.setVisibility(View.GONE);
mc.show(0);
FrameLayout f = (FrameLayout) mc.getParent();
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
lp.addRule(RelativeLayout.ALIGN_BOTTOM, videoView.getId());
((LinearLayout) f.getParent()).removeView(f);
((RelativeLayout) videoView.getParent()).addView(f, lp);
mc.setAnchorView(videoView);
}
the problem with this solution is, that setting the anchorView doesn't have any effect and therefore tapping on the VideoView doesn't hide/show the MediaController as it's supposed to.
There definitly is a much better solution and hopefully someone can give me a hint!

Just wanted to add to DERIIIFranz's answer. I used the same method to assign the media controller to the view I wanted and to get the Hide() and Show() functions to work properly I simply made my own MediaController class and overrode the Hide() and Show() methods as well as the isShowing property (I'm doing this in C# with Xamarin, so I don't know what issues you would have with Java).
I also added my own click listener on the VideoView to ensure that I could handle the Hide() and Show() events myself.
public class MyMediaController : MediaController
{
private bool _isShowing { get; set; } = false;
public override bool IsShowing { get { return _isShowing; } }
public override void Show ()
{
base.Show();
_isShowing = true;
Native.ViewGroup parent = ((Native.ViewGroup)this.Parent);
parent.Visibility = Native.ViewStates.Visible;
}
public override void Hide ()
{
base.Hide();
_isShowing = false;
Native.ViewGroup parent = ((Native.ViewGroup)this.Parent);
parent.Visibility = Native.ViewStates.Gone;
}
}

To convert Jonathan Hockman's answer to Java and add it to DERIIIFranz's answer:
public class MyMediaController extends MediaController {
public MyMediaController(Context context) {
super(context);
}
public MyMediaController(Context context, boolean useFastForward) {
super (context, useFastForward);
}
public MyMediaController(Context context, AttributeSet attrs) {
super(context, attrs);
}
private boolean _isShowing = false;
#Override
public boolean isShowing() { return _isShowing; }
#Override
public void show() {
super.show();
_isShowing = true;
ViewGroup parent = (ViewGroup) this.getParent();
parent.setVisibility(View.VISIBLE);
}
#Override
public void hide() {
super.hide();
_isShowing = false;
ViewGroup parent = (ViewGroup) this.getParent();
parent.setVisibility(View.GONE);
}
}
For the videoView:
public void onPrepared(MediaPlayer mediaPlayer) {
MyMediaController mediaController = new MyMediaController(videoView.getContext(), false);
RelativeLayout parentLayout = (RelativeLayout) videoView.getParent();
RelativeLayout.LayoutParams parentParams = (RelativeLayout.LayoutParams) parentLayout.getLayoutParams();
parentParams.height = this.getHeight();
parentLayout.setLayoutParams(parentParams);
FrameLayout frameLayout = (FrameLayout) mediaController.getParent();
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, this.getId());
((ViewGroup)frameLayout.getParent()).removeView(frameLayout);
parentLayout.addView(frameLayout, layoutParams);
mediaController.setAnchorView(this);
mediaController.hide();
videoView.setMediaController(mediaController);
}

Related

Not able to create buttons dynamically

I have an overlay on my screen which will show some buttons to control the feature. This overlay will have a dynamic list of buttons which will be created based on the number of steps. Example if steps are 3 then 3 button will get created. I have created a LinearLayout inside this buttons will get created. I have created a method which will set all the button attributes, but somehow it's giving me null pointer exception.
In onCreateView I have initialize the buttonArray.
Here is my fragment:
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
mContext = getActivity();
gc = GlobalClass.getInstance(mContext);
db = DataBaseHelper.getInstance(mContext);
sectionButtons = new Button[3];
/*if(savedInstanceState!=null)
mVisible = savedInstanceState.getBoolean("visible",false);*/
manager = SharedPreferenceManager.getInstance(mContext);
//check wether to play video in cover mode or another mode
inflater.inflate(R.layout.fragment_video_side_by_side, container, false);
}
and onViewCreated() I am calling my method addSections():
// show overlay with buttons in onTouch
parentLayout.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (!mVisible) {
overLay.setVisibility(View.VISIBLE);
addSections(3);
mVisible = true;
} else {
overLay.setVisibility(View.GONE);
mVisible = false;
}
}
return true;
}
});
Method:
public void addSections(int numOfSection){
if(numOfSection==0)
return;
else {
for (int i = 0; i < numOfSection; i++) {
//set the properties for button
sectionButtons[i].setLayoutParams(new LinearLayout.LayoutParams(50, 50));
sectionButtons[i].setBackgroundResource(R.drawable.round_button);
sectionButtons[i].setText("Section "+i+"");
sectionButtons[i].setId(i);
//add button to the layout
mSectionLayout.addView(sectionButtons[i]);
}
}
}
mSectionLayout is my parent LinearLayout. While debugging I found my sectionButtons is not showing null but while setting the attributes it's throwing nullPointer exception.
Create Dynamic Buttons and attach with the Layout
You can easily create the dynamic button by the following way:
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
LinearLayout layout = (LinearLayout) findViewById(R.id.layout);
TextView textView = new TextView(this);
textView.setText("Text View ");
LinearLayout.LayoutParams p = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT
);
layout.addView(textView, p);
Button buttonView = new Button(this);
buttonView.setText("Button");
buttonView.setOnClickListener(mThisButtonListener);
layout.addView(buttonView, p);
}
private OnClickListener mThisButtonListener = new OnClickListener() {
public void onClick(View v) {
Toast.makeText(MainActivity.this, "Hello !",
Toast.LENGTH_LONG).show();
}
};
}
Using this code, you easily generate a list of buttons on the layout.
Happy coding

PopupWindow cannot display Unity3D views in Android, but Dialog does?

Here is some brief codes of my project, in which I'd like to display a Unity3D model to do something.
public class MainActivity extends FragmentActivity{
protected UnityPlayer mUnityPlayer;
#Override
protected void onCreate(Bundle savedInstanceState) {
...
getWindow().setFormat(PixelFormat.RGBX_8888);
mUnityPlayer = new UnityPlayer(this);
...
mTestImageButton = ***;
mTestImageButton.setOnClickListener(mTestImageButtonClickListener);
}
private ImageButton mTestImageButton;
private View.OnClickListener mTestImageButtonClickListener = new
View.OnClickListener() {
#Override
public void onClick(View v) {
showUnity3D_dialog(v);
//showUnity3D_popupwindow(v);
}
};
private void showUnity3D_dialog(View v) {
Dialog dialog = new Dialog(v.getContext(), R.style.move_dialog);
dialog.setContentView(mUnityPlayer);
Window window = dialog.getWindow();
window.setWindowAnimations(R.style.move_dialog);
WindowManager.LayoutParams lp = window.getAttributes();
window.setGravity(Gravity.RIGHT | Gravity.BOTTOM);
lp.width = 1179;
lp.height = WindowManager.LayoutParams.MATCH_PARENT;
window.setFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
window.setAttributes(lp);
dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
}
});
dialog.setCanceledOnTouchOutside(true);
dialog.show();
mUnityPlayer.resume();
}
private void showUnity3D_popupwindow(View v) {
PopupWindow pop = new PopupWindow(mUnityPlayer, 1000, 800);
pop.setBackgroundDrawable(new BitmapDrawable());
pop.setFocusable(true);
pop.setOutsideTouchable(false);
pop.setOnDismissListener(new PopupWindow.OnDismissListener() {
#Override
public void onDismiss() {
}
});
pop.showAtLocation(v, Gravity.BOTTOM, 0, 0);
mUnityPlayer.resume();
}
}
As codes above, I tried to display a Unity3D-model in a PopupWindow, but the result makes me a bit confused, since there is nothing on screen when I called showUnity3D_popupwindow(v).
But when I called showUnity3D_dialog(v), the model by Unity3D shows.
I really can't understand what caused such scenario, and how can I display my model in a PopupWindow in android? Or, is it an impossible task?
I have my project under Android 4.3 & Unity 5.4.0.
Thanks a lot.
Looks like you are currently using the PopupWindow(View contentView, int width, int height) overload function. I've seen instances where functions that take View, Context or Activity does not work in Unity and you have to try other overloads.
You've tried the one takes View, now try the Context overload:
PopupWindow(Context context)
then set the width and height later on with the setWidth and setHeight function. You can get the current Context with UnityPlayer.currentActivity.getApplicationContext().
private void showUnity3D_popupwindow(View v)
{
Context mContext = UnityPlayer.currentActivity.getApplicationContext();
PopupWindow pop = new PopupWindow(mContext);
pop.setWidth(1000);
pop.setHeight(800);
pop.setBackgroundDrawable(new BitmapDrawable());
pop.setFocusable(true);
pop.setOutsideTouchable(false);
pop.setOnDismissListener(new PopupWindow.OnDismissListener() {
#Override
public void onDismiss() {
}
});
pop.showAtLocation(v, Gravity.BOTTOM, 0, 0);
mUnityPlayer.resume();
}

Dynamically add LinearLayout into LinearLayout

I have a issue trying to dynamically add some linear layout into a linearlayout container after user have clicked on a button.
private void AddView() {
MyView myView1 = new MyView("Name");
this.mainLinearLayout.addView(myView1);
}
This code works great in activity's onCreate method but not after handling user event.
Do you have any idea why it's not working ? (I mean nothing appears on UI)
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AddView(); => works great
}
playButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
AddView(); => not working
}
});
Thanks,
I think that AddView is wrong.
private void addView() {
LayoutParams lparams = new LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
MyView myView1 = new MyView("Name");
myView1.setLayoutParams(lparams);
this.mainLinearLayout.addView(myView1);
}

HTML5 video mediacontroller hide behind dialog

I have a webview to display html5 video, my objective is to display the video in fullscreen. In order to do this, I have to extend the WebChromeClient Class and override the method onShowCustomView and OnHideCustomView. The project I am currently working on is a library project, so the activity_main.xml is not available. Then I use a dialog to display the video in full screen. The problem is the mediacontroller is not showing. Here is my code:
#Override
public void onShowCustomView(View view, CustomViewCallback callback) {
if (customView != null){
customViewCallback = callback;
callback.onCustomViewHidden();
return;
}
root = new RelativeLayout(mContext);
customViewCallback = callback;
customView = view;
root.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
root.addView(customView,params);
Button closeBtn = new Button(mContext);
closeBtn.setText("Close");
params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.ALIGN_PARENT_TOP);
closeBtn.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
onHideCustomView();
}
});
root.addView(closeBtn);
mDialog = new Dialog(mContext,android.R.style.Theme_NoTitleBar_Fullscreen);
mDialog.setContentView(root);
mDialog.show();
}
#Override
public void onHideCustomView() {
if (mDialog != null) {
mDialog.dismiss();
customViewCallback.onCustomViewHidden();
}
mDialog = null;
customView = null;
root = null;
}
customView is a View, root is a RelativeLayout and they are members of the extended WebChromeClient class. How to show the media controller, anybody helps? By the way, is there any ways to customize the media contorller in this case?

Android WebView with an embedded youtube video, full screen button freezes video

I have an android webview that loads a wordpress blog. Some blog posts contain youtube videos which I would like the user to be able to make full screen if they wish. The problem is the HTML5 full screen button does nothing when clicked but freeze up the view.
Any ideas?
This is something I've spent the last day or so tearing my hair out over. Based on various bits of code from around the web I've managed to get it working.
First, you need to create a custom WebChromeClient class, which implements the onShowCustomView and onHideCustomView methods.
private class MyWebChromeClient extends WebChromeClient {
FrameLayout.LayoutParams LayoutParameters = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT);
#Override
public void onShowCustomView(View view, CustomViewCallback callback) {
// if a view already exists then immediately terminate the new one
if (mCustomView != null) {
callback.onCustomViewHidden();
return;
}
mContentView = (RelativeLayout) findViewById(R.id.activity_main);
mContentView.setVisibility(View.GONE);
mCustomViewContainer = new FrameLayout(MainActivity.this);
mCustomViewContainer.setLayoutParams(LayoutParameters);
mCustomViewContainer.setBackgroundResource(android.R.color.black);
view.setLayoutParams(LayoutParameters);
mCustomViewContainer.addView(view);
mCustomView = view;
mCustomViewCallback = callback;
mCustomViewContainer.setVisibility(View.VISIBLE);
setContentView(mCustomViewContainer);
}
#Override
public void onHideCustomView() {
if (mCustomView == null) {
return;
} else {
// Hide the custom view.
mCustomView.setVisibility(View.GONE);
// Remove the custom view from its container.
mCustomViewContainer.removeView(mCustomView);
mCustomView = null;
mCustomViewContainer.setVisibility(View.GONE);
mCustomViewCallback.onCustomViewHidden();
// Show the content view.
mContentView.setVisibility(View.VISIBLE);
setContentView(mContentView);
}
}
}
Basically, what is happening here is when the full screen button gets pressed, we're creating a new view to hold the video and hiding the main view. And then when full screen is closed, we do the opposite - get rid of the new view and display the original view.
You'll need to also add all those properties to your activity class:
private MyWebChromeClient mWebChromeClient = null;
private View mCustomView;
private RelativeLayout mContentView;
private FrameLayout mCustomViewContainer;
private WebChromeClient.CustomViewCallback mCustomViewCallback;
And you probably want to make it close the fullscreen video when the back button is pressed:
#Override
public void onBackPressed() {
if (mCustomViewContainer != null)
mWebChromeClient.onHideCustomView();
else if (myWebView.canGoBack())
myWebView.goBack();
else
super.onBackPressed();
}
Then it's just a matter of using your new class when you create your webview:
myWebView = (WebView) findViewById(R.id.webView1);
mWebChromeClient = new WMWebChromeClient();
myWebView.setWebChromeClient(mWebChromeClient);
This works for me on Android 4.x. Not sure about earlier versions as my app isn't targeting them.
I found these links particularly useful: WebView and HTML5 <video> and http://code.google.com/p/html5webview/source/browse/trunk/HTML5WebView/src/org/itri/html5webview/HTML5WebView.java
Thanks to #Mark Parnell for his response, but he is doing it in hard way with heavy UI changes, maybe this way is cleaner and more understandable:
When fullscreen button clicked, chrome client gives us fullscreen view and then we should add it to our activity view :
Define this variable global to hold fullscreen view reference in our activity:
public class MyAmazingActivity extends AppCompatActivity {
private View fullscreenView;
//...
}
Then web chrome client will notify us about showing and hiding fullscreen view in onShowCustomView and onHideCustomView methods:
WebChromeClient webChromeClient = new WebChromeClient() {
private ViewGroup rootView;
private WebChromeClient.CustomViewCallback customViewCallback;
#Override
public void onShowCustomView(View view, CustomViewCallback callback) {
//Destroy full screen view if already exists
if (fullscreenView != null) {
callback.onCustomViewHidden();
return;
}
//Layout params to fit fullscreen view in our activity
ViewGroup.LayoutParams layoutParams =
new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
//Catch root of current activity to add fullscreen view
rootView = (ViewGroup) WebViewBaseActivity.this.webView.getRootView();
//Store full screen view, we need it to destroy it out of scope
fullscreenView = view;
customViewCallback = callback;
rootView.addView(fullscreenView, layoutParams);
}
#Override
public void onHideCustomView() {
//Make sure fullscreen view exists
if (fullscreenView != null) {
//Remove fullscreen view from activity root view
rootView.removeView(fullscreenView);
fullscreenView = null;
//Tell browser we did remove fullscreen view
customViewCallback.onCustomViewHidden();
}
}
};
And finally removing fullscreen view when back pressed(User expects this behaviour):
#Override
public void onBackPressed() {
if (fullscreenView != null) {
webChromeClient.onHideCustomView();
}
}
You can start an external YouTube app when you will cath video info URLif it is not important to show YouTube video directly in application.
To catch video info URL You need to owerride onLoadResource method:
new WebViewClient() {
#Override
public void onLoadResource(WebView view, String url) {
if (url.startsWith("http://www.youtube.com/get_video_info?")) {
try {
String path = url.replace("http://www.youtube.com/get_video_info?", "");
String[] parqamValuePairs = path.split("&");
String videoId = null;
for (String pair : parqamValuePairs) {
if (pair.startsWith("video_id")) {
videoId = pair.split("=")[1];
break;
}
}
if(videoId != null){
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.youtube.com"))
.setData(Uri.parse("http://www.youtube.com/watch?v=" + videoId)));
needRefresh = true;
return;
}
} catch (Exception ex) {
}
} else {
super.onLoadResource(view, url);
}
}
}

Categories

Resources