Nyan Cat: Lost In Space (Android)

Nyan Cat's lost, so he's got to collect a bunch of stuff! Personally, I think the priority should be finding where in space he actually is...

Uncompiled Code
Inside the apk for at least one version is EngineActivity.java.bak: almost 40kb of uncompiled commented java code.

package com.istomgames.engine;

import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10;

import com.adwhirl.AdWhirlLayout; import com.adwhirl.AdWhirlManager; import com.adwhirl.AdWhirlTargeting; import com.google.ads.AdView; import com.istomgames.engine.ExpansionDownloadService.XAPKFile;

import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.InputStream; import java.lang.String; import java.net.URL; import java.util.Date; import java.util.Vector;

import android.app.Activity; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Color; import android.graphics.Point; import android.hardware.SensorManager; import android.net.Uri; import android.opengl.GLSurfaceView; import android.opengl.GLUtils; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.StrictMode; import android.util.DisplayMetrics; import android.util.Log; import android.view.Display; import android.view.Gravity; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; import android.view.Window; import android.view.WindowManager; import android.view.ViewGroup.LayoutParams; import android.widget.LinearLayout; import android.widget.Toast;

public class EngineActivity extends Activity { private static EngineActivity sInstance; public static EngineActivity getInstance { return sInstance; } private String mFileDirPath; private GLSurfaceView mGLView; private GameRenderer mRenderer; private SensorHandler mAccelerometer; private boolean mLandscapeOriented = true; private MusicPlayer mMusicPlayer; private GameCenterHandler mGameCenter = null; private FacebookHandler mFacebookHandler; private Handler mJobHandler; public static final String PackageName = "com.istomgames.engine"; // game center public static final String ScoreLoopSecret = ""; // expansion download default ertekek public static final XAPKFile[] xAPKS = { new XAPKFile( 	true, // true signifies a main file               		6, // the version of the APK that the file was uploaded against                		60915415L // the length of the file in bytes        ) };   // az alap ertekekhez (a PackageInfo-bol kerdezi egyebkent) public static final int majorVersion = 1; public static final int minorVersion = 0; private ExpansionDownloadService mExpansionDownload; // reklamok private AdView mAdView; private boolean mAllowAd = true; private int mAdWidth = 350; private int mAdHeight = 50; private LinearLayout mLinearLayout; private AdWhirlLayout mAdWhirlLayout; private final String ADWHIRL_ID = "527f7e4d17ea460d8ec588c586cc37b4"; // news update private static final String HOST = "http://gamehs.ergosystem.hu";

static { System.loadLibrary("openal"); System.loadLibrary("game"); }   public EngineActivity{ sInstance = this; }	@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.i("EXP", "kell-e az expansion file?"); DisplayMetrics metrics = new DisplayMetrics; getWindowManager.getDefaultDisplay.getMetrics(metrics);

int height = metrics.heightPixels; int width = metrics.widthPixels; // FONTOS! : jelenleg az utils.cpp-ben a GetDeviceFilenName ugyanezt hasznalja, //			hogy eldontse melyik textura kell, ha az valtozik ezt is valtoztatni kell int max = (width > height) ? width : height; if (max >= 960) {       	Log.i("EXP", "igen, expansion file ellenorzese"); if (!ExpansionDownloadService.expansionFilesDelivered(this, xAPKS)) {	       	Intent myIntent = new Intent(EngineActivity.this, ExpansionDownloaderActivity.class); EngineActivity.this.startActivity(myIntent); finish; return; }       }        else Log.i("EXP", "nem, kis texturak hasznalata"); mJobHandler = new Handler; this.requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,                             WindowManager.LayoutParams.FLAG_FULLSCREEN); if (mLandscapeOriented){ setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); }       else{ setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); }       Toast.makeText(this, "Loading...", Toast.LENGTH_SHORT).show; try{ mAccelerometer = new SensorHandler((SensorManager)getSystemService(Context.SENSOR_SERVICE), false, true); mMusicPlayer = new MusicPlayer(this); /*    	        	mGameCenter = new GameCenterHandler(getApplicationContext); mGameCenter.login; */     	        	mRenderer = new GameRenderer(this); mGLView = new GameSurfaceView(this); mGLView.setRenderer(mRenderer); setContentView(mGLView);

//    	if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) //    		mGLView.setSystemUiVisibility(View.STATUS_BAR_HIDDEN); }       catch(Exception e){ Log.e("JAVA", e.getMessage); }       File f = this.getApplicationContext.getFilesDir; mFileDirPath = f.toString; mFacebookHandler = new FacebookHandler; if (mAllowAd) {	       AdWhirlManager.setConfigExpireTimeout(1000 * 60 * 5); AdWhirlTargeting.setKeywords("games gaming"); //     AdWhirlTargeting.setTestMode(true); mAdWhirlLayout = new AdWhirlLayout(this, ADWHIRL_ID); mLinearLayout = new LinearLayout(this); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT); mLinearLayout.setGravity(Gravity.CENTER | Gravity.BOTTOM); this.addContentView(mLinearLayout, params); mAdWhirlLayout.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.TOP); params = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); mLinearLayout.addView(mAdWhirlLayout, params); }	}   @Override protected void onPause { Log.i("JAVA", "onPause"); super.onPause; if (mExpansionDownload == null) {	       adHide; if (mGLView != null) mGLView.onPause; if (mAccelerometer != null) mAccelerometer.pause; if (mGameCenter != null) mGameCenter.onPause; }   }

@Override protected void onResume { Log.i("JAVA", "onResume"); super.onResume; if (mExpansionDownload == null) {	       if (mGLView != null) mGLView.onResume; if (mAccelerometer != null) mAccelerometer.resume; if (mGameCenter != null) mGameCenter.onResume; if (mFacebookHandler != null) mFacebookHandler.onResume; }   }    protected void onStart { Log.i("JAVA", "onStart"); super.onStart;

if (mMusicPlayer != null) mMusicPlayer.reload; nativeStart; }   protected void onRestart { super.onRestart; }   protected void onStop { Log.i("JAVA", "onStop"); super.onStop; if (mMusicPlayer != null) mMusicPlayer.release; nativeStop; }   protected void onDestroy { Log.i("JAVA", "onDestory"); nativeDestroy; super.onDestroy; if (mMusicPlayer != null) mMusicPlayer.release; if (mGameCenter != null) mGameCenter.onExit; if (mAdView != null) mAdView.destroy; }   @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); mFacebookHandler.onActivityResult(requestCode, resultCode, data); }   public boolean onKeyDown(int keyCode, KeyEvent event){ if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN ||       		keyCode == KeyEvent.KEYCODE_VOLUME_UP ||        		keyCode == KeyEvent.KEYCODE_MUTE) return false; GameSurfaceView.nativeKey(false, keyCode); return true; }   public boolean onKeyUp(int keyCode, KeyEvent event){ if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN ||   		keyCode == KeyEvent.KEYCODE_VOLUME_UP ||    		keyCode == KeyEvent.KEYCODE_MUTE) return false; GameSurfaceView.nativeKey(true, keyCode); return true; }   public boolean isLandscapeOriented{ return mLandscapeOriented; }   public GameCenterHandler getGameCenterHandler{ return mGameCenter; }   public int getAdWidth{ return mAdWidth; }   public int getAdHeight{ return mAdHeight; }   public Handler getJobHandler{ return mJobHandler; }   static public void showErrorMessage(final String msg){ sInstance.mJobHandler.post(new Runnable {			public void run {				Toast t = Toast.makeText(sInstance, "error: " + msg, Toast.LENGTH_LONG);	   	//	t.setGravity(Gravity.TOP, 0, 0);	    		t.show;			}    	}); }   static public void alertSmallResolution{ sInstance.mJobHandler.post(new Runnable {			public void run {				try{					AlertDialog.Builder builder = new AlertDialog.Builder(EngineActivity.sInstance);			        builder.setTitle("Small Resolution")			         	   .setMessage("The resolution of your phone is not officially supported. " + "You can still play but you may experience problems " + "and graphical errors.")			        	   .setPositiveButton("Ok", new DialogInterface.OnClickListener { @Override public void onClick(DialogInterface dialog, int which) { dialog.cancel; }			 				});			        AlertDialog alert = builder.create;			         alert.show;				}				catch (Exception e){					Log.i("Exception", e.toString);				}			}		}); }   //c++-bol hivodnak static public void loadMusic(String path){ if (sInstance.mMusicPlayer != null){ sInstance.mMusicPlayer.load(path); Log.i("MUSIC", "load music:" + path); }   }    static public void startMusic{ if (sInstance.mMusicPlayer != null) sInstance.mMusicPlayer.start; }   static public void stopMusic{ if (sInstance.mMusicPlayer != null) sInstance.mMusicPlayer.stop; }   static public void pauseMusic{ if (sInstance.mMusicPlayer != null) sInstance.mMusicPlayer.pause; }   static public void setVolume(float volume){ if (sInstance.mMusicPlayer != null) sInstance.mMusicPlayer.setVolume(volume); }

static public void openfeintLogin{ Log.i("JAVA", "openfeintLogin"); if (sInstance.mGameCenter != null) sInstance.mGameCenter.login; }   static public void showLeaderboard(String leaderboardId){ if (sInstance.mGameCenter != null) sInstance.mGameCenter.showLeaderboard(leaderboardId); }   static public void reportScore(long score, String leaderboardId){ if (sInstance.mGameCenter != null) sInstance.mGameCenter.reportScore(score, leaderboardId); }   static public void openURL(String url){ if (!url.startsWith("http://") && !url.startsWith("https://")) url = "http://" + url; Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); sInstance.startActivity(browserIntent); }   static public void sendMail(String subject, String body){ Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND); emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, subject); emailIntent.setType("text/plain"); emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, body); sInstance.startActivity(emailIntent); }

static public void adShow{ if (sInstance.mAllowAd) {   		sInstance.mJobHandler.post(new Runnable {				public void run {					try{						if(sInstance.mAdWhirlLayout.getVisibility != AdWhirlLayout.VISIBLE)						{							sInstance.mAdWhirlLayout.setVisibility(AdWhirlLayout.VISIBLE);							sInstance.mLinearLayout.addView(sInstance.mAdWhirlLayout);						}					}					catch (Exception e){						Log.i("Exception", e.toString);					}				}			}); }   }    static public void adHide{ if (sInstance.mAllowAd) {   		sInstance.mJobHandler.post(new Runnable {				public void run {					try{						if(sInstance.mAdWhirlLayout.getVisibility == AdWhirlLayout.VISIBLE)						{							sInstance.mAdWhirlLayout.setVisibility(AdWhirlLayout.GONE);							sInstance.mLinearLayout.removeView(sInstance.mAdWhirlLayout);						}					}					catch (Exception e){						Log.i("Exception", e.toString);					}				}			}); }   }    static public void fbLogin{ sInstance.mJobHandler.post(new Runnable {			public void run {				sInstance.mFacebookHandler.login;			}		}); }   static public void fbLogout{ sInstance.mJobHandler.post(new Runnable {			public void run {				sInstance.mFacebookHandler.logout;			}		}); }

static public void fbPublish(final String attachName, final String attachCapiton, final String attachDescription, final String attachLink){ sInstance.mJobHandler.post(new Runnable {			public void run {				sInstance.mFacebookHandler.publishStream(attachName, attachCapiton, attachDescription, attachLink);			}		}); }   static public boolean fbIsLoggedIn { return sInstance.mFacebookHandler.isLoggedIn; }   static public void sendTweet(String tweet){ //		sInstance.mJobHandler.post(new Runnable {	//		public void run {				Intent tweetIntent = new Intent(android.content.Intent.ACTION_SEND); 				tweetIntent.setType("text/plain");  				tweetIntent.putExtra(android.content.Intent.EXTRA_TEXT, tweet);  		    	sInstance.startActivity(tweetIntent);	//		}	//	}); }   static public int getMajorVersion {   	try{ PackageInfo pInfo = sInstance.getPackageManager.getPackageInfo(sInstance.getPackageName, 0); return Integer.parseInt(pInfo.versionName.substring(0, pInfo.versionName.indexOf('.'))); }   	catch(Exception e) { Log.w("JAVA", e.toString); }   	return majorVersion; }   static public int getMinorVersion {   	try{ PackageInfo pInfo = sInstance.getPackageManager.getPackageInfo(sInstance.getPackageName, 0); return Integer.parseInt(pInfo.versionName.substring(pInfo.versionName.indexOf('.')+1)); }   	catch(Exception e) { Log.w("JAVA", e.toString); }   	return minorVersion; }   static public void displayExitDialog{ sInstance.mJobHandler.post(new Runnable {			public void run {				AlertDialog dialog = new AlertDialog.Builder(sInstance).create;				dialog.setTitle("Quit");				dialog.setMessage("Are you sure you want to quit?");				dialog.setButton(AlertDialog.BUTTON_POSITIVE, "Yes, quit!", new DialogInterface.OnClickListener { public void onClick(DialogInterface dialog, int which) { android.os.Process.killProcess(android.os.Process.myPid); }				});				dialog.setButton(AlertDialog.BUTTON_NEGATIVE, "No, keep playing...", new DialogInterface.OnClickListener { public void onClick(DialogInterface dialog, int which) { dialog.dismiss; }				});				dialog.show;			}   	}); }   static public void newsUpdate{ new Thread(new Runnable {   	    public void run {    	    	BufferedInputStream in = null;    	    	FileOutputStream fout = null;    	        try{    	        	String url = HOST + "/android_news/news.txt";    	        	String filename = EngineActivity.sInstance.mFileDirPath;    	        	filename += (filename.endsWith("/")) ? "cache/last_news.txt" : "/cache/last_news.txt";    	        	// letolteni news.txt-t    	        	in = new BufferedInputStream(new URL(url).openStream);        	        fout = new FileOutputStream(filename);

byte data[] = new byte[1024]; int count; while ((count = in.read(data, 0, 1024)) != -1) {	               	fout.write(data, 0, count); }	               in.close; fout.close; // kepnevek kiszedese Vector imageNames = new Vector; BufferedReader reader = new BufferedReader(new FileReader(filename)); String line; int startIndex, endIndex; String picName; while ((line = reader.readLine) != null) { if (line.contains("filename")){ startIndex = line.indexOf("") + 3; endIndex = line.indexOf(""); picName = line.substring(startIndex, endIndex); if (line.contains("banner_base_filename")){ if (!sInstance.mLandscapeOriented) picName += "_p"; picName += GetBannerPicPostFix; }	                   	imageNames.add(picName); }	                   else if (line.contains("image")){ startIndex = line.indexOf('"') + 1;	                   	endIndex = line.lastIndexOf('"'); picName = line.substring(startIndex, endIndex); picName += GetBannerPicPostFix; imageNames.add(picName); }	               }	                reader.close; //letoltes idejenek a beleirasa Date d = new Date; BufferedWriter writer = new BufferedWriter(new FileWriter(filename, true)); writer.newLine; writer.append("downloaded = " + d.getTime); writer.newLine; writer.close; // kepek letoltese for (int i = 0; i < imageNames.size; ++i){ StringBuilder picUrl = new StringBuilder; picUrl.append(HOST); picUrl.append("/android_news/"); picUrl.append(imageNames.get(i)); picUrl.append(".png"); StringBuilder picFile = new StringBuilder; picFile.append(EngineActivity.sInstance.mFileDirPath); if (picFile.charAt(picFile.length - 1) != '/') picFile.append("/"); picFile.append("cache/"); picFile.append(imageNames.get(i)); picFile.append(".png"); java.io.File file = new java.io.File(picFile.toString); if(!file.exists){ Log.i("DOWNLOAD", "start image:"+picUrl.toString); in = new BufferedInputStream(new URL(picUrl.toString).openStream); fout = new FileOutputStream(picFile.toString); byte picData[] = new byte[1024]; int picCount; while ((picCount = in.read(picData, 0, 1024)) != -1) fout.write(picData, 0, picCount); in.close; fout.close; Log.i("DOWNLOAD", "image downloaded:"+picUrl.toString); }		               else Log.i("DOWNLOAD", "image skipped:"+picUrl.toString+" (already exists)"); }   	        }    	        catch(Exception e){ Log.w("JAVA", "update chache error:"+e.toString); }   	        finally { /*    	try{ if (in != null) in.close; if (fout != null) fout.close; } catch (Exception e){ }*/   	        }    	    }    	}).start;    }    static private String GetBannerPicPostFix    {    	int width = EngineActivity.sInstance.getWindowManager.getDefaultDisplay.getWidth;    	if (width > 768)            return "_ipad";        else if (width > 480)            return "_ip4";        else             return "_ip";    }    //nativ hivasok    static private native void nativeStop;    static private native void nativeStart;    static private native void nativeDestroy; }

class GameSurfaceView extends GLSurfaceView { static private GameSurfaceView instance; private Vector mTouchEvents = new Vector; public GameSurfaceView(Context context) { super(context); this.setKeepScreenOn(true); instance = this; }

private float lastTouchX; private float lastTouchY; private int touchId = -1;

public boolean onTouchEvent(final MotionEvent event) { switch(event.getAction) {           case MotionEvent.ACTION_DOWN: {               if (touchId < 0) {                   touchId = event.getPointerId(0); float x = event.getX(0); float y = event.getY(0); //nativeTouch(toByte(MsgType.MT_ACTION_DOWN), x,y, 0.0f,0.0f, (byte)0); mTouchEvents.add(new TouchEvent(toByte(MsgType.MT_ACTION_DOWN), x,y, 0.0f,0.0f, (byte)0)); lastTouchX = x;                   lastTouchY = y;                } break; }           case MotionEvent.ACTION_UP: {               int index = event.findPointerIndex(touchId); if (index >= 0) {                   float x = event.getX(index); float y = event.getY(index); //nativeTouch(toByte(MsgType.MT_ACTION_UP), x, y, x - lastTouchX, y - lastTouchY, (byte)0); mTouchEvents.add(new TouchEvent(toByte(MsgType.MT_ACTION_UP), x, y, x - lastTouchX, y - lastTouchY, (byte)0)); touchId = -1; }               break; }           case MotionEvent.ACTION_MOVE: {               int index = event.findPointerIndex(touchId); if (index >= 0) {                   float x = event.getX(index); float y = event.getY(index); //nativeTouch(toByte(MsgType.MT_ACTION_MOVE), x, y, x - lastTouchX, y - lastTouchY, (byte)0); mTouchEvents.add(new TouchEvent(toByte(MsgType.MT_ACTION_MOVE), x, y, x - lastTouchX, y - lastTouchY, (byte)0)); lastTouchX = x;                   lastTouchY = y;                } break; }           case MotionEvent.ACTION_CANCEL: {                       if (event.getPointerId(event.getActionIndex) == touchId) {                      touchId = -1; //nativeTouch(toByte(MsgType.MT_ACTION_CANCEL), 0.0f,0.0f ,0.0f,0.0f, (byte)0); mTouchEvents.add(new TouchEvent(toByte(MsgType.MT_ACTION_CANCEL), 0.0f,0.0f ,0.0f,0.0f, (byte)0)); }               break; }       }        return true; }   private byte toByte(MsgType type){ return (byte)type.ordinal; }   private enum MsgType {       MT_ACTION_DOWN, MT_ACTION_UP, MT_ACTION_MOVE, MT_ACTION_CANCEL,

MT_ACTION_SCROLL }   class TouchEvent{ byte type; float x;   	float y;    	float dx; float dy; byte modifiers; public TouchEvent(byte type, float x, float y, float dx, float dy, byte modifiers){ this.type = type; this.x = x;   		this.y = y;    		this.dx = dx; this.dy = dy; this.modifiers = modifiers; }   	public void SendToNative{ nativeTouch(type, x, y, dx, dy, modifiers); }   }    static public void sendNativeTouchEvents{ if (instance.mTouchEvents.size > 0){ for (int i = 0; i < instance.mTouchEvents.size; ++i){ instance.mTouchEvents.get(i).SendToNative; }   		instance.mTouchEvents.clear; }   }    private static native void nativeTouch(byte type, float x, float y, float dx, float dy, byte modifiers);

public static native void nativeKey(boolean up, int keycode); }

class GameRenderer implements GLSurfaceView.Renderer { private static GameRenderer instance; private Context context; private int width; private int height; private Vector freeTextures = new Vector; private Vector loadedTextures = new Vector; private Vector waitingTextures = new Vector; private Vector toBeDeleted = new Vector; private final int defaultHandleNum = 64; public GameRenderer(Context context){ this.context = context; instance = this; }   boolean firstCreated = true; public void onSurfaceCreated(GL10 gl, EGLConfig config) { if (firstCreated) {			String apkFilePath = null; ApplicationInfo appInfo = null; PackageManager packMgr = context.getPackageManager; try{ appInfo = packMgr.getApplicationInfo("com.istomgames.engine", 0); }	       catch (NameNotFoundException e){ e.printStackTrace; throw new RuntimeException("Unable to locate assets, abort..."); }	       createTextureHandles(gl, defaultHandleNum); apkFilePath = appInfo.sourceDir; File f = EngineActivity.getInstance.getApplicationContext.getFilesDir; Log.i("file path", f.toString); Log.i("JAVA", "nativeInit"); nativeInit(apkFilePath, f.toString); firstCreated = false; }	}	private boolean firstChange = true; public void onSurfaceChanged(GL10 gl, int w, int h) { Log.i("JAVA", "onSurfaceChanged"); if (firstChange) {	   		firstChange = false; Log.i("JAVA", "nativeResize"); int max = (w > h) ? w : h;	   		Log.i("JAVA", "resolution:"+w+"x"+h); if (max < 480) EngineActivity.alertSmallResolution; if (!EngineActivity.getInstance.isLandscapeOriented) {		   		nativeResize(w, h); width = w;		   		height = h;	    		} else {		   		nativeResize(h, w); width = h;		   		height = w;	    		} }	   	else {	   		reloadTextures(gl); nativeReloadGLResources; }   }

public void onDrawFrame(GL10 gl) { GameSurfaceView.sendNativeTouchEvents; if (!toBeDeleted.isEmpty) {   		deleteToBeDeleted(gl); }   	else if (!waitingTextures.isEmpty) {   		loadWaitingTextures(gl); }   	else nativeRender; }   public static native void nativeInit(String apkPath, String fileDirPath); public static native void nativeResize(int w, int h); public static native void nativeRender; public static native void nativeReloadGLResources; private void reloadTextures(GL10 gl){ for (int i = 0; i < loadedTextures.size; ++i) {   		int[] texture = new int[1]; texture[0] = loadedTextures.get(i).id; gl.glDeleteTextures(1, texture, 0); }   	while(freeTextures.size > 0) {   		int[] texture = new int[1]; texture[0] = freeTextures.remove(0); gl.glDeleteTextures(1, texture, 0); }   	freeTextures.clear; createTextureHandles(gl, defaultHandleNum); for (int i = 0; i < waitingTextures.size; ++i) {   		waitingTextures.get(i).id = freeTextures.remove(0); }   	for (int i = 0; i < loadedTextures.size; ++i) {   		TextureData data = loadedTextures.get(i); addWaitingTexture(data.filename); }   	loadedTextures.clear; System.gc; Log.i("JAVA", "Reloaded texture num:" + loadedTextures.size); }   private void createTextureHandles(GL10 gl, int num){ int[] textures = new int[num]; gl.glGenTextures(num, textures, 0); for (int i = 0; i < textures.length; ++i) freeTextures.add(textures[i]); }   // ezt taroljuk static public class TextureData { public String filename; public Bitmap bitmap; public int id; public int width; public int height; public TextureInfo toTextureInfo {   		TextureInfo info = new TextureInfo; info.id = id; info.width = width; info.height = height; return info; }   }    // ezt adja vissza, mikor valaki texturat akar betölteni static public class TextureInfo { public int width; public int height; public int id; }   private void loadWaitingTextures(GL10 gl){ while (!waitingTextures.isEmpty) {   		TextureData data = waitingTextures.remove(0); if (data.bitmap == null || data.bitmap.isRecycled) Log.e("ERROR", "ERROR: loadWaitingTextures bitmap is null or recycled"); gl.glBindTexture(GL10.GL_TEXTURE_2D, data.id); gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR); gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR); gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_REPEAT); gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_REPEAT); GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, data.bitmap, 0); data.bitmap.recycle; data.bitmap = null; loadedTextures.add(data); }   }    private TextureInfo loadTexture(String filename) { TextureInfo result = null; for (int i = 0; i < loadedTextures.size; ++i) if (loadedTextures.get(i).filename.equals(filename)) result = loadedTextures.get(i).toTextureInfo; if (result == null){ for (int i = 0; i < waitingTextures.size; ++i) if (waitingTextures.get(i).filename.equals(filename)) return waitingTextures.get(i).toTextureInfo; }   	if (result == null) result = addWaitingTexture(filename); // a ha keres erkezik a textura betoltesre, akkor toroljuk ki a torlendok listajarol if (toBeDeleted.size > 0){ for (int i = 0; i < toBeDeleted.size; ++i) if (result.id == toBeDeleted.get(i)) toBeDeleted.remove(i); }   	return result; }   private static Bitmap loadBitmap(String filename){ Bitmap bitmap = null; InputStream stream = null; try { stream = new FileInputStream(filename); }       catch (Exception e) { try { if (filename.startsWith("assets/")) filename = filename.substring("assets/".length, filename.length); stream = EngineActivity.getInstance.getAssets.open(filename); }           catch (Exception e2) { Log.i("JAVA", "addWaitingTexture file:"+filename+" error: " + e2.toString + "(lehet hogy az expansion fajlban van)"); try { // nincs stream, probaljuk az expansion file-t if (filename.startsWith("assets/")) filename = filename.substring("assets/".length, filename.length); Log.i("JAVA", "fajl betoltese expansion fajlbol:"+filename); stream = ExpansionDownloadService.getFileFromMainExpansion(EngineActivity.getInstance, EngineActivity.xAPKS[0], filename); }           	catch(Exception e3) { Log.e("JAVA","addWaitingTexture file:"+filename+" error: " + e3.toString); }           }        }		bitmap = BitmapFactory.decodeStream(stream); return bitmap; }   private TextureInfo addWaitingTexture(String filename) { TextureInfo info = new TextureInfo; try { Bitmap bitmap = loadBitmap(filename); int textureId = freeTextures.remove(0); if (bitmap != null) Log.i("JAVA", "bitmap loaded: "+filename); else Log.i("JAVA", "bitmap is null! ("+filename+")"); info.width = bitmap.getWidth; info.height = bitmap.getHeight; info.id = textureId; TextureData data = new TextureData; data.filename = filename; data.bitmap = bitmap; data.id = textureId; data.width = bitmap.getWidth; data.height = bitmap.getHeight; waitingTextures.add(data); } catch(Exception e) { Log.i("JAVA", "loadTexture file: "+filename+" error: " + e.toString); }   	return info; }   private void deleteToBeDeleted(GL10 gl){ TextureData data; int id; for (int i = 0;i < toBeDeleted.size; ++i){ data = null; id = toBeDeleted.get(i); for (int j = 0; j < loadedTextures.size; ++j){ if (loadedTextures.get(j).id == id){ data = loadedTextures.get(j); loadedTextures.remove(j); break; }   		}    		if (data == null){ for (int k = 0; k < waitingTextures.size; ++k){ if (waitingTextures.get(k).id == id){ data = waitingTextures.get(k); waitingTextures.remove(k); break; }       		}    		}    		if (data != null) deleteTexture(gl, data); }   	toBeDeleted.clear; System.gc; }   private void deleteTexture(GL10 gl, TextureData data){ if (data.bitmap != null) {   		data.bitmap.recycle; data.bitmap = null; }   	int[] texture = new int[]{data.id}; gl.glDeleteTextures(1, texture, 0); System.gc; Log.i("### JAVA TESZT ###", "delete texture:" + data.filename); }   public static void releaseTexture(int id){ instance.toBeDeleted.add(id); }   public static TextureInfo createTexture(String filename) { return GameRenderer.instance.loadTexture(filename); }   // fuggvenyek a CImageBits-hez // a kis texturakhoz (pár kb-os háttér pixel texturak) (ha nagyobb texturakhoz is kell majd, akkor at kellene irni, hogy ne egyesevel kerdezze le a pixel ertekeket) private static String lastFileName = null; private static Bitmap lastBitmap = null; private static Bitmap getLastBitmap(String filename){ Bitmap bitmap = null; if (lastFileName != null && lastFileName.equals(filename)){ bitmap = lastBitmap; }   	else{ if (lastBitmap != null) lastBitmap.recycle; bitmap = loadBitmap(filename); lastBitmap = bitmap; lastFileName = filename; }   	return bitmap; }   public static int getPixel(String filename, int x, int y){ Bitmap bitmap = getLastBitmap(filename); int color = (bitmap != null) ? bitmap.getPixel(x, y) : 0; color =	(Color.alpha(color) << 24) | (Color.blue(color) << 16) | (Color.green(color) << 8) | Color.red(color);

return color; }   public static int getWidth(String filename){ Bitmap bitmap = getLastBitmap(filename); return (bitmap != null) ? bitmap.getWidth : 0; }   public static int getHeight(String filename){ Bitmap bitmap = getLastBitmap(filename); return (bitmap != null) ? bitmap.getHeight : 0; } }

A translation of the Hungarian text found in the above code: