We just released a Feb. 5 '89 prototype of DuckTales for the NES!
If you'd like to support our preservation efforts (and this wasn't cheap), please consider donating or supporting us on Patreon. Thank you!

Nyan Cat: Lost In Space (Android)

From The Cutting Room Floor
Jump to navigation Jump to search

Title Screen

Nyan Cat: Lost In Space

Developer: isTom Games
Platform: Android
Released internationally: December 19, 2012


SourceIcon.png This game has uncompiled source code.


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<String> imageNames = new Vector<String>();
	                
	                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("<t>") + 3;
	                    	endIndex = line.indexOf("</t>");
	                    	
	                    	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<TouchEvent> mTouchEvents = new Vector<TouchEvent>();
	
	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<Integer> freeTextures = new Vector<Integer>();
	private Vector<TextureData> loadedTextures = new Vector<TextureData>();
	private Vector<TextureData> waitingTextures = new Vector<TextureData>();
	
	private Vector<Integer> toBeDeleted = new Vector<Integer>();
	
	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:

Hungarian: English:
expansion download default ertekek expansion download default values
az alap ertekekhez (a PackageInfo-bol kerdezi egyebkent) for the default values (otherwise it queries PackageInfo)
reklamok ads
kell-e az expansion file? do we need the expansion file?
FONTOS! : jelenleg az utils.cpp-ben a GetDeviceFilenName() ugyanezt hasznalja,

hogy eldontse melyik textura kell, ha az valtozik ezt is valtoztatni kell

IMPORTANT! : currently GetDeviceFilenName() in utils.cpp uses this

to decide which texture is needed, if that changes this needs to be changed too

igen, expansion file ellenorzese yes, verifying expansion file
nem, kis texturak hasznalata no, use small textures
c++-bol hivodnak called from c++
letoltes idejenek a beleirasa write time of download
ezt adja vissza, mikor valaki texturat akar betölteni this gets returned when someone wants to load a texture
a ha keres erkezik a textura betoltesre, akkor toroljuk ki a torlendok listajarol if a request to load a texture arrives, remove it from the to-be-deleted list
(lehet hogy az expansion fajlban van) (it's possible that it's in the expansion file)
### JAVA TESZT ### ### JAVA TEST ###
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)

functions for CImageBits

for small textures (background pixel textures weighing a few kilobytes) (if needed for bigger textures, it should be rewritten so that it doesn't read pixel values one by one)