chai
chai

Reputation: 21

How to change the size of a window's surface?

So I know that a SurfaceView's surface size can be changed by calling setFixedSize() on the SurfaceHolder, but when I try to do the same thing on an arbitrary window, one obtained from an activity, I cannot. Here's the relevant test code:

public class TestActivity extends Activity implements Callback2 {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        getWindow().takeSurface(this);
    }

    @Override
    public void surfaceCreated(SurfaceHolder arg0) {
        // TODO Auto-generated method stub
        arg0.setFixedSize(300, 300);
    }
}

This results in the following error log:

01-15 23:21:46.111: E/AndroidRuntime(9748): FATAL EXCEPTION: main

01-15 23:21:46.111: E/AndroidRuntime(9748): Process: com.example.windowtest, PID: 9748

01-15 23:21:46.111: E/AndroidRuntime(9748): java.lang.UnsupportedOperationException: Currently only support sizing from layout

01-15 23:21:46.111: E/AndroidRuntime(9748): at android.view.ViewRootImpl$TakenSurfaceHolder.setFixedSize(ViewRootImpl.java:6094)

Where by layout I suppose it means WindowManager.LayoutParams which would resize the Window's dimension as well. So is there no way to change the size of a Window's Surface without changing the Window's dimensions? I would think there is, since we can do it with SurfaceView, but I'm not sure how.

Edit: In addition, the SurfaceView setFixedSize() call results in a requestLayout(), which propagates up to an object that implements the ViewParent interface. What is this ViewParent object that is getting attached to the SurfaceView at runtime? Maybe then the logic behind how the surface buffer is getting resized will be clear.

Upvotes: 2

Views: 1583

Answers (2)

Vlad Alex
Vlad Alex

Reputation: 178

This is actually possible using NDK's ANativeWindow_setBuffersGeometry:

JNIEXPORT void JNICALL Java_com_organization_app_TestActivity_setBufferGeometry(JNIEnv *env, jobject thiz, jobject surface, jint width, jint height)
{
    __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, "setBufferGeometry(): %p %dx%d", surface, width, height);
    ANativeWindow* window = ANativeWindow_fromSurface(env, surface);
    __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, "setBufferGeometry(): window: %p", window);
    ANativeWindow_setBuffersGeometry(window, width, height, AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM);
}

Java Code:

private static native void setBufferGeometry(Surface surface, int width , int height );

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
{
    Log.d( TAG, "surfaceChanged()...");
    setBufferGeometry(holder.getSurface(), 768, 1366);
    /* ... */

From the ANativeWindow_setBuffersGeometry docs:

Change the format and size of the window buffers.

The width and height control the number of pixels in the buffers, not the dimensions of the window on screen. If these are different than the window's physical size, then its buffer will be scaled to match that size when compositing it to the screen.

Upvotes: 2

fadden
fadden

Reputation: 52323

All of the View-based UI is on a single layer (a/k/a window). You can't change the surface scaling for a single View; that wouldn't make sense. You'd have to change the setup for the entire View composition surface, and the framework doesn't want to let you do that.

The SurfaceView's surface is on a separate layer, composited independently, so you have much more freedom to alter its dimensions.

See also: Android System-Level Graphics.

Upvotes: 0

Related Questions