Search code examples
androidandroid-canvassurfaceview

Surface View will not display content


We are trying to learn how to use dynamic animation and this code is from Github Code We have tried many changes but the code just displays nothing. We will post the three Class's and no XML file is included in the link

My question is can anyone see what is missing or perhaps wrong with the code. YES We have included this in the build.gradle

implementation "com.android.support:support-dynamic-animation:26.1.0"

Here is the Main Activity

import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

import static android.view.View.SYSTEM_UI_FLAG_FULLSCREEN;

/**
* This app demonstrates how to use a SurfaceView to render an image from a
* separate thread.
* In addition, it shows how you can use clipping for animation,
* and implements a basic game loop. This is not intended as a production
* quality app. Rather, it demonstrates the basics
* of these techniques, so you can dive deeper on your own.
*
* Note that SurfaceView offers trade-offs you must consider:
*
* * Offers a lover level drawing surface with more control without the need
* for learning OpenGL or the NDK.
*     * You can draw on it same as a canvas.
*     * Draw from a separate thread, not the UI thread.
*     * Does not have built-in hardware acceleration, e.g. for 
 transformations.
*  Monitor performance carefully, especially if you are doing animations.
*
* Game play:
*
* The user is presented with a dark surface with a white circle.
* This represents a wall shone at with a flashlight cone. Touching the
* surface hides an android image. The light cone then follows continuous
* motion. If the image of an android is discovered, the screen lights up and
* the word "WIN!" appears. To restart lift finger and touch screen again.
*
* The following limitations are imposed to keep the code focused.
*
*     * No startup screen or any other functionality other than game play.
*     * No saving of state, game, or user data.
*     * No acrobatics to handle edge cases.
*/

public class MainActivity extends AppCompatActivity {

private GameView mGameView;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Lock orientation into landscape.
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

    // Create a GameView and bind it to this activity.
    // You don't need a ViewGroup to fill the screen, because the system
    // has a FrameLayout to which this will be added.
    mGameView = new GameView(this);
    // Android 4.1 and higher simple way to request fullscreen.
    mGameView.setSystemUiVisibility(SYSTEM_UI_FLAG_FULLSCREEN);
    setContentView(mGameView);
    }

   /**
   * Pauses game when activity is paused.
   */
   @Override
  protected void onPause() {
    super.onPause();
    mGameView.pause();
  }

 /**
  * Resumes game when activity is resumed.
  */
 @Override
 protected void onResume() {
    super.onResume();
    mGameView.resume();
  }

And the FlashlightCone Class

/**
* Cone of flashlight that the user moves around the view.

*/

public class FlashlightCone {

private int mX;
private int mY;
private int mRadius;

public FlashlightCone(int viewWidth, int viewHeight) {
    mX = viewWidth / 2;
    mY = viewHeight / 2;
    // Adjust the radius for the narrowest view dimension.
    mRadius = ((viewWidth <= viewHeight) ? mX / 3 : mY / 3);
 }

/**
 * Update the coordinates of the flashlight cone.
 *
 * @param newX Changed value for x coordinate.
 * @param newY Changed value for y coordinate.
 */
 public void update(int newX, int newY) {
    mX = newX;
    mY = newY;
 }

public int getX() {
    return mX;
}

public int getY() {
    return mY;
}

public int getRadius() {
    return mRadius;
}

And the GameView

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.Region;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

/**
* This class demonstrates the following interactive game basics:
*
*   * Manages a rendering thread that draws to a SurfaceView.
*   * Basic game loop that sleeps to conserve resources.
*   * Processes user input to update game state.
*   * Uses clipping as a means of animation.
*
* Note that these are basic versions of these techniques.
* Non-fatal edge cases are not handled.
* Error handling is minimal. No logging. App assumes and uses a single 
 thread.
* Additional thread management would otherwise be necessary. See code 
 comments.
*/

public class GameView extends SurfaceView implements Runnable {

private boolean mRunning;
private Thread mGameThread = null;
private Path mPath;

private Context mContext;

private FlashlightCone mFlashlightCone;

private Paint mPaint;
private Bitmap mBitmap;
private RectF mWinnerRect;
private int mBitmapX;
private int mBitmapY;
private int mViewWidth;
private int mViewHeight;
private SurfaceHolder mSurfaceHolder;

public GameView(Context context) {
    this(context, null);
}

public GameView(Context context, AttributeSet attrs) {
    super(context, attrs);
    mContext = context;
    mSurfaceHolder = getHolder();
    mPaint = new Paint();
    mPaint.setColor(Color.DKGRAY);
    mPath = new Path();
}

 /**
  * We cannot get the correct dimensions of views in onCreate because
  * they have not been inflated yet. This method is called every time the
  * size of a view changes, including the first time after it has been
  * inflated.
  *
  * @param w Current width of view.
  * @param h Current height of view.
  * @param oldw Previous width of view.
  * @param oldh Previous height of view.
  */
  @Override
  protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);

    mViewWidth = w;
    mViewHeight = h;

    mFlashlightCone = new FlashlightCone(mViewWidth, mViewHeight);

    // Set font size proportional to view size.
    mPaint.setTextSize(mViewHeight / 5);

    mBitmap = BitmapFactory.decodeResource(
            mContext.getResources(), R.drawable.android);
    setUpBitmap();
    }

  /**
   * Runs in a separate thread.
   * All drawing happens here.
   */
  public void run() {

    Canvas canvas;

    while (mRunning) {
        // If we can obtain a valid drawing surface...
        if (mSurfaceHolder.getSurface().isValid()) {

            // Helper variables for performance.
            int x = mFlashlightCone.getX();
            int y = mFlashlightCone.getY();
            int radius = mFlashlightCone.getRadius();

            // Lock the canvas. Note that in a more complex app, with
            // more threads, you need to put this into a try/catch block
            // to make sure only one thread is drawing to the surface.
            // Starting with O, you can request a hardware surface with
            //    lockHardwareCanvas().
            // See https://developer.android.com/reference/android/view/
            //    SurfaceHolder.html#lockHardwareCanvas()
            canvas = mSurfaceHolder.lockCanvas();

            // Fill the canvas with white and draw the bitmap.
            canvas.save();
            canvas.drawColor(Color.WHITE);
            canvas.drawBitmap(mBitmap, mBitmapX, mBitmapY, mPaint);

            // Add clipping region and fill rest of the canvas with black.
            mPath.addCircle(x, y, radius, Path.Direction.CCW);
            canvas.clipPath(mPath, Region.Op.DIFFERENCE);
            canvas.drawColor(Color.BLACK);

            // If the x, y coordinates of the user touch are within a
            //  bounding rectangle, display the winning message.
            if (x > mWinnerRect.left && x < mWinnerRect.right
                    && y > mWinnerRect.top && y < mWinnerRect.bottom) {
                canvas.drawColor(Color.WHITE);
                canvas.drawBitmap(mBitmap, mBitmapX, mBitmapY, mPaint);
                canvas.drawText(
                        "WIN!", mViewWidth / 3, mViewHeight / 2, mPaint);
            }
            // Clear the path data structure.
            mPath.rewind();
            // Restore the previously saved (default) clip and matrix state.
            canvas.restore();
            // Release the lock on the canvas and show the surface's
            // contents on the screen.
            mSurfaceHolder.unlockCanvasAndPost(canvas);
         }
     }
   }

   /**
    * Updates the game data.
    * Sets new coordinates for the flashlight cone.
    *
    * @param newX New x position of touch event.
    * @param newY New y position of touch event.
    */
   private void updateFrame(int newX, int newY) {
    mFlashlightCone.update(newX, newY);
   }

   /**
    * Calculates a randomized location for the bitmap
    * and the winning bounding rectangle.
    */
  private void setUpBitmap() {
    mBitmapX = (int) Math.floor(
            Math.random() * (mViewWidth - mBitmap.getWidth()));
    mBitmapY = (int) Math.floor(
            Math.random() * (mViewHeight - mBitmap.getHeight()));
    mWinnerRect = new RectF(mBitmapX, mBitmapY,
            mBitmapX + mBitmap.getWidth(),
            mBitmapY + mBitmap.getHeight());
   }

  /**
   * Called by MainActivity.onPause() to stop the thread.
   */
  public void pause() {
    mRunning = false;
    try {
        // Stop the thread == rejoin the main thread.
        mGameThread.join();
    } catch (InterruptedException e) {
    }
  }

  /**
   * Called by MainActivity.onResume() to start a thread.
   */
  public void resume() {
    mRunning = true;
    mGameThread = new Thread(this);
    mGameThread.start();
  }

   @Override
   public boolean onTouchEvent(MotionEvent event) {
    float x = event.getX();
    float y = event.getY();

    // Invalidate() is inside the case statements because there are
    // many other motion events, and we don't want to invalidate
    // the view for those.
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            setUpBitmap();
            // Set coordinates of flashlight cone.
            updateFrame((int) x, (int) y);
            invalidate();
            break;
        case MotionEvent.ACTION_MOVE:
            // Updated coordinates for flashlight cone.
            updateFrame((int) x, (int) y);
            invalidate();
            break;
        default:
            // Do nothing.
      }
       return true;
    }

Solution

  • this issue is not the software it is the hardware on your computer and the emulator settings if you look at the bottom of the screen you will see this Emulator: android/android-emugl/host/libs/Translator/GLES_V2/GLESv2Imp.cpp:glTexSubImage2D:3237 error 0x500 (moments ago)

    So the FIX is this open the emulator by clicking on AVD manager select the emulator you are testing on and make this change to the Graphics setting what ever it is change to this Software GLES 2.0 click finish and then close Android Studio just to be sure Reopen start your app with that emulator and presto magic the app will run