简体   繁体   中英

Android custom SurfaceView orientation can't rotate from portrait to landscape

I'm a new android application engineer. I'm trying to make a vulkan rendering backend demo which use SurfaceView as a View on android Java code. I made the gles rendering backend demo using GLSurfaceView as well. On application code, I use setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) API set activity from default portrait to landscape. But it doesn't work on SurfaceView while it works on GLSurfaceView.

I use renderdoc capture the rendering result, the image is in landscape layout(the same layout as gles backend). I doubt it was's something wrong with some settings on activity or window, but can't figure it out the root cause. Could somebody help what maybe the problem is?

Here is the Java source code.

package com.example.graphicsdebugger;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.view.GestureDetector;
import android.view.MotionEvent;

//////////////////////////////////////////////Jerome///////////////////////////////////////////////
import android.view.SurfaceHolder;
import android.view.View;
import android.view.WindowManager;
import android.util.Log;
import android.widget.CheckBox;
import android.widget.SeekBar;
import android.widget.TextView;

///////////////////////////////////////////////////////////////////////////////////////////////////

/**
 * An example full-screen activity that shows and hides the system UI (i.e.
 * status bar and navigation/system bar) with user interaction.
 */
public class DemoFullscreenActivity extends AppCompatActivity /*implements Serializable */{
    //////////////////////////////////////////////Jerome///////////////////////////////////////////
    private static final String TAG = "9527";
    private static final int UNKNOWN_RENDERER = -1;
    private static final int FORWARD_RENDERER = 0;
    private static final int DEFERRED_RENDERER = 1;

    private static final int SET_UNKNOWN = -1;
    private static final int SET_MODEL = 0;
    private static final int SET_SSAO = 1;
    private static final int SET_SSSSS = 2;
    private static final int SET_SSAO_RADIUS = 3;
    private static final int SET_SSAO_BIAS = 4;
    private static final int SET_SSAO_COEFFICIENT = 5;
    private static final int SET_SSAO_KERNEL_SIZE = 6;
    private static final int SET_BACKEND = 7;

    private boolean mBackend = false;
    private GLSurfaceView mGLSurfaceView;
    private VKSurfaceView mVKSurfaceView;
    protected static final float FLIP_DISTANCE = 50;
    GestureDetector mDetector;
    DemoRenderer mRender;
    ///////////////////////////////////////////////////////////////////////////////////////////////
    private void setSSAORadiusSeekBar() {
        SeekBar seekBar = (SeekBar) findViewById(R.id.seekBarRadius);
        // set default value
        seekBar.setProgress(5);
        TextView textView = (TextView) findViewById(R.id.textRadius);
        seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                textView.setText("Radius:" + Integer.toString(progress));
                mRender.SetInt(SET_SSAO_RADIUS, progress);
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {}
            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {}
        });
    }

    private void setSSAOBiasSeekBar() {
        SeekBar seekBar = (SeekBar) findViewById(R.id.seekBarBias);
        // set default value
        seekBar.setProgress(5);
        TextView textView = (TextView) findViewById(R.id.textBias);
        seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                textView.setText("Bias:" + Integer.toString(progress));
                mRender.SetInt(SET_SSAO_BIAS, progress);
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {}
            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {}
        });
    }

    private void setSSAOCoefficientSeekBar() {
        SeekBar seekBar = (SeekBar) findViewById(R.id.seekBarCoefficient);
        // set default value
        seekBar.setProgress(150);
        TextView textView = (TextView) findViewById(R.id.textCoefficient);
        seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                textView.setText("Coefficient:" + Integer.toString(progress));
                mRender.SetInt(SET_SSAO_COEFFICIENT, progress);
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {}
            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {}
        });
    }

    private void setSSAOKernelSizeSeekBar() {
        SeekBar seekBar = (SeekBar) findViewById(R.id.seekBarKernelSize);
        // set default value
        seekBar.setProgress(2);
        TextView textView = (TextView) findViewById(R.id.textKernelSize);
        seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                textView.setText("Kernel Size:" + Integer.toString(progress * 8));
                mRender.SetInt(SET_SSAO_KERNEL_SIZE, progress);
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {}
            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {}
        });
    }

    private void setSSAOCheckBox() {
        CheckBox ssao = (CheckBox) findViewById(R.id.ssao_check_box);
        ssao.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                boolean checked = ((CheckBox)v).isChecked();
                mRender.SetSSAO(checked);
            }
        });
    }

    private void setSSSSSCheckBox() {
        CheckBox sssss = (CheckBox) findViewById(R.id.sssss_check_box);
        sssss.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                boolean checked = ((CheckBox)v).isChecked();
                mRender.SetSSSSS(checked);
            }
        });
    }

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

        //////////////////////////////////////////////Jerome///////////////////////////////////////
        // 设置横屏
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        // 隐藏导航栏
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
        // 隐藏应用标题栏
        getSupportActionBar().hide();

        setSSAOCheckBox();
        setSSSSSCheckBox();
        setSSAORadiusSeekBar();
        setSSAOBiasSeekBar();
        setSSAOCoefficientSeekBar();
        setSSAOKernelSizeSeekBar();
        rendererDraw();
        ///////////////////////////////////////////////////////////////////////////////////////////
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        setIntent(intent);
    }

    //////////////////////////////////////////////Jerome///////////////////////////////////////////
    private void rendererDraw() {

        Bundle bundle = getIntent().getExtras();
        if (bundle == null) return;

        if (bundle.containsKey("Backend")) {
            mBackend = bundle.getBoolean("Backend");
        }

        if (mBackend) { // Vulkan
            Log.d("9527", "init VKSurfaceView");
            mVKSurfaceView = (VKSurfaceView)findViewById(R.id.vk_surface_view);
            SurfaceHolder holder = mVKSurfaceView.getHolder();
            mRender = new DemoRenderer(this, holder.getSurface());
            mVKSurfaceView.setRenderer(mRender);
        } else { // GLES
            Log.d("9527", "init GLSurfaceView");
            mGLSurfaceView = (GLSurfaceView)findViewById(R.id.gl_surface_view);
            mGLSurfaceView.setEGLContextClientVersion(2);
            SurfaceHolder holder = mGLSurfaceView.getHolder();
            mRender = new DemoRenderer(this, holder.getSurface());
            mGLSurfaceView.setRenderer(mRender);
            mGLSurfaceView.getAlpha();
        }

        mRender.SetInt(SET_SSAO_RADIUS, 5);
        mRender.SetInt(SET_SSAO_BIAS, 5);
        mRender.SetInt(SET_SSAO_COEFFICIENT, 150);
        mRender.SetInt(SET_SSAO_KERNEL_SIZE, 2);

        int renderer = UNKNOWN_RENDERER;
        if (bundle.containsKey("Renderer")) {
            renderer = bundle.getInt("Renderer");
            mRender.SetRenderer(renderer);
        }

        if (bundle.containsKey("Backend")) {
            mRender.SetInt(SET_BACKEND, mBackend ? 1 : 0);
        }

        if (renderer != DEFERRED_RENDERER) {
            CheckBox ssao = (CheckBox) findViewById(R.id.ssao_check_box);
            ssao.setEnabled(false);
        } else if (bundle.containsKey("SSAO")) {
            boolean isChecked = bundle.getBoolean("SSAO");
            mRender.SetSSAO(isChecked);
            CheckBox ssao = (CheckBox) findViewById(R.id.ssao_check_box);
            ssao.setChecked(isChecked);
        }

        if (renderer != DEFERRED_RENDERER) {
            CheckBox sssss = (CheckBox) findViewById(R.id.sssss_check_box);
            sssss.setEnabled(false);
        } else if (bundle.containsKey("SSSSS")) {
            mRender.SetSSSSS(bundle.getBoolean("SSSSS"));
        }
        if (bundle.containsKey("Model")) {
            mRender.SetModel(bundle.getInt("Model"));
        }

        mDetector = new GestureDetector(this, new GestureDetector.OnGestureListener() {

            @Override
            public boolean onSingleTapUp(MotionEvent e) {
                // TODO Auto-generated method stub
                return false;
            }

            @Override
            public void onShowPress(MotionEvent e) {
                // TODO Auto-generated method stub
            }

            @Override
            public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
                // TODO Auto-generated method stub
                return false;
            }

            @Override
            public void onLongPress(MotionEvent e) {
                // TODO Auto-generated method stub
            }

            /**
             *
             * e1 The first down motion event that started the fling. e2 The
             * move motion event that triggered the current onFling.
             */
            @Override
            public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
                if (e1.getX() - e2.getX() > FLIP_DISTANCE) {
                    Log.d(TAG, "Slide left...");
                    return true;
                }
                if (e2.getX() - e1.getX() > FLIP_DISTANCE) {
                    Log.d(TAG, "Slide right...");
                    return true;
                }
                if (e1.getY() - e2.getY() > FLIP_DISTANCE) {
                    Log.d(TAG, "Slide up...");
                    return true;
                }
                if (e2.getY() - e1.getY() > FLIP_DISTANCE) {
                    Log.d(TAG, "Slide down...");
                    return true;
                }

                Log.d(TAG, e2.getX() + " " + e2.getY());

                return false;
            }

            @Override
            public boolean onDown(MotionEvent e) {
                // TODO Auto-generated method stub
                return false;
            }
        });
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        //Log.d(TAG, "===> MainActivity call dispatchTouchEvent()");
        //Log.d(TAG, "===> super.dispatchTouchEvent() default return true");
        //Log.d(TAG, "--------------------------------------------------");
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public void onUserInteraction() {
        //Log.d(TAG, "===> MainActivity call onUserInteraction()");
        //Log.d(TAG, "--------------------------------------------------");
        super.onUserInteraction();
    }

    float Finger_0_DownX = 0;
    float Finger_0_DownY = 0;
    float Finger_1_DownX = 0;
    float Finger_1_DownY = 0;
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                int mActivePointerId =0;
                int idx = event.findPointerIndex(mActivePointerId);
                if (idx >=0 ) {
                    Finger_0_DownX = event.getX(idx);
                    Finger_0_DownY = event.getY(idx);
                    mRender.setFingerDown(0, Finger_0_DownX, Finger_0_DownY);
                }
                break;
            case MotionEvent.ACTION_UP:
                Finger_0_DownX = 0.0f;
                Finger_0_DownY = 0.0f;
                mRender.setFingerUp(0);
                break;
            default:
                break;
        }

        switch(event.getActionMasked()) {
            case MotionEvent.ACTION_POINTER_DOWN:
                int mActivePointerId = 1;
                int idx = event.findPointerIndex(mActivePointerId);
                if (idx >=0 ) {
                    Finger_1_DownX = event.getX(idx);
                    Finger_1_DownY = event.getY(idx);
                    mRender.setFingerDown(1, Finger_1_DownX, Finger_1_DownY);
                }
                break;
            case MotionEvent.ACTION_POINTER_UP:
                Finger_1_DownX = 0.0f;
                Finger_1_DownY = 0.0f;
                mRender.setFingerUp(1);
                break;
            default:
                break;
        }

        if (Finger_0_DownX != 0.0f && Finger_0_DownY != 0.0f) {
            int mActivePointerId =0;
            int idx = event.findPointerIndex(mActivePointerId);
            if (idx >=0 ) {
                mRender.setFingerPosition(0, event.getX(idx), event.getY(idx));
            }
        }

        if (Finger_1_DownX != 0.0f && Finger_1_DownY != 0.0f) {
            int mActivePointerId = 1;
            int idx = event.findPointerIndex(mActivePointerId);
            if (idx >=0 ) {
                mRender.setFingerPosition(1, event.getX(idx), event.getY(idx));
            }
        }
        return mDetector.onTouchEvent(event);
    }
    ///////////////////////////////////////////////////////////////////////////////////////////////
}

Here is the activity layout.

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/frameLayout3"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="?attr/fullscreenBackgroundColor"
    android:theme="@style/ThemeOverlay.GraphicsDebugger.FullscreenContainer"
    tools:context=".DemoFullscreenActivity">

    <android.opengl.GLSurfaceView
        android:id="@+id/gl_surface_view"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.0" />

    <com.example.graphicsdebugger.VKSurfaceView
        android:id="@+id/vk_surface_view"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.0" />

    <CheckBox
        android:id="@+id/ssao_check_box"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="24dp"
        android:text="SSAO"
        app:layout_constraintBottom_toTopOf="@+id/sssss_check_box"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.019"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.728" />

    <CheckBox
        android:id="@+id/sssss_check_box"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="272dp"
        android:text="SSSSS"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.019"
        app:layout_constraintStart_toStartOf="parent" />

    <TextView
        android:id="@+id/textRadius"
        android:layout_width="72dp"
        android:layout_height="35dp"
        android:text="Radius:5"
        app:layout_constraintBottom_toBottomOf="@+id/gl_surface_view"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.175"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.101" />

    <TextView
        android:id="@+id/textCoefficient"
        android:layout_width="111dp"
        android:layout_height="35dp"
        android:text="Coefficient:150"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.419"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.101" />

    <TextView
        android:id="@+id/textBias"
        android:layout_width="72dp"
        android:layout_height="35dp"
        android:text="Bias:5"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.68"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.101" />

    <TextView
        android:id="@+id/textKernelSize"
        android:layout_width="111dp"
        android:layout_height="35dp"
        android:text="Kernel Size:16"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.925"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.101" />

    <SeekBar
        android:id="@+id/seekBarKernelSize"
        android:layout_width="146dp"
        android:layout_height="28dp"
        android:max="8"
        android:min="1"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.935"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.043" />

    <SeekBar
        android:id="@+id/seekBarCoefficient"
        android:layout_width="146dp"
        android:layout_height="28dp"
        android:max="300"
        android:min="100"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.408"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.041" />

    <SeekBar
        android:id="@+id/seekBarRadius"
        android:layout_width="146dp"
        android:layout_height="28dp"
        android:max="100"
        android:min="0"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="@+id/gl_surface_view"
        app:layout_constraintHorizontal_bias="0.141"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.04" />

    <SeekBar
        android:id="@+id/seekBarBias"
        android:layout_width="146dp"
        android:layout_height="28dp"
        android:max="30"
        android:min="0"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="@+id/gl_surface_view"
        app:layout_constraintHorizontal_bias="0.675"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.041" />

</androidx.constraintlayout.widget.ConstraintLayout>

Here is the AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.graphicsdebugger">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.GraphicsDebugger">
        <activity android:name=".RendererSettingsActivity"></activity>
        <activity
            android:name=".DemoFullscreenActivity"
            android:configChanges="orientation|keyboardHidden|screenSize"
            android:label="@string/title_activity_demo_fullscreen"
            android:theme="@style/Theme.GraphicsDebugger.Fullscreen"
            android:launchMode="singleInstance"/>
        <activity android:name=".RenderingEngineActivity" />
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

In the tag of AndroidManifest.xml, add the line android:screenOrientation="portrait"

Thanks

Refer to https://www.geeksforgeeks.org/designing-the-landscape-and-portrait-mode-of-application-in-android/ add landscape layout. The layout file will be at res/layout-land/ directory. The layout xml file is the same name as the file in res/layout directory. This file name will be used in setContentView(R.layout.activity_layout_name). The chozen of landsacpe/portrait layout for the activity is set in AndroidManifest.xml parameter android:screenOrientation="value" as experimented while the value either landscape or portrait. When we choose portrait mode in AndroidManifest.xml, the corresponding activity will find the layout file in res/layout directory and setContentView. When choose landscape, it will find layout file in res/layout-land directory. That's why both in res/layout and res/layout-land directories, the layout file name should be the same, because we call the setContentView API in activity, the parameter should be both fit for file in res/layout and res/layout-land directories.

I need set my activity in landscape layout, so here in AndroidManifest.xml corresponding activity, I set android:screenOrientation="landscape".

Then Activity code will setContentView use the layout file in res/layout-land directory. In landscape layout xml file, I had two Views, one is GLSurfaceView and the other is VKSurfaceView.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM