I have "solved" it with an ugly hack. This is not a solution but a
workaround until I find a better way:

    private GLSurfaceView mGLSurfaceView;
        private static boolean firstCreate = true;

        /*
         * Constructors
         */

        /*
         * Methods
         */
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Create our Preview view and set it as the content of our
        // Activity
        mGLSurfaceView = new GLSurfaceView(this);
        mGLSurfaceView.setRenderer(new ContactsRenderer(this));
        setContentView(mGLSurfaceView);

        if (firstCreate) {
                setRequestedOrientation
(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
                setRequestedOrientation
(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
                setRequestedOrientation
(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
                firstCreate = false;
        }
    }




On Apr 1, 4:10 pm, Ulrich Scheller <[email protected]> wrote:
> I have an Activity that was created based on the TriangleRenderer
> example. It works flawlessly as a standalone project, but when I use
> it as the tab of a tabhost there is a problem. At startup the whole
> activity is just black - I can get touch events and do everything else
> but it doesnt show anything. When I change the orientation (and
> therefore recreate the activity) it all works well.
>
> Maybe the problem comes from the View focus. My SurfaceView is not
> focused when created inside of the tabhost. I tried to fiddle around
> with the methods available in my onCreate() and onPostCreate(), but
> couldnt find a way to get the SurfaceView focused.
>
> The following sourcecode blocks in the guardedRun() method because
> needToWait() is true because !mHasFocus is true. If I exclude the !
> mHasFocus, it goes on but shows a black View anyways.
>
> Do you have any idea why it does work after orientation change, but
> not at the first startup?
>
> The Activity looks quite simple:
> =======================
>
>     @Override
>     protected void onCreate(Bundle savedInstanceState) {
>         super.onCreate(savedInstanceState);
>         // Create our Preview view and set it as the content of our
>         // Activity
>         mGLSurfaceView = new GLSurfaceView(this);
>         mGLSurfaceView.setRenderer(new ContactsRenderer(this));
>         setContentView(mGLSurfaceView);
>         System.out.println("focused: " + mGLSurfaceView.isFocused() +
> " focusable: " + mGLSurfaceView.isFocusable());
>     }
>
>     @Override
>     protected void onResume() {
>         // Ideally a game should implement onResume() and onPause()
>         // to take appropriate action when the activity looses focus
>         super.onResume();
>         mGLSurfaceView.onResume();
>     }
>
>     @Override
>     protected void onPause() {
>         // Ideally a game should implement onResume() and onPause()
>         // to take appropriate action when the activity looses focus
>         super.onPause();
>         mGLSurfaceView.onPause();
>     }
>
> Thats my SurfaceView Class:
> ======================
> /**
>  * An implementation of SurfaceView that uses the dedicated surface
> for
>  * displaying an OpenGL animation.  This allows the animation to run
> in a
>  * separate thread, without requiring that it be driven by the update
> mechanism
>  * of the view hierarchy.
>  *
>  * The application-specific rendering code is delegated to a
> GLView.Renderer
>  * instance.
>  */
> public class GLSurfaceView extends SurfaceView implements
> SurfaceHolder.Callback {
>     private float touch_x = 0;
>         private long touch_time = 0;
>         private int touch_selected = 0;
>         private Context contactScreen;
>
>         public GLSurfaceView(Context context) {
>         super(context);
>         this.contactScreen = context;
>         init();
>     }
>
>     public GLSurfaceView(Context context, AttributeSet attrs) {
>         super(context, attrs);
>         init();
>     }
>
>     private void init() {
>         setFocusable(true);
>         // Install a SurfaceHolder.Callback so we get notified when
> the
>         // underlying surface is created and destroyed
>         mHolder = getHolder();
>         mHolder.addCallback(this);
>         mHolder.setType(SurfaceHolder.SURFACE_TYPE_GPU);
>     }
>
>     public SurfaceHolder getSurfaceHolder() {
>         return mHolder;
>     }
>
>     public void setGLWrapper(GLWrapper glWrapper) {
>         mGLWrapper = glWrapper;
>     }
>
>     public void setRenderer(Renderer renderer) {
>         mGLThread = new GLThread(renderer);
>         mGLThread.start();
>     }
>
>     public void surfaceCreated(SurfaceHolder holder) {
>         mGLThread.surfaceCreated();
>     }
>
>     public void surfaceDestroyed(SurfaceHolder holder) {
>         // Surface will be destroyed when we return
>         mGLThread.surfaceDestroyed();
>     }
>
>     public void surfaceChanged(SurfaceHolder holder, int format, int
> w, int h) {
>         // Surface size or format has changed. This should not happen
> in this
>         // example.
>         mGLThread.onWindowResize(w, h);
>     }
>
>     /**
>      * Inform the view that the activity is paused.
>      */
>     public void onPause() {
>         mGLThread.onPause();
>     }
>
>     /**
>      * Inform the view that the activity is resumed.
>      */
>     public void onResume() {
>         mGLThread.onResume();
>     }
>
>     @Override
>     public boolean onTouchEvent(MotionEvent event) {
>         ContactsRenderer render = (ContactsRenderer) mGLThread.mRenderer;
>         if (event.getAction() == MotionEvent.ACTION_DOWN) {
>                 touch_x = event.getX();
>                 touch_time = System.currentTimeMillis();
>                 touch_selected = render.getSelectedContact();
>                 return true;
>         } else {
>                 float diff = touch_x - event.getX();
>                 long time_diff = System.currentTimeMillis() - touch_time;
>                 if (event.getAction() == MotionEvent.ACTION_MOVE){
>                         render.move(-diff/1000f);
>                         touch_x  = event.getX();
>                         return true;
>                 } else if (event.getAction() == MotionEvent.ACTION_UP) {
>                         if (time_diff < 170 && touch_selected ==
> render.getSelectedContact()) {
> //                              
> contactScreen.switchToProfile(render.getSelectedContact());
>                                 return true;
>                         } else {
>                                 render.moveToClosestContact();
>                         }
>                 }
>         }
>         return false;
>     }
>
>     /**
>      * Inform the view that the window focus has changed.
>      */
>     @Override public void onWindowFocusChanged(boolean hasFocus) {
>         super.onWindowFocusChanged(hasFocus);
>         mGLThread.onWindowFocusChanged(hasFocus);
>     }
>
>     /**
>      * Queue an "event" to be run on the GL rendering thread.
>      * @param r the runnable to be run on the GL rendering thread.
>      */
>     public void queueEvent(Runnable r) {
>         mGLThread.queueEvent(r);
>     }
>
>     @Override
>     protected void onDetachedFromWindow() {
>         super.onDetachedFromWindow();
>         mGLThread.requestExitAndWait();
>     }
>
>     //
> ----------------------------------------------------------------------
>
>     public interface GLWrapper {
>       GL wrap(GL gl);
>     }
>
>     //
> ----------------------------------------------------------------------
>
>     /**
>      * A generic renderer interface.
>      */
>     public interface Renderer {
>         /**
>          * @return the EGL configuration specification desired by the
> renderer.
>          */
>         int[] getConfigSpec();
>
>         /**
>          * Surface created.
>          * Called when the surface is created. Called when the
> application
>          * starts, and whenever the GPU is reinitialized. This will
>          * typically happen when the device awakes after going to
> sleep.
>          * Set your textures here.
>          */
>         void surfaceCreated(GL10 gl);
>         /**
>          * Surface changed size.
>          * Called after the surface is created and whenever
>          * the OpenGL ES surface size changes. Set your viewport here.
>          * @param gl
>          * @param width
>          * @param height
>          */
>         void sizeChanged(GL10 gl, int width, int height);
>         /**
>          * Draw the current frame.
>          * @param gl
>          */
>         void drawFrame(GL10 gl);
>     }
>
>     /**
>      * An EGL helper class.
>      */
>
>     private class EglHelper {
>         public EglHelper() {
>
>         }
>
>         /**
>          * Initialize EGL for a given configuration spec.
>          * @param configSpec
>          */
>         public void start(int[] configSpec){
>             /*
>              * Get an EGL instance
>              */
>             mEgl = (EGL10) EGLContext.getEGL();
>
>             /*
>              * Get to the default display.
>              */
>             mEglDisplay = mEgl.eglGetDisplay
> (EGL10.EGL_DEFAULT_DISPLAY);
>
>             /*
>              * We can now initialize EGL for that display
>              */
>             int[] version = new int[2];
>             mEgl.eglInitialize(mEglDisplay, version);
>
>             EGLConfig[] configs = new EGLConfig[1];
>             int[] num_config = new int[1];
>             mEgl.eglChooseConfig(mEglDisplay, configSpec, configs, 1,
>                     num_config);
>             mEglConfig = configs[0];
>
>             /*
>             * Create an OpenGL ES context. This must be done only
> once, an
>             * OpenGL context is a somewhat heavy object.
>             */
>             mEglContext = mEgl.eglCreateContext(mEglDisplay,
> mEglConfig,
>                     EGL10.EGL_NO_CONTEXT, null);
>
>             mEglSurface = null;
>         }
>
>         /*
>          * Create and return an OpenGL surface
>          */
>         public GL createSurface(SurfaceHolder holder) {
>             /*
>              *  The window size has changed, so we need to create a
> new
>              *  surface.
>              */
>             if (mEglSurface != null) {
>
>                 /*
>                  * Unbind and destroy the old EGL surface, if
>                  * there is one.
>                  */
>                 mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
>                         EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
>                 mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
>             }
>
>             /*
>              * Create an EGL surface we can render into.
>              */
>             mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay,
>                     mEglConfig, holder, null);
>
>             /*
>              * Before we can issue GL commands, we need to make sure
>              * the context is current and bound to a surface.
>              */
>             mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
>                     mEglContext);
>
>             GL gl = mEglContext.getGL();
>             if (mGLWrapper != null) {
>                 gl = mGLWrapper.wrap(gl);
>             }
>             return gl;
>         }
>
>         /**
>          * Display the current render surface.
>          * @return false if the context has been lost.
>          */
>         public boolean swap() {
>             mEgl.eglSwapBuffers(mEglDisplay, mEglSurface);
>
>             /*
>              * Always check for EGL_CONTEXT_LOST, which means the
> context
>              * and all associated data were lost (For instance because
>              * the device went to sleep). We need to sleep until we
>              * get a new surface.
>              */
>             return mEgl.eglGetError() != EGL11.EGL_CONTEXT_LOST;
>         }
>
>         public void finish() {
>             if (mEglSurface != null) {
>                 mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
>                         EGL10.EGL_NO_SURFACE,
>                         EGL10.EGL_NO_CONTEXT);
>                 mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
>                 mEglSurface = null;
>             }
>             if (mEglContext != null) {
>                 mEgl.eglDestroyContext(mEglDisplay, mEglContext);
>                 mEglContext = null;
>             }
>             if (mEglDisplay != null) {
>                 mEgl.eglTerminate(mEglDisplay);
>                 mEglDisplay = null;
>             }
>         }
>
>         EGL10 mEgl;
>         EGLDisplay mEglDisplay;
>         EGLSurface mEglSurface;
>         EGLConfig mEglConfig;
>         EGLContext mEglContext;
>     }
>
>     /**
>      * A generic GL Thread. Takes care of initializing EGL and GL.
> Delegates
>      * to a Renderer instance to do the actual drawing.
>      *
>      */
>
>     class GLThread extends Thread {
>         GLThread(Renderer renderer) {
>             super();
>             mDone = false;
>             mWidth = 0;
>             mHeight = 0;
>             mRenderer = renderer;
>             setName("GLThread");
>         }
>
>         @Override
>         public void run() {
>             /*
>              * When the android framework launches a second instance
> of
>              * an activity, the new instance's onCreate() method may
> be
>              * called before the first instance returns from onDestroy
> ().
>              *
>              * This semaphore ensures that only one instance at a time
>              * accesses EGL.
>              */
>             try {
>                 try {
>                 sEglSemaphore.acquire();
>                 } catch (InterruptedException e) {
>                     return;
>                 }
>                 guardedRun();
>             } catch (InterruptedException e) {
>                 // fall thru and exit normally
>             } finally {
>                 sEglSemaphore.release();
>             }
>         }
>
>         private void guardedRun() throws InterruptedException {
>             mEglHelper = new EglHelper();
>             /*
>              * Specify a configuration for our opengl session
>              * and grab the first configuration that matches is
>              */
>             int[] configSpec = mRenderer.getConfigSpec();
>             mEglHelper.start(configSpec);
>
>             GL10 gl = null;
>             boolean tellRendererSurfaceCreated = true;
>             boolean tellRendererSurfaceChanged = true;
>
>             /*
>              * This is our main activity thread's loop, we go until
>              * asked to quit.
>              */
>             while (!mDone) {
>
>                 /*
>                  *  Update the asynchronous state (window size)
>                  */
>                 int w, h;
>                 boolean changed;
>                 boolean needStart = false;
>                 synchronized (this) {
>                     Runnable r;
>                     while ((r = getEvent()) != null) {
>                         r.run();
>                     }
>                     if (mPaused) {
>                         mEglHelper.finish();
>                         needStart = true;
>                     }
>                     if(needToWait()) {
>                         while (needToWait()) {
> // this wait() is called because the surface is not focused
>                             wait();
>                         }
>                     }
>                     if (mDone) {
>                         break;
>                     }
>                     changed = mSizeChanged;
>                     w = mWidth;
>                     h = mHeight;
>                     mSizeChanged = false;
>                 }
>                 if (needStart) {
>                     mEglHelper.start(configSpec);
>                     tellRendererSurfaceCreated = true;
>                     changed = true;
>                 }
>                 if (changed) {
>                     gl = (GL10) mEglHelper.createSurface(mHolder);
>                     tellRendererSurfaceChanged = true;
>                 }
>                 if (tellRendererSurfaceCreated) {
>                     mRenderer.surfaceCreated(gl);
>                     tellRendererSurfaceCreated = false;
>                 }
>                 if (tellRendererSurfaceChanged) {
>                     mRenderer.sizeChanged(gl, w, h);
>                     tellRendererSurfaceChanged = false;
>                 }
>                 if ((w > 0) && (h > 0)) {
>                     /* draw a frame here */
>                     mRenderer.drawFrame(gl);
>
>                     /*
>                      * Once we're done with GL, we need to call
> swapBuffers()
>                      * to instruct the system to display the rendered
> frame
>                      */
>                     mEglHelper.swap();
>                 }
>              }
>
>             /*
>              * clean-up everything...
>              */
>             mEglHelper.finish();
>         }
>
>         private boolean needToWait() {
>             return (mPaused || (! mHasFocus) || (! mHasSurface) ||
> mContextLost)
>                 && (! mDone);
>         }
>
>         public void surfaceCreated() {
>             synchronized(this) {
>                 mHasSurface = true;
>                 mContextLost = false;
>                 notify();
>             }
>         }
>
>         public void surfaceDestroyed() {
>             synchronized(this) {
>                 mHasSurface = false;
>                 notify();
>             }
>         }
>
>         public void onPause() {
>             synchronized (this) {
>                 mPaused = true;
>             }
>         }
>
>         public void onResume() {
>             synchronized (this) {
>                 mPaused = false;
>                 notify();
>             }
>         }
>
>         public void onWindowFocusChanged(boolean hasFocus) {
>             synchronized (this) {
>                 mHasFocus = hasFocus;
>                 if (mHasFocus == true) {
>                     notify();
>                 }
>             }
>         }
>         public void onWindowResize(int w, int h) {
>             synchronized (this) {
>                 mWidth = w;
>                 mHeight = h;
>                 mSizeChanged = true;
>             }
>         }
>
>         public void requestExitAndWait() {
>             // don't call this from GLThread thread or it is a
> guaranteed
>             // deadlock!
>             synchronized(this) {
>                 mDone = true;
>                 notify();
>             }
>             try {
>                 join();
>             } catch (InterruptedException ex) {
>                 Thread.currentThread().interrupt();
>             }
>         }
>
>         /**
>          * Queue an "event" to be run on the GL rendering thread.
>          * @param r the runnable to be run on the GL rendering thread.
>          */
>         public void queueEvent(Runnable r) {
>             synchronized(this) {
>                 mEventQueue.add(r);
>             }
>         }
>
>         private Runnable getEvent() {
>             synchronized(this) {
>                 if (mEventQueue.size() > 0) {
>                     return mEventQueue.remove(0);
>                 }
>
>             }
>             return null;
>         }
>
>         private boolean mDone;
>         private boolean mPaused;
>         private boolean mHasFocus;
>         private boolean mHasSurface;
>         private boolean mContextLost;
>         private int mWidth;
>         private int mHeight;
>         private Renderer mRenderer;
>         private ArrayList<Runnable> mEventQueue = new
> ArrayList<Runnable>();
>         private EglHelper mEglHelper;
>     }
>
>     private static final Semaphore sEglSemaphore = new Semaphore(1);
>     private boolean mSizeChanged = true;
>
>     private SurfaceHolder mHolder;
>     private GLThread mGLThread;
>     private GLWrapper mGLWrapper;
>
> }
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google
Groups "Android Developers" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/android-developers?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to