Reputation: 21
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
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
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