GLSurfaceView overlaps other views - android

I've got a programmatically-created layout, where when my app gets ads, it'll show an admob view, pushing my existing GLView down and resizing it.
However, although it initially seems to be pushing my GLView down, the GLView suddenly resets itself and overlaps the AdMob view and resets itself to its original size.
This is what I do to resize and reposition the GLSurfaceView:
Main.Instance.admobView.setVisibility(View.VISIBLE);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(Main.Instance.GLView.getWidth(),
Main.Instance.GLView.getHeight() - AdSize.BANNER.getHeight());
params.topMargin = AdSize.BANNER.getHeight();
Main.Instance.GLView.setLayoutParams(params);
Main.Instance.TopView.requestLayout();
This is what I get in the end:
http://i.stack.imgur.com/UuwKA.png
Does anyone have any idea what could be causing this?

Related

Custom view added to WindowManager, pass events to underlying window depending on state

I have a fairly complicated situation where I need to either process events in a custom view, which is added via WindowManager, or pass them to the underlying window if it is outside of the wanted area. The wanted area is the containerView where it can be smaller from the root view itself, or may have equal width / height.
The view has a size of 28x28, but it can grow up until 60x60. The growing part is done with ValueAnimator where current width and target width is determined by the ValueAnimator.getAnimatedValue() (in this case, between 28 and 60). The window needs to consume the event if it has been clicked on, or the target view which may be smaller than the window itself, is clicked.
An example of the layout looks like this:
<FrameLayout android:layout_width="wrap_content"
android:layout_height="wrap_content">
<FrameLayout android:id="#+id/containerView"
android:layout_width="28dp"
android:layout_height="28dp"
android:layout_gravity="center">
<!-- rest of the view, not important -->
<!-- the containerView can have 28x28 size or
60x60 size -->
</FrameLayout>
</FrameLayout>
The animated view is the one that is defined with android:id="#+id/containerView".
I've tried to attach the view using regular layout params, like this, to make the window layout dynamic:
WindowManager manager = context.getSystemService(WindowManager.class);
View rootView = LayoutInflater.from(context).inflate(resId, null, false);
WindowManager.LayoutParams params = new WindowManager.LayoutParams();
params.width = WindowManager.LayoutParams.WRAP_CONTENT;
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
params.flags = FLAG_NOT_FOCUSABLE | FLAG_WATCH_OUTSIDE_TOUCH;
manager.addView(rootView, params);
And this similar code block adds the view with 28x28 size, that's not a problem. However, while animating to 60x60 size depending on a state change (on containerView), the animation flickers a lot. I guess it happens because both view itself and the window needs to be re-sized. I've tried to use setLayerType(HARDWARE, null) but that didn't seem to work. Then I've found another workaround, which is increasing the size of the window directly, before starting the animation, by giving it fixed width-height values, like this:
params.width = dpToPx(60);
params.height = dpToPx(60);
manager.updateViewLayout(rootView, params);
And after this, I start the growing animation, which changes the containerView width and height gradually. With this way, animation is smooth, even on lower-end devices so I think it's a good optimization.
The problem begins with the window size change. You see, containerView has to have the attribute android:layout_gravity="center" to position the view to window's center. But, increasing the window width and height changes the view's position. To overcome that, I've decided to write another approach by doing something like this:
// This method is inside the root view, which contains
// the WindowManager.LayoutParams as its layout params.
private void setWindowSize(int widthPx, int heightPx)
{
WindowManager.LayoutParams params = getLayoutParams(); // ignore cast
int oldWidth = params.width;
int oldHeight = params.height;
int differenceWidth = widthPx - oldWidth;
int differenceHeight = heightPx - oldHeight;
// Position the view relatively to the window so
// it should look like its position is not changed
// due to containerView's center layout_gravity.
params.x -= differenceWidth / 2;
params.y -= differenceHeight / 2;
params.width = widthPx;
params.height = heightPx;
// Update itself since this is already the root view.
manager.updateViewLayout(this, params);
}
The code above was causing the position change happening with animation. Hence, I've searched if this animation can be disabled, and found an answer here which seems to be working with Android 10 emulator. However, I don't think this is a reliable approach, as most manufacturers change source codes of framework classes to implement their own themes etc. so I'm looking for a more reliable approach. The change also cause a flicker due to the containerView.onLayout() operation, presumably happening after manager.updateViewLayout() is executed, where it appears on top-left for one frame and on center on the 2nd frame, visible to the eyes.
At this point, I can only think of some ways to prevent these bugs:
1) Process touch events only on certain states (such as the coordinates intercepting the containerView)
2) Make the view non-touchable after receiving MotionEvent.ACTION_OUTSIDE which will indicate a touch event happened outside of the view's boundaries.
1st one has a flaw: If the view is clickable in all cases, it becomes clickable starting from the root view, and once the touch event is received from that view, it is not transferred to other windows (a.k.a underlying applications) which cause an issue.
2nd one seemed a good approach for me, but the event MotionEvent.ACTION_OUTSIDE does not contain any specific x or y coordinates so it is impossible to tell if the event occurred in window's boundaries. If this was possible, I'd add FLAG_NOT_TOUCHABLE to layout params and updated the view, and removed that flag if the touch is to be processed.
So, my question is:
Can a custom view, that has been added with a WindowManager choose to deliver the events further based on, i don't know, returning false from dispatchTouchEvent() or something? Or, is there a way to receive all touch events even outside our application with the specific screen coordinates so I can change the window flags depending on it?
Any help is appreciated, thank you very much.
I was able to resolve the issue by applying an ugly hack. I've used a second window, where the window itself is full screen and contains flags FLAG_NOT_FOCUSABLE and FLAG_NOT_TOUCHABLE and since the touch is disabled the events are passed below window.
The window-resize flickering depending on the animation was the cause, so I've thought about using a temporary view, added the view to a second window, by getting the cache of the view itself using a bitmap and a canvas (the states are cached and recycled by the way), and making the image view visible, setting the view on the original window as INVISIBLE and after making sure it became invisible (by using ViewTreeObserver.addOnDrawListener because the draw function is called) changing window size.
With this approach, the view becomes already invisible while the window size is changed, and translated accordingly, which eliminated the possibility of the buggy view.
Then, after the layout is complete (I've also made sure by using ViewTreeObserver.addOnGlobalLayoutListener() and waiting for the view to be placed on the target coordinates relative to parent), switched the views. Extra memory is used because of the extra added window and image view and bitmap, but the issue seems to be resolved.
The only remaining thing is how to disable window animations with the call windowManager.updateViewLayout() because the flag that the other question mentioned is apparently added in API 18, whereas this app targets to API 16. On the rest of the emulators and the devices that I've tested on seem to have this flag consistently, and the window translate animations seem to be disabled successfully.

android VideoView resizes video

I have a custom VideoView, I'm overriding onMeasure method to make video fill the screen, while keeping proportions of the video file.
Everything works fine, but with some videos, it has a strange behaviour:
I put an interrupt point in onMeasure method and run in debug mode.
When video loads, it fills the screen as expected, but after some seconds, exactly when the mouse pointer disappears, the video resizes to its original size, not filling the screen, and without passing again over the interrupt point (onMeasure method is not called).
If I move the mouse again, the video fills the screen until the pointer disappears.
I'm using Android 4.4.4.
In case someone has the same problem, I'll post what I did:
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getRealMetrics(metrics);
FrameLayout fralayout = (FrameLayout) findViewById(R.id.framelayoutparent);
FrameLayout.LayoutParams lpFraParams = (FrameLayout.LayoutParams) fralayout.getLayoutParams();
lpFraParams.width = metrics.widthPixels-1;
lpFraParams.height = metrics.heightPixels-1;
fralayout.setLayoutParams(lpFraParams);
Previously I didn't substract one pixel to width and height, substracting one pixel did the trick. This FrameLayout is the parent of the VideoView.
I don't understand why it had that behaviour.

Android ViewPropertyAnimator silently fails alpha animations on large views

I have a list view that is populated with data from a web request. While waiting for the response I overlay another view on top (mNoDataLayout) with a progress bar and other information telling the user the data is coming. Once the data arrives I want to fade out the overlay view to reveal the populated list view:
mNoDataLayout.animate().setDuration(300).alpha(0.f);
The problem is this animation doesn't always run. Sometimes is works, sometimes it doesn't.
The fix was to set the height of my overlay view mNoDataLayout to the screen height. Previously I had it set to match_parent which meant that when lots of list data arrived, the list view could be very large, which caused the overlay view to be very large.
Once I set my overlay view to be smaller, the alpha animation started working without any other changes.
Perhaps Android is silently killing alpha animations on very large views in order to optimise rendering fill rate. But since those pixels are offscreen anyway, this probably implies it's also not doing any scissoring / culling, which seems odd.
DisplayMetrics displayMetrics = getActivity().getResources().getDisplayMetrics();
ViewGroup.LayoutParams layoutParams = mNoDataLayout.getLayoutParams();
layoutParams.height = displayMetrics.heightPixels;
mNoDataLayout.setLayoutParams(layoutParams);
This was on a Samsung Galaxy Note 4.

Android Game development - Imageview automatically shrinks at screen edge

I have a bunch of dynamically created ImageViews representing different objects in a game, which is working fine. However if any Image reaches the edge of the screen, it shrinks. Looks like android is attempting to create a smooth transition, but this is not wanted.
I found another thread with the same issue here: Animation Drawable gets automatically shrinks at the corners ?, however his solution does not work for me, it only enhances the issue as it starts shrinking once the margin hits the screen edge.
This is my code:
final LayoutParams _updated_params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
_updated_params.setMargins((int)m_x, (int)m_y, 0, 0);
m_image.setLayoutParams(_updated_params);</code>
Where m_x/m_y is the absolute position of the image and m_image is an ImageView instance.
Does anyone know how I can turn off this automatic resizing?
Add setScaleType
m_image.setScaleType(ScaleType.MATRIX);
Use setScaleType
m_image.setScaleType(ScaleType.FIT_XY);

android pinch zoom scale view scrollbar moves

i have a view in linear layout. the app is music notation which is a series of musical bars which line wrap so they always less than width of screen (no horizontal scrolling). there is a vertical scrollbar when the music score gets too big for the view. so far so good. i can scroll up and down fine.
now i'm implementing pinch zoom, i set up an onScale in a ScaleGestureDetector, save the scale factor, invalidate and in onDraw i use the scale factor like this canvas.scale(mScaleFactor, mScaleFactor);
it scales the view ok except its not doing exactly what i want. i want the drawing area of the canvas to scale as it does but the scrollbar to stay in place, but zooming sends it off to the side, out of view.
any idea how to scale the view but not the scrollbar?
BTW, i can recalculate where to line wrap my music bars by applying the scalefactor to the width, its really just a problem with the scrollbar display.
can anyone help? thanks
I figured out the way. I needed to decouple the drawing of the scrollbar from the drawing of the main music notation view. that way I can zoom the main notation view without affecting the scroll bar.
so I use linear layout to create 2 views -
layout.setLayoutParams(new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT,
100));
layout.setOrientation(LinearLayout.HORIZONTAL);
Globals.mMainView = new MainView(context);
Globals.mMainView.setLayoutParams(new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT, 60));
layout.addView(Globals.mMainView);
Globals.mScrollbarView = new ScrollbarView(context);
Globals.mScrollbarView.setLayoutParams(new LinearLayout.LayoutParams(20, LinearLayout.LayoutParams.WRAP_CONTENT, 0));
layout.addView(Globals.mScrollbarView);
then I remove display of scrollbars from MainView and put them in ScrollbarView.
then I use onScroll events in ScrollbarView to control scrolling in MainView. I have to remember to return the actual display length of MainView from ScrollbarView.computeVerticalScrollRange so the scroll bar size shows up ok.
since I have reference to both views saved as globals, its easy for them to talk to each other as necessary.

Categories

Resources