Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android OpenGL: crazy aspect ratio after sleep

If I hit the power button on my android phone (or wait for it to time out) and the phone goes to sleep, after waking back up, the screen aspect ratio is all out of wack.

Screenshots:

broken

http://i.imgur.com/4C6ID.png

correct

http://i.imgur.com/CNAV0.png

in GameActivity.onCreate()

    // Grab display info
    DisplayMetrics dm = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(dm);
    ACTUAL_SCREEN_WIDTH = (int) dm.widthPixels;
    ACTUAL_SCREEN_HEIGHT = (int) dm.heightPixels;
    ACTUAL_DENSITY = dm.density;

    double scale = ((double) MainMenuActivity.resolutionScale / 100.0);
    SCREEN_WIDTH = (int) (ACTUAL_SCREEN_WIDTH * scale);
    SCREEN_HEIGHT = (int) (ACTUAL_SCREEN_HEIGHT * scale);
    DENSITY = ACTUAL_DENSITY * scale;

    // Setup graphics
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    surface_view = new GLSurfaceView(this);

    if (SCREEN_WIDTH != ACTUAL_SCREEN_WIDTH
            || SCREEN_HEIGHT != ACTUAL_SCREEN_HEIGHT)
        surface_view.getSurfaceHolder().setFixedSize(SCREEN_WIDTH,
                SCREEN_HEIGHT);

I am reloading everything correctly in GLSurfaceView (i.e. hitting home and going back to the game reloads the textures, etc).

I've printed out the orientation in onWindowFocusChanged, and it is landscape (as expected).

The problem does not appear if I do not use setFixedSize (i.e. if resolutionScale is 100). Also, the problem disappears if another window appears in front of the game (like the preferences window) and then you return the game.

Thanks in advance. I've been trying random things for about an hour since research dried up.

like image 643
coda Avatar asked Aug 25 '11 05:08

coda


2 Answers

I am working on this issue right now, and at this moment it appears to be an Android bug related to SurfaceHolder.setFixedSize().

What I do to get these logs is this: wait for game to load, push power, let screen go blank, push power again (quickly), unlock slide (quickly). This is on HTC Thunderbolt 2.3.4, by the way.

Here is the normal course of events (without using setFixedSize):

----- power button pushed ------
JavaMain: onPause: called, thread: 1
ActivityManager: Config changed: { scale=1.0 imsi=310/12 loc=en_US touch=3 keys=1/1/2 nav=1/1 orien=1 layout=34 uiMode=17 seq=1509 skin=default}
JavaMain: onConfigurationChanged, orientation: 1 thread: 1
JavaMain: mSView(old): 800x480
JavaMain: surfaceChanged: width: 480, height:800, thread: 1
JavaMain: onWindowFocusChanged: called, thread: 1
(screen is now off)
------ power button pushed, and slide-lock undone -----
JavaMain: onResume: called, thread: 1
ActivityManager: Config changed: { scale=1.0 imsi=310/12 loc=en_US touch=3 keys=1/1/2 nav=1/1 orien=2 layout=34 uiMode=17 seq=1510 skin=default}
JavaMain: onConfigurationChanged, orientation: 2 thread: 1
JavaMain: mSView(old): 480x800
JavaMain: onWindowFocusChanged: called, thread: 1
JavaMain: surfaceChanged: width: 800, height:480, thread: 1
(back in game)

Notice, that after onPause, my surface view is redone as portrait and after onResume it is changed back to landscape. I have screenOrientation set to landscape in the manifest.

Now look what happens during the same sequence but now SurfaceHolder.setFixedSize() is used (to reduce resolution):

----- power button pushed -------
JavaMain: onPause: called, thread: 1
ActivityManager: Config changed: { scale=1.0 imsi=310/12 loc=en_US touch=3 keys=1/1/2 nav=1/1 orien=1 layout=34 uiMode=17 seq=1513 skin=default}
JavaMain: onConfigurationChanged, orientation: 1 thread: 1
JavaMain: mSView(old): 800x480
JavaMain: surfaceChanged: width: 640, height:384, thread: 1
JavaMain: onWindowFocusChanged: called, thread: 1
(screen is now off)
------ power button pushed, and slide-lock undone -----
JavaMain: onResume: called, thread: 1
ActivityManager: Config changed: { scale=1.0 imsi=310/12 loc=en_US touch=3 keys=1/1/2 nav=1/1 orien=2 layout=34 uiMode=17 seq=1514 skin=default}
JavaMain: onConfigurationChanged, orientation: 2 thread: 1
JavaMain: mSView(old): 480x800
JavaMain: onWindowFocusChanged: called, thread: 1
(back in game, with a messed up screen as in OP)

Now notice that, after onPause, surfaceChanged reflects the fixed size that I had specified, however upon onResume the surface view is in portrait orientation (somewhat unexpected). But what is really missing, is the surfaceChanged call with my fixed size parameters. And before you ask, no doing .setFixedSize() in onConfigurationChanged() does not have any effect.

UPDATE AND SOLUTION:

Indeed, the solution came down to restoring (actually, never allowing any changes to) my surface view. This is accomplished by adding the following two lines after the super call in onConfigurationChanged for your activity. (Asumming you have the following manifest setting set).

android:configChanges="orientation"
android:screenOrientation="landscape"

This effectively prevents the surface view dimensions from ever being set to anything else (such as portrait). Which, incidentally, IS WHAT I WANTED WHEN I SPECIFIED screenOrientation=landscape !!! (I'm looking at you here, Google)

public void onConfigurationChanged(Configuration newConfig) {       
    super.onConfigurationChanged(newConfig);

    // -- stomp any attempts by the OS to resize my view.
    // -- Hardcoded values for illustration only. In real life
    // -- you'll need to save these when the surface view is originally created
    mSView.getLayoutParams().width = 800;
    mSView.getLayoutParams().height = 480;
}
like image 146
gadget Avatar answered Nov 14 '22 10:11

gadget


You need to call gl.glViewport(0, 0, width, height); or similar from the onSurfaceChanged method of your GL10.Renderer. My assumption is that when the device wakes from sleep, something must be altering the viewport, however the viewport is initialised for you when your app is first launched, which is why it works properly until you sleep.

like image 32
fabspro Avatar answered Nov 14 '22 10:11

fabspro