«

»

Jul 11

TouchWiz and the onOffsetChanged missing call

I am currently working on a Live Wallpaper project for a customer.

Interestingly, I found that though my app works perfectly on different devices – I have a Nexus7, Nexus10, a Galaxy Tab p1010, different chinese allWinner devices, and a Note II phone – my wallpaper can’t scroll when the screen is swiped on some Samsung Device.

Usually to detect the swiping on a Live Wallpaper, you use the WallpaperService.Engine.onOffsetChanged, i.e. overriding this method on your engine class.

Unfortunately, the Samsung launcher app, TouchWiz, seems to have a bug, or maybe it’s an undocumented/not compliant feature: the onOffsetChanged method is never reached, because simply they don’t call it (or maybe they don’t call the setWallpaperOffset, as explained in the Android Docs).

So you need to use some workaround for this.

Here’s mine: override the onTouchEvent method and simulate the scrolling.

The scroll will need a value for the offset, and it will be calculated from the swipe gesture; but unfortunately you’ll not be able to have the exact position of the screens, this means you’ll not detect if the screen “bounces back” as when you make a short swipe.

So your scrolling will be “desynchronized” with the screen. This could not be a problem, but you may prefer to use the correct method (onOffsetChanged) when available, and the “hack” when the o.s. doesn’t provide the call.

But you don’t have any way to know how the launcher app will behave, you need to start assuming that onOffsetChanged is NOT available and switch on standard method if it does.

This is how:

First, set a mScrollingWorking boolean as false. You’ll need to do this anytime the surface or view is created, because the use may change the launcher.

Then, whenever the onOffsetChanged is called, set it as “true”.

Then, override the onTouchEvent and if mScrollingWorking is false, simulate the scrolling.

This is my code:

 

      private boolean mScrollingWorking = false;
      private float tw_oldx, tw_fx, tw_sign;

      @Override
	public void onTouchEvent(MotionEvent event,
			GLWallpaperService.GLEngine engine) {
		if (!mScrollingWorking) {
			if (event.getPointerCount() < 1)
 				return;
                        float xinc = 0.0f;
 			float xstep = 0.333f;
 			float x;
 			switch(event.getAction()) {
 			case MotionEvent.ACTION_DOWN:
 				tw_fx = event.getX(0);
 				tw_oldx = tw_fx;
 				return;
 			case MotionEvent.ACTION_MOVE:
 				xinc = (event.getX(0) - tw_oldx) / (float)screen_width;
 				x = screen_x - xinc * xstep;
 				tw_oldx = event.getX(0);
 				break;
 			case MotionEvent.ACTION_UP:
 				tw_sign = Math.signum(event.getX(0) - tw_fx);
 				if (tw_sign > 0.0) {
					x = (float) (Math.floor(screen_x / xstep) * xstep);
				} else {
					x = (float) (Math.ceil(screen_x / xstep) * xstep);
				}
				break;
			default:
				return;
			}

				if (x < 0.0f)
 					x = 0.0f;
 				if (x > 1.0f)
					x = 1.0f;

			setOffset(x, 0.0f, xstep, 0.0f);
		}
	}
        public void onOffsetChanged(float x, float y, float xstep, float ystep, int xpo, int ypo) {
		mScrollingWorking = true;
		setOffset(x, y, xstep, ystep);
	}	

	private void setOffset(float x, float y, float xstep, float ystep) {
      // Here you can scroll the background
                screen_x = x;
        }

Note that the code on the ACTION_UP label will round the offset with the nearest page as it would do a working onOffsetChanged() call. But as said, you may have a situation where the launcher bounces back to the starting page and your code is scrolling on the next. Sorry: blame Samsung, not me 🙂

Remember that on newer version, you’ll need to use setOffsetNotificationsEnabled(true) to enable raw touch event delivery.

UPDATE:

The original code has two problems: first, as hybridtv noted, some variable was missing and needed some clarification.

While the role of tw_oldx and screen_width are trivial, screen_x need to be explained. It stores the older offset, and it is updated in the setOffset() function.

Second, there was a bug in the code. TouchWiz and our code need to be as synchronized as possible while moving, so when the finger is released from the screen (touch_up) we need to round the current screen. Also the offset need to be limited between 0.0 and 1.0.

Thanks to hybridtv for pointing out.

Permanent link to this article: http://www.studiofuga.com/2013/07/11/touchwiz-and-the-onoffsetchanged-missing-call/

6 comments

Skip to comment form

  1. hybridtv

    Thanks for sharing your code!
    I tried it but there are some undefined variables.
    I guess tw_oldx is a member field and screen_width is the width in pixel but what is screen_x ?

    1. happycactus

      You’re true, while posting what I believed it was the relevant code, I overlooked some variable.
      tw_oldx and tw_oldy are member variables used to store the older values.
      screen_width is the width in pixel.
      screen_x is indeed the old offset, it is updated on the setOffset() function. I’ll update the article with your notes. Thanks.

      1. floyd

        Thank you very much for sharing you source!

        screen_x and screen_width still seems to be missing, right?

        1. happycactus

          Yes, indeed. Read it as an exercise for the reader 🙂

          1. floyd

            I have another question:

            Is it right that you cannot know
            how many screens the user has, neither how wide they are nor on which
            screen the user currently is, right?

            So maybe “screen_x” is already
            1.0f, even if the user isn’t on the very right of his home screen, but
            you will never know… or did I miss something?

          2. happycactus

            Yes, indeed there may be situations where the background and the pages are moving in a “uncoordinated” manner. You may start with TouchWiz on the last page and the background on the first. So moving to the right will move the pages but not the background. You could avoid this if you can make the background “circular”.
            I think Samsung decided this approach to limit “moving backgrounds”. The TouchWiz pages are linked in a “ring”, you can move from the last to the first and back, and this is incompatible with the “onOffsetChanged” API.
            Hope this answer your doubt, please write me if you have any.

            Cheers

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

%d bloggers like this: