diff options
Diffstat (limited to 'platform_tools/android/apps/sample_app/src/main/java')
3 files changed, 698 insertions, 0 deletions
diff --git a/platform_tools/android/apps/sample_app/src/main/java/com/skia/SkiaSampleActivity.java b/platform_tools/android/apps/sample_app/src/main/java/com/skia/SkiaSampleActivity.java new file mode 100644 index 0000000000..d9cd9f887d --- /dev/null +++ b/platform_tools/android/apps/sample_app/src/main/java/com/skia/SkiaSampleActivity.java @@ -0,0 +1,279 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +package com.skia; + +import android.app.ActionBar; +import android.app.Activity; +import android.app.DownloadManager; +import android.content.Intent; +import android.content.Context; +import android.os.Build; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.view.KeyEvent; +import android.view.Menu; +import android.view.MenuItem; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.widget.Toast; + +import java.io.File; + +public class SkiaSampleActivity extends Activity +{ + private TextView mTitle; + private SkiaSampleView mSampleView; + + private ArrayAdapter<String> mSlideList; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.layout); + mTitle = (TextView) findViewById(R.id.title_view); + mSlideList = new ArrayAdapter<String>(this, android.R.layout.simple_expandable_list_item_1); + + try { + System.loadLibrary("skia_android"); + } catch (UnsatisfiedLinkError e) { + // This might be because skia was linked to SampleApp statically. + } + + try { + System.loadLibrary("SampleApp"); + + createSampleView(false, 0); + + setupActionBar(); + } catch (UnsatisfiedLinkError e) { + mTitle.setText("ERROR: native library could not be loaded"); + } + } + + private void createSampleView(boolean useOpenGLAPI, int msaaSampleCount) { + if (mSampleView != null) { + ViewGroup viewGroup = (ViewGroup) mSampleView.getParent(); + viewGroup.removeView(mSampleView); + mSampleView.terminate(); + } + + // intent get intent extras if triggered from the command line + Intent intent = this.getIntent(); + String flags = intent.getStringExtra("cmdLineFlags"); + + if (flags == null || flags.isEmpty()) { + flags = "--pictureDir /data/local/tmp/skia_skp "; + flags += "--resourcePath /data/local/tmp/skia_resources "; + } + + mSampleView = new SkiaSampleView(this, flags, useOpenGLAPI, msaaSampleCount); + LinearLayout holder = (LinearLayout) findViewById(R.id.holder); + holder.addView(mSampleView, new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT)); + } + + private void setupActionBar() { + ActionBar.OnNavigationListener navigationCallback = new ActionBar.OnNavigationListener() { + @Override + public boolean onNavigationItemSelected(int position, long itemId) { + mSampleView.goToSample(position); + return true; + } + }; + + ActionBar actionBar = getActionBar(); + actionBar.setDisplayShowHomeEnabled(false); + actionBar.setDisplayShowTitleEnabled(false); + actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST); + actionBar.setListNavigationCallbacks(mSlideList, navigationCallback); + } + + @Override + protected void onResume () { + super.onResume(); + if (mSampleView != null && mSampleView.getWidth() > 0 && mSampleView.getHeight() > 0) { + //TODO try mSampleView.requestRender() instead + mSampleView.inval(); + } + } + + @Override + public void onDestroy() { + if (mSampleView != null) { + mSampleView.terminate(); + } + super.onDestroy(); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.action_bar, menu); + return true; + } + + @Override + public boolean onPrepareOptionsMenu(Menu menu) { + if (mSampleView != null) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) { + ((MenuItem) menu.findItem(R.id.glcontext_menu)) + .setEnabled(false); + + } else { + boolean usesOpenGLAPI = mSampleView.getUsesOpenGLAPI(); + boolean isMSAA4 = mSampleView.getMSAASampleCount() == 4; + + ((MenuItem) menu.findItem(R.id.glcontext_opengles)) + .setChecked(!usesOpenGLAPI && !isMSAA4); + + ((MenuItem) menu.findItem(R.id.glcontext_msaa4_opengles)) + .setChecked(!usesOpenGLAPI && isMSAA4); + + ((MenuItem) menu.findItem(R.id.glcontext_opengl)) + .setChecked(usesOpenGLAPI && !isMSAA4); + + ((MenuItem) menu.findItem(R.id.glcontext_msaa4_opengl)) + .setChecked(usesOpenGLAPI && isMSAA4); + } + } + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (mSampleView == null) { + return false; + } + + switch (item.getItemId()) { + case R.id.overview: + mSampleView.showOverview(); + return true; + case R.id.prev: + mSampleView.previousSample(); + return true; + case R.id.next: + mSampleView.nextSample(); + return true; + case R.id.toggle_rendering: + mSampleView.toggleRenderingMode(); + return true; + case R.id.slideshow: + mSampleView.toggleSlideshow(); + return true; + case R.id.fps: + mSampleView.toggleFPS(); + return true; + case R.id.tiling: + mSampleView.toggleTiling(); + return true; + case R.id.bbox: + mSampleView.toggleBBox(); + return true; + case R.id.save_to_pdf: + mSampleView.saveToPDF(); + return true; + case R.id.glcontext_opengles: + return setOpenGLContextSettings(false, 0); + case R.id.glcontext_msaa4_opengles: + return setOpenGLContextSettings(false, 4); + case R.id.glcontext_opengl: + return setOpenGLContextSettings(true, 0); + case R.id.glcontext_msaa4_opengl: + return setOpenGLContextSettings(true, 4); + default: + return false; + } + } + + @Override + public boolean dispatchKeyEvent(KeyEvent event) { + final int keycode = event.getKeyCode(); + if (keycode == KeyEvent.KEYCODE_BACK) { + if (event.getAction() == KeyEvent.ACTION_UP) { + finish(); + } + return true; + } + return false; + } + + private static final int SET_TITLE = 1; + private static final int SET_SLIDES = 2; + private static final int TOAST_DOWNLOAD = 3; + + private Handler mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case SET_TITLE: + mTitle.setText((String) msg.obj); + SkiaSampleActivity.this.getActionBar().setSubtitle((String) msg.obj); + break; + case SET_SLIDES: + mSlideList.addAll((String[]) msg.obj); + break; + case TOAST_DOWNLOAD: + Toast.makeText(SkiaSampleActivity.this, (String) msg.obj, + Toast.LENGTH_SHORT).show(); + break; + default: + break; + } + } + }; + + // Called by JNI + @Override + public void setTitle(CharSequence title) { + mHandler.obtainMessage(SET_TITLE, title).sendToTarget(); + } + + // Called by JNI + public void setSlideList(String[] slideList) { + mHandler.obtainMessage(SET_SLIDES, slideList).sendToTarget(); + } + + // Called by JNI + public void addToDownloads(final String title, final String desc, final String path) { + File file = new File(path); + final long length = file.exists() ? file.length() : 0; + if (length == 0) { + String failed = getString(R.string.save_failed); + mHandler.obtainMessage(TOAST_DOWNLOAD, failed).sendToTarget(); + return; + } + String toast = getString(R.string.file_saved).replace("%s", title); + mHandler.obtainMessage(TOAST_DOWNLOAD, toast).sendToTarget(); + final DownloadManager manager = + (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE); + new Thread("Add PDF to downloads") { + @Override + public void run() { + final String mimeType = "application/pdf"; + manager.addCompletedDownload(title, desc, true, mimeType, path, length, true); + } + }.start(); + } + + private boolean setOpenGLContextSettings(boolean requestedOpenGLAPI, int requestedSampleCount) { + if (mSampleView != null && + mSampleView.getMSAASampleCount() == requestedSampleCount && + mSampleView.getUsesOpenGLAPI() == requestedOpenGLAPI) { + return true; + } + + createSampleView(requestedOpenGLAPI, requestedSampleCount); + + return true; + } +} diff --git a/platform_tools/android/apps/sample_app/src/main/java/com/skia/SkiaSampleRenderer.java b/platform_tools/android/apps/sample_app/src/main/java/com/skia/SkiaSampleRenderer.java new file mode 100644 index 0000000000..55257094cd --- /dev/null +++ b/platform_tools/android/apps/sample_app/src/main/java/com/skia/SkiaSampleRenderer.java @@ -0,0 +1,113 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +package com.skia; + +import android.opengl.GLSurfaceView; +import android.os.Handler; +import android.util.Log; + +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.opengles.GL10; +import javax.microedition.khronos.opengles.GL11; + +public class SkiaSampleRenderer implements GLSurfaceView.Renderer { + + private final SkiaSampleView mSampleView; + private Handler mHandler = new Handler(); + private int mMSAASampleCount; + private String mCmdLineFlags; + + SkiaSampleRenderer(SkiaSampleView view, String cmdLineFlags) { + mSampleView = view; + mCmdLineFlags = cmdLineFlags; + } + + @Override + public void onDrawFrame(GL10 gl) { + draw(); + } + + @Override + public void onSurfaceChanged(GL10 gl, int width, int height) { + updateSize(width, height); + } + + @Override + public void onSurfaceCreated(GL10 gl, EGLConfig config) { + if (gl instanceof GL11) { + int value[] = new int[1]; + ((GL11) gl).glGetIntegerv(GL11.GL_SAMPLES, value, 0); + if (value[0] == 1) { + mMSAASampleCount = 0; + } else { + mMSAASampleCount = value[0]; + } + } + + gl.glClearStencil(0); + gl.glClear(GL10.GL_STENCIL_BUFFER_BIT); + + init((SkiaSampleActivity)mSampleView.getContext(), mCmdLineFlags, mMSAASampleCount); + } + + // Called by JNI and the view. + synchronized public int getMSAASampleCount() { + return mMSAASampleCount; + } + + // Called by JNI + private void startTimer(int ms) { + // After the delay, queue an event to the Renderer's thread + // to handle the event on the timer queue + mHandler.postDelayed(new Runnable() { + @Override + public void run() { + mSampleView.queueEvent(new Runnable() { + @Override + public void run() { + serviceQueueTimer(); + } + }); + } + }, ms); + } + + // Called by JNI + private void queueSkEvent() { + mSampleView.queueEvent(new Runnable() { + @Override + public void run() { + processSkEvent(); + } + }); + } + + // Called by JNI + private void requestRender() { + mSampleView.requestRender(); + } + + native void init(SkiaSampleActivity activity, String flags, int msaaSampleCount); + native void term(); + native void draw(); + native void updateSize(int w, int h); + native void handleClick(int owner, float x, float y, int state); + native void showOverview(); + native void nextSample(); + native void previousSample(); + native void goToSample(int position); + native void toggleRenderingMode(); + native void toggleSlideshow(); + native void toggleFPS(); + native void toggleTiling(); + native void toggleBBox(); + native void processSkEvent(); + native void serviceQueueTimer(); + native void saveToPDF(); + native void postInval(); +}
\ No newline at end of file diff --git a/platform_tools/android/apps/sample_app/src/main/java/com/skia/SkiaSampleView.java b/platform_tools/android/apps/sample_app/src/main/java/com/skia/SkiaSampleView.java new file mode 100644 index 0000000000..c33f8ae8ac --- /dev/null +++ b/platform_tools/android/apps/sample_app/src/main/java/com/skia/SkiaSampleView.java @@ -0,0 +1,306 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +package com.skia; + +import javax.microedition.khronos.egl.EGL10; +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.egl.EGLDisplay; +import javax.microedition.khronos.opengles.GL10; + +import android.content.Context; +import android.opengl.EGL14; +import android.opengl.GLSurfaceView; +import android.os.Build; +import android.util.Log; +import android.view.MotionEvent; + +public class SkiaSampleView extends GLSurfaceView { + + private final SkiaSampleRenderer mSampleRenderer; + private boolean mRequestedOpenGLAPI; // true == use (desktop) OpenGL. false == use OpenGL ES. + private int mRequestedMSAASampleCount; + + public SkiaSampleView(Context ctx, String cmdLineFlags, boolean useOpenGL, int msaaSampleCount) { + super(ctx); + + mSampleRenderer = new SkiaSampleRenderer(this, cmdLineFlags); + mRequestedMSAASampleCount = msaaSampleCount; + + setEGLContextClientVersion(2); + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) { + setEGLConfigChooser(8, 8, 8, 8, 0, 8); + } else { + mRequestedOpenGLAPI = useOpenGL; + setEGLConfigChooser(new SampleViewEGLConfigChooser()); + } + setRenderer(mSampleRenderer); + setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + int count = event.getPointerCount(); + for (int i = 0; i < count; i++) { + final float x = event.getX(i); + final float y = event.getY(i); + final int owner = event.getPointerId(i); + int action = event.getAction() & MotionEvent.ACTION_MASK; + switch (action) { + case MotionEvent.ACTION_POINTER_UP: + action = MotionEvent.ACTION_UP; + break; + case MotionEvent.ACTION_POINTER_DOWN: + action = MotionEvent.ACTION_DOWN; + break; + default: + break; + } + final int finalAction = action; + queueEvent(new Runnable() { + @Override + public void run() { + mSampleRenderer.handleClick(owner, x, y, finalAction); + } + }); + } + return true; + } + + public void inval() { + queueEvent(new Runnable() { + @Override + public void run() { + mSampleRenderer.postInval(); + } + }); + } + + public void terminate() { + queueEvent(new Runnable() { + @Override + public void run() { + mSampleRenderer.term(); + } + }); + } + + public void showOverview() { + queueEvent(new Runnable() { + @Override + public void run() { + mSampleRenderer.showOverview(); + } + }); + } + + public void nextSample() { + queueEvent(new Runnable() { + @Override + public void run() { + mSampleRenderer.nextSample(); + } + }); + } + + public void previousSample() { + queueEvent(new Runnable() { + @Override + public void run() { + mSampleRenderer.previousSample(); + } + }); + } + + public void goToSample(final int position) { + queueEvent(new Runnable() { + @Override + public void run() { + mSampleRenderer.goToSample(position); + } + }); + } + + public void toggleRenderingMode() { + queueEvent(new Runnable() { + @Override + public void run() { + mSampleRenderer.toggleRenderingMode(); + } + }); + } + + public void toggleSlideshow() { + queueEvent(new Runnable() { + @Override + public void run() { + mSampleRenderer.toggleSlideshow(); + } + }); + } + + public void toggleFPS() { + queueEvent(new Runnable() { + @Override + public void run() { + mSampleRenderer.toggleFPS(); + } + }); + } + + public void toggleTiling() { + queueEvent(new Runnable() { + @Override + public void run() { + mSampleRenderer.toggleTiling(); + } + }); + } + + public void toggleBBox() { + queueEvent(new Runnable() { + @Override + public void run() { + mSampleRenderer.toggleBBox(); + } + }); + } + + public void saveToPDF() { + queueEvent(new Runnable() { + @Override + public void run() { + mSampleRenderer.saveToPDF(); + } + }); + } + + public boolean getUsesOpenGLAPI() { + return mRequestedOpenGLAPI; + } + + public int getMSAASampleCount() { + return mSampleRenderer.getMSAASampleCount(); + } + + private class SampleViewEGLConfigChooser implements GLSurfaceView.EGLConfigChooser { + + @Override + public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) { + int numConfigs = 0; + int[] configSpec = null; + int[] value = new int[1]; + + int[] validAPIs = new int[] { + EGL14.EGL_OPENGL_API, + EGL14.EGL_OPENGL_ES_API + }; + int initialAPI = mRequestedOpenGLAPI ? 0 : 1; + + for (int i = initialAPI; i < validAPIs.length && numConfigs == 0; i++) { + int currentAPI = validAPIs[i]; + EGL14.eglBindAPI(currentAPI); + + // setup the renderableType which will only be included in the + // spec if we are attempting to get access to the OpenGL APIs. + int renderableType = EGL14.EGL_OPENGL_BIT; + if (currentAPI == EGL14.EGL_OPENGL_API) { + renderableType = EGL14.EGL_OPENGL_ES2_BIT; + } + + if (mRequestedMSAASampleCount > 0) { + configSpec = new int[] { + EGL10.EGL_RED_SIZE, 8, + EGL10.EGL_GREEN_SIZE, 8, + EGL10.EGL_BLUE_SIZE, 8, + EGL10.EGL_ALPHA_SIZE, 8, + EGL10.EGL_DEPTH_SIZE, 0, + EGL10.EGL_STENCIL_SIZE, 8, + EGL10.EGL_SAMPLE_BUFFERS, 1, + EGL10.EGL_SAMPLES, mRequestedMSAASampleCount, + EGL10.EGL_RENDERABLE_TYPE, renderableType, + EGL10.EGL_NONE + }; + + // EGL_RENDERABLE_TYPE is only needed when attempting to use + // the OpenGL API (not ES) and causes many EGL drivers to fail + // with a BAD_ATTRIBUTE error. + if (!mRequestedOpenGLAPI) { + configSpec[16] = EGL10.EGL_NONE; + Log.i("Skia", "spec: " + configSpec); + } + + if (!egl.eglChooseConfig(display, configSpec, null, 0, value)) { + Log.i("Skia", "Could not get MSAA context count: " + mRequestedMSAASampleCount); + } + + numConfigs = value[0]; + } + + if (numConfigs <= 0) { + // Try without multisampling. + configSpec = new int[] { + EGL10.EGL_RED_SIZE, 8, + EGL10.EGL_GREEN_SIZE, 8, + EGL10.EGL_BLUE_SIZE, 8, + EGL10.EGL_ALPHA_SIZE, 8, + EGL10.EGL_DEPTH_SIZE, 0, + EGL10.EGL_STENCIL_SIZE, 8, + EGL10.EGL_RENDERABLE_TYPE, renderableType, + EGL10.EGL_NONE + }; + + // EGL_RENDERABLE_TYPE is only needed when attempting to use + // the OpenGL API (not ES) and causes many EGL drivers to fail + // with a BAD_ATTRIBUTE error. + if (!mRequestedOpenGLAPI) { + configSpec[12] = EGL10.EGL_NONE; + Log.i("Skia", "spec: " + configSpec); + } + + if (!egl.eglChooseConfig(display, configSpec, null, 0, value)) { + Log.i("Skia", "Could not get non-MSAA context count"); + } + numConfigs = value[0]; + } + } + + if (numConfigs <= 0) { + throw new IllegalArgumentException("No configs match configSpec"); + } + + // Get all matching configurations. + EGLConfig[] configs = new EGLConfig[numConfigs]; + if (!egl.eglChooseConfig(display, configSpec, configs, numConfigs, value)) { + throw new IllegalArgumentException("Could not get config data"); + } + + for (int i = 0; i < configs.length; ++i) { + EGLConfig config = configs[i]; + if (findConfigAttrib(egl, display, config , EGL10.EGL_RED_SIZE, 0) == 8 && + findConfigAttrib(egl, display, config, EGL10.EGL_BLUE_SIZE, 0) == 8 && + findConfigAttrib(egl, display, config, EGL10.EGL_GREEN_SIZE, 0) == 8 && + findConfigAttrib(egl, display, config, EGL10.EGL_ALPHA_SIZE, 0) == 8 && + findConfigAttrib(egl, display, config, EGL10.EGL_STENCIL_SIZE, 0) == 8) { + return config; + } + } + + throw new IllegalArgumentException("Could not find suitable EGL config"); + } + + private int findConfigAttrib(EGL10 egl, EGLDisplay display, + EGLConfig config, int attribute, int defaultValue) { + int[] value = new int[1]; + if (egl.eglGetConfigAttrib(display, config, attribute, value)) { + return value[0]; + } + return defaultValue; + } + + } +} |