Android–Encryption Made Easy

Hi,

I am giving you following class that you can embed in your code to encrypt and decrypt. You just need to put a PASSWORD to call its init( ) method.

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
 
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
 
 
public class Encryption {
    // related links http://stackoverflow.com/questions/2256774/android-secretkeyfactory-problems-implementation-not-found
    // http://download.oracle.com/javase/6/docs/technotes/guides/security/SunProviders.html
    // PBEWithMD5AndDES
    private static final String INSTANCE = "PBEWithSHA256And256BitAES-CBC-BC";
    private static final String TAG = "Encryption";
    private static final int SALT_LENGTH     = 10;
    private static final int SALT_ITERATIONS = 10;
    
    private static SecretKey secretKey;
    
    public static CipherOutputStream encryptionWrap(OutputStream os) {
        try {
            final byte salt[] = new byte[SALT_LENGTH];
            new java.security.SecureRandom().nextBytes(salt); // @TEMP
            os.write(salt);
            
            PBEParameterSpec pbeParamSpec = new PBEParameterSpec(salt, SALT_ITERATIONS);
            Cipher c = Cipher.getInstance(INSTANCE);
            c.init(Cipher.ENCRYPT_MODE, secretKey, pbeParamSpec);
    
            return new CipherOutputStream(os, c);
        } catch (Exception e) {
            OpenFeintInternal.log(TAG, e.getMessage());
        }
        return null;
    }
 
    public static CipherInputStream decryptionWrap(InputStream is) {
        try {
            final byte salt[] = new byte[SALT_LENGTH];
            if (is.read(salt) != SALT_LENGTH) throw new Exception("Couldn't read entire salt");
            
            PBEParameterSpec pbeParamSpec = new PBEParameterSpec(salt, SALT_ITERATIONS);
            Cipher c = Cipher.getInstance(INSTANCE);
            c.init(Cipher.DECRYPT_MODE, secretKey, pbeParamSpec);
    
            return new CipherInputStream(is, c);
        } catch (Exception e) {
            OpenFeintInternal.log(TAG, e.getMessage());
        }
        return null;
    }
 
    /*
     * if init return false, then this platform does not support
     * secure data store. then can't not use ofx
     */
    public static boolean init(String password) {
        try {
            PBEKeySpec pbeKeySpec = new PBEKeySpec(password.toCharArray());
            SecretKeyFactory keyFac = SecretKeyFactory.getInstance(INSTANCE);
            secretKey = keyFac.generateSecret(pbeKeySpec);
 
            // try to make an encrypter and decrypter to see if it works.
            byte testString[] = INSTANCE.getBytes(); // just write the name of the cipher we're using
            
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            CipherOutputStream cos = encryptionWrap(baos);
            cos.write(testString);
            cos.close();
            final byte[] encryptedContents = baos.toByteArray();
            if (encryptedContents.length == 0) throw new Exception();
            
            CipherInputStream cis = decryptionWrap(new ByteArrayInputStream(encryptedContents));
            byte decryptedContents[] = Util.toByteArray(cis);
            if (!Arrays.equals(decryptedContents, testString)) throw new Exception();
            
        } catch (Exception e) {
            secretKey = null;
            return false;
        }
        
        return true;
    }
    
    public static boolean initialized() {
        return secretKey != null;
    }
    
    public static InputStream decrypt(File file) throws FileNotFoundException {
        return decryptionWrap(new FileInputStream(file));
    }
    
    public static byte[] decryptFile(String path) throws FileNotFoundException, IOException {
        return Util.toByteArray(decrypt(new File(path)));
    }
    
    public static byte[] decrypt(byte input[]) {
        try {
            return Util.toByteArray(decryptionWrap(new ByteArrayInputStream(input)));
        } catch (Exception e) {
            return null;
        }
    }
    
    public static boolean encrypt(byte[] in, String path) {
        try {
            OutputStream os = encrypt(path);
            os.write(in);
            os.close();
            return true;
        } catch (Exception e) {
            // @TODO cleanup?
        }
        return false;
    }
    
    public static OutputStream encrypt(String path) throws FileNotFoundException {
        return encryptionWrap(new FileOutputStream(new File(path)));
    }
 
    public static byte[] encrypt(byte input[]) {
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            final CipherOutputStream enc = encryptionWrap(baos);
            enc.write(input);
            enc.close();
            return baos.toByteArray();
        } catch (Exception e) {
            return null;
        }
    }
    
}

Usage


if (!Encryption.initialized()) {
            Encryption.init(“Password”);
        }


Encryption.encryptionWrap(oos);


InputStream inn = Encryption.decryptionWrap(is);


Tags:


android, java, encryption, secret key factory problems solved,

Detecting App Installations alternative to IMEI

public class Installation {
    private static String sID = null;
    private static final String INSTALLATION = "INSTALLATION";
 
    public synchronized static String getIdentifier(Context context) {
        if (sID == null) {  
            File installation = new File(context.getFilesDir(), INSTALLATION);
            try {
                if (!installation.exists())
                    writeInstallationFile(installation);
                sID = readInstallationFile(installation);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        return sID;
    }
 
    private static String readInstallationFile(File installation) throws IOException {
        RandomAccessFile f = new RandomAccessFile(installation, "r");//read only mode
        byte[] bytes = new byte[(int) f.length()];
        f.readFully(bytes);        
        f.close();
        return new String(bytes);
    }
 
    private static void writeInstallationFile(File installation) throws IOException {
        FileOutputStream out = new FileOutputStream(installation);
        String id = UUID.randomUUID().toString();
        out.write(id.getBytes());
        out.close();
    }
}


If you are not giving support before Froyo then you can use ANDROID_ID


ANDROID_ID

More specifically, Settings.Secure.ANDROID_ID. This is a 64-bit quantity that is generated and stored when the device first boots. It is reset when the device is wiped.

ANDROID_ID seems a good choice for a unique device identifier. There are downsides: First, it is not 100% reliable on releases of Android prior to 2.2 (“Froyo”). Also, there has been at least one widely-observed bug in a popular handset from a major manufacturer, where every instance has the same ANDROID_ID.

 


 


POST URL: http://android-developers.blogspot.com/2011/03/identifying-app-installations.html


 


tags: android, unique, identifier, alternative, IMEI, android_id, android id

AndEngine Menu Scrolling Example

AndEngine Menu Scroll Example
//VERSION # 1
package dk.dionysus.hjarl;
 
import java.util.ArrayList;
import java.util.List;
 
import org.anddev.andengine.engine.Engine;
import org.anddev.andengine.engine.camera.Camera;
import org.anddev.andengine.engine.camera.hud.HUD;
import org.anddev.andengine.engine.options.EngineOptions;
import org.anddev.andengine.engine.options.EngineOptions.ScreenOrientation;
import org.anddev.andengine.engine.options.resolutionpolicy.FillResolutionPolicy;
import org.anddev.andengine.entity.primitive.Rectangle;
import org.anddev.andengine.entity.scene.Scene;
import org.anddev.andengine.entity.scene.Scene.IOnSceneTouchListener;
import org.anddev.andengine.entity.scene.background.ColorBackground;
import org.anddev.andengine.entity.sprite.Sprite;
import org.anddev.andengine.entity.util.FPSLogger;
import org.anddev.andengine.input.touch.TouchEvent;
import org.anddev.andengine.input.touch.detector.ClickDetector;
import org.anddev.andengine.input.touch.detector.ClickDetector.IClickDetectorListener;
import org.anddev.andengine.input.touch.detector.ScrollDetector;
import org.anddev.andengine.input.touch.detector.ScrollDetector.IScrollDetectorListener;
import org.anddev.andengine.input.touch.detector.SurfaceScrollDetector;
import org.anddev.andengine.opengl.font.Font;
import org.anddev.andengine.opengl.font.FontFactory;
import org.anddev.andengine.opengl.texture.TextureOptions;
import org.anddev.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlas;
import org.anddev.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlasTextureRegionFactory;
import org.anddev.andengine.opengl.texture.region.TextureRegion;
import org.anddev.andengine.ui.activity.BaseGameActivity;
 
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Color;
import android.view.KeyEvent;
import android.widget.Toast;
 
 
/**
 * 
 * @author Knoll Florian
 * @email myfknoll@gmail.com
 * @since 28.02.2012
 * @author Kasper Olesen
 * @website http://dionysus.dk/devstuff
 *
 */
public class ScrollMenu extends BaseGameActivity implements IScrollDetectorListener, IOnSceneTouchListener, IClickDetectorListener {
       
        // ===========================================================
        // Constants
        // ===========================================================
        protected static int CAMERA_WIDTH = 480;
        protected static int CAMERA_HEIGHT = 320;
 
        protected static int FONT_SIZE = 28;
        protected static int PADDING = 50;
        
        protected static int MENUITEMS = 7;
        
 
        // ===========================================================
        // Fields
        // ===========================================================
        private Scene mScene;
        private Camera mCamera;
 
        private Font mFont; 
        private BitmapTextureAtlas mFontTexture;     
        
        private BitmapTextureAtlas mMenuTextureAtlas;        
        private TextureRegion mMenuLeftTextureRegion;
        private TextureRegion mMenuRightTextureRegion;
        
        private BitmapTextureAtlas BackgroundTexture;
        private TextureRegion BackgroundTextureRegion;
        private Sprite background;
        
        private BitmapTextureAtlas TitleTexture;
        private TextureRegion TitleTextureRegion;
        private Sprite title;
        
        
        HUD hud = new HUD();
        
        private Sprite menuleft;
        private Sprite menuright;
 
        // Scrolling
        private SurfaceScrollDetector mScrollDetector;
        private ClickDetector mClickDetector;
 
        private float mMinX = 0;
        private float mMaxX = 0;
        private float mCurrentX = 0;
        private int iItemClicked = -1;
        
        private Rectangle scrollBar;        
        private List<TextureRegion> columns = new ArrayList<TextureRegion>();
 
        // ===========================================================
        // Constructors
        // ===========================================================
 
        // ===========================================================
        // Getter & Setter
        // ===========================================================
 
        // ===========================================================
        // Methods for/from SuperClass/Interfaces
        // ===========================================================
 
        @Override
        public void onLoadResources() {
                // Paths
                FontFactory.setAssetBasePath("font/");
                BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("gfx/");
 
                // Font
                this.mFontTexture = new BitmapTextureAtlas(256, 256);
                this.mFont = FontFactory.createFromAsset(this.mFontTexture, this, "DIRTYDOZ.TTF", FONT_SIZE, true, Color.RED);
                this.mEngine.getTextureManager().loadTextures(this.mFontTexture);
                this.mEngine.getFontManager().loadFonts(this.mFont);
                
                this.BackgroundTexture = new BitmapTextureAtlas(1024, 1024, TextureOptions.REPEATING_BILINEAR_PREMULTIPLYALPHA);
                this.BackgroundTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(this.BackgroundTexture, this, "baggrund.jpg", 0, 0);
                this.TitleTexture = new BitmapTextureAtlas(512, 512, TextureOptions.REPEATING_BILINEAR_PREMULTIPLYALPHA);
                this.TitleTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(this.TitleTexture, this, "menu/title.png", 0, 0);
                
                //Images for the menu
                for (int i = 0; i < MENUITEMS; i++) {                
                    BitmapTextureAtlas mMenuBitmapTextureAtlas = new BitmapTextureAtlas(256,256, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
                    TextureRegion mMenuTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(mMenuBitmapTextureAtlas, this, "menu/menu"+i+".png", 0, 0);
                    
                    this.mEngine.getTextureManager().loadTexture(mMenuBitmapTextureAtlas);
                    columns.add(mMenuTextureRegion);
                    
                    
                }
                
                
                //Textures for menu arrows
                this.mMenuTextureAtlas = new BitmapTextureAtlas(128,128, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
                this.mMenuLeftTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(mMenuTextureAtlas, this, "menu/menu_left.png", 0, 0);
                this.mMenuRightTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(mMenuTextureAtlas, this, "menu/menu_right.png",64, 0);
                this.mEngine.getTextureManager().loadTextures(mMenuTextureAtlas, BackgroundTexture, TitleTexture);
          
        }
 
        @Override
        public Engine onLoadEngine() {
                this.mCamera = new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
 
                final EngineOptions engineOptions = new EngineOptions(true, ScreenOrientation.LANDSCAPE, new FillResolutionPolicy(), this.mCamera);
                engineOptions.getTouchOptions().setRunOnUpdateThread(true);
 
                final Engine engine = new Engine(engineOptions);
                return engine;
        }
 
        @Override
        public Scene onLoadScene() {
                this.mEngine.registerUpdateHandler(new FPSLogger());
 
                this.mScene = new Scene();
                this.mScene.setBackground(new ColorBackground(0, 0, 0));
               
                int x = (CAMERA_WIDTH - this.BackgroundTextureRegion.getWidth()) / 2;
                int y = (CAMERA_HEIGHT - this.BackgroundTextureRegion.getHeight()) / 2;
                
                background = new Sprite(x, y, this.BackgroundTextureRegion);
                background.setScale(1.25f);
                mScene.attachChild(background);
                
                
                x = (CAMERA_WIDTH - this.TitleTextureRegion.getWidth()) / 2;
                y = (this.TitleTextureRegion.getHeight() / 2);
                
                title = new Sprite(x, y, this.TitleTextureRegion);
                title.setScale(0.8f);
                mScene.attachChild(title);
                
                
                this.mScrollDetector = new SurfaceScrollDetector(this);
                this.mClickDetector = new ClickDetector(this);
 
                this.mScene.setOnSceneTouchListener(this);
                this.mScene.setTouchAreaBindingEnabled(true);
                this.mScene.setOnSceneTouchListenerBindingEnabled(true);
 
                CreateMenuBoxes();
 
                return this.mScene;
 
        }
 
        @Override
        public boolean onSceneTouchEvent(final Scene pScene, final TouchEvent pSceneTouchEvent) {
                this.mClickDetector.onTouchEvent(pSceneTouchEvent);
                this.mScrollDetector.onTouchEvent(pSceneTouchEvent);
                return true;
        }
 
        @Override
        public void onScroll(final ScrollDetector pScollDetector, final TouchEvent pTouchEvent, final float pDistanceX, final float pDistanceY) {
 
                //Disable the menu arrows left and right (15px padding)
                if(mCamera.getMinX()<=15)
                     menuleft.setVisible(false);
                 else
                     menuleft.setVisible(true);
                 
                 if(mCamera.getMinX()>mMaxX-15)
                     menuright.setVisible(false);
                 else
                     menuright.setVisible(true);
                     
                //Return if ends are reached
                if ( ((mCurrentX - pDistanceX) < mMinX)  ){                    
                    return;
                }else if((mCurrentX - pDistanceX) > mMaxX){
                    
                    return;
                }
                
                //Center camera to the current point
                this.mCamera.offsetCenter(-pDistanceX,0 );
                mCurrentX -= pDistanceX;
                
               
                //Set the scrollbar with the camera
                float tempX =mCamera.getCenterX()-CAMERA_WIDTH/2;
                // add the % part to the position
                tempX+= (tempX/(mMaxX+CAMERA_WIDTH))*CAMERA_WIDTH;      
                //set the position
                scrollBar.setPosition(tempX, scrollBar.getY());
                
                //set the arrows for left and right
                menuright.setPosition(mCamera.getCenterX()+CAMERA_WIDTH/2-menuright.getWidth(),menuright.getY());
                menuleft.setPosition(mCamera.getCenterX()-CAMERA_WIDTH/2,menuleft.getY());
                background.setPosition(mCamera.getCenterX()-background.getWidth() / 2,background.getY());
                title.setPosition(mCamera.getCenterX()-title.getWidth() / 2,title.getY());
                
              
                
                //Because Camera can have negativ X values, so set to 0
                if(this.mCamera.getMinX()<0){
                    this.mCamera.offsetCenter(0,0 );
                    mCurrentX=0;
                }
                
 
        }
 
        @Override
        public void onClick(ClickDetector pClickDetector, TouchEvent pTouchEvent) {
                loadLevel(iItemClicked);
        };
 
        // ===========================================================
        // Methods
        // ===========================================================
        
        private void CreateMenuBoxes() {
            
             int spriteX = PADDING;
             int spriteY = PADDING;
             
             //current item counter
             int iItem = 1;
 
             for (int x = 0; x < columns.size(); x++) {
                 
                 //On Touch, save the clicked item in case it's a click and not a scroll.
                 final int itemToLoad = iItem;
                 
                 Sprite sprite = new Sprite(spriteX,spriteY + CAMERA_HEIGHT / 4 - 15,columns.get(x)){
                     
                     public boolean onAreaTouched(final TouchEvent pSceneTouchEvent, final float pTouchAreaLocalX, final float pTouchAreaLocalY) {
                         iItemClicked = itemToLoad;
                         return false;
                     }                     
                 };                 
                 iItem++;
                
                 
                 this.mScene.attachChild(sprite);                 
                 this.mScene.registerTouchArea(sprite);                 
   
                 spriteX += 20 + PADDING+sprite.getWidth();
            }
            
             mMaxX = spriteX - CAMERA_WIDTH;
             
             //set the size of the scrollbar
             float scrollbarsize = CAMERA_WIDTH/((mMaxX+CAMERA_WIDTH)/CAMERA_WIDTH);
             scrollBar = new Rectangle(0,CAMERA_HEIGHT-20,scrollbarsize, 20);
             scrollBar.setColor(1,0,0);
             this.mScene.attachChild(scrollBar);
             
             menuleft = new Sprite(0,CAMERA_HEIGHT/2-mMenuLeftTextureRegion.getHeight()/2,mMenuLeftTextureRegion);
             menuright = new Sprite(CAMERA_WIDTH-mMenuRightTextureRegion.getWidth(),CAMERA_HEIGHT/2-mMenuRightTextureRegion.getHeight()/2,mMenuRightTextureRegion);
             this.mScene.attachChild(menuright);
             menuleft.setVisible(false);
             this.mScene.attachChild(menuleft);
        }
        
        
 
        @Override
        public void onLoadComplete() {
 
        }
 
        //Here is where you call the item load.
        private void loadLevel(final int iLevel) {
                if (iLevel != -1) {
                        runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                            
                                        Toast.makeText(ScrollMenu.this, "Load Item" + String.valueOf(iLevel), Toast.LENGTH_SHORT).show();
                                        if (iLevel == 1) {
                                            Intent game = new Intent(ScrollMenu.this, HjarlGameActivity.class); // When clicked, run HjarlGameActivity
                                            startActivity(game); // runs the game intent, which targets the HjarlGameActivity
                                        }
                                        if (iLevel == 2) {
                                            Intent game = new Intent(ScrollMenu.this, RacerGameActivity.class); // When clicked, run RacerGameActivity
                                            startActivity(game); // runs the game intent, which targets the RacerGameActivity
                                        }
                                        if (iLevel == 3) {
                                            Intent control = new Intent(ScrollMenu.this, OSControlSetup.class);
                                            startActivity(control);
                                        }
                                        if (iLevel == 4) {
                                            Intent game = new Intent(ScrollMenu.this, OptionsActivity.class);
                                            startActivity(game);
                                        }
                                        if (iLevel == 5) {
                                            Intent help = new Intent(ScrollMenu.this, HelpActivity.class);
                                            startActivity(help);
                                        }
                                        if (iLevel == 6) {
                                            Intent help = new Intent(ScrollMenu.this, MovingBallExample.class);
                                            startActivity(help);
                                        }
                                        if (iLevel == 7) {
                                            Intent help = new Intent(ScrollMenu.this, MovingBallExample.class);
                                            startActivity(help);
                                        }
                                        if (iLevel == 8) {
                                            Intent help = new Intent(ScrollMenu.this, MovingBallExample.class);
                                            startActivity(help);
                                        }
                                        iItemClicked = -1;
                                }
                        });
                }
        }
        @Override
        public boolean onKeyDown(final int pKeyCode, final KeyEvent pEvent) { 
            // Maybe the user decides to use Android buttons instead? Lets try to stop the user from quitting with the back button, by accident.
 
            if (pKeyCode == KeyEvent.KEYCODE_BACK
                    && pEvent.getAction() == KeyEvent.ACTION_DOWN) { // Check if the back button is being pressed
                showExitDialog(); // Run the showExitDialog.
                return true;
            }
            
            return super.onKeyDown(pKeyCode, pEvent);
        }
        
        public void showExitDialog() { // Here a showExitDialog is prepared. Its a kind of submenu, but since it is very simple its all done without XML
            AlertDialog.Builder builder = new AlertDialog.Builder(ScrollMenu.this); // Making an AlerDialog, its an Android feature
            builder.setMessage("Are you sure you want to exit?")
                    .setCancelable(false)
                    .setTitle("EXIT")
                    .setPositiveButton("Yes",
                            new DialogInterface.OnClickListener() {
                                public void onClick(DialogInterface dialog, int id) {
                                    ScrollMenu.this.finish(); // if yes is clicked, close this class. If this class had been opened by another class, we would return to that class.
                                }
                            })
                    .setNegativeButton("No", new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int id) {
                            dialog.cancel(); // Of the NO choice is clicked, we cancel the AlertDialog and go back to Menuactivity2
                        }
                    });
 
            AlertDialog alert = builder.create(); // This takes the AlertDialog and prepares it
            alert.setIcon(R.drawable.icon); // Puts the application icon in the drawable folder into the dialog
            alert.show(); // shows the alert dialog
        
        }
}
 

 



//Version 0
import java.util.ArrayList;
import java.util.List;
 
import org.anddev.andengine.engine.Engine;
import org.anddev.andengine.engine.camera.Camera;
import org.anddev.andengine.engine.options.EngineOptions;
import org.anddev.andengine.engine.options.EngineOptions.ScreenOrientation;
import org.anddev.andengine.engine.options.resolutionpolicy.FillResolutionPolicy;
import org.anddev.andengine.entity.primitive.Rectangle;
import org.anddev.andengine.entity.scene.Scene;
import org.anddev.andengine.entity.scene.Scene.IOnSceneTouchListener;
import org.anddev.andengine.entity.scene.background.ColorBackground;
import org.anddev.andengine.entity.sprite.Sprite;
import org.anddev.andengine.entity.util.FPSLogger;
import org.anddev.andengine.input.touch.TouchEvent;
import org.anddev.andengine.input.touch.detector.ClickDetector;
import org.anddev.andengine.input.touch.detector.ClickDetector.IClickDetectorListener;
import org.anddev.andengine.input.touch.detector.ScrollDetector;
import org.anddev.andengine.input.touch.detector.ScrollDetector.IScrollDetectorListener;
import org.anddev.andengine.input.touch.detector.SurfaceScrollDetector;
import org.anddev.andengine.opengl.font.Font;
import org.anddev.andengine.opengl.font.FontFactory;
import org.anddev.andengine.opengl.texture.TextureOptions;
import org.anddev.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlas;
import org.anddev.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlasTextureRegionFactory;
import org.anddev.andengine.opengl.texture.region.TextureRegion;
import org.anddev.andengine.ui.activity.BaseGameActivity;
 
import android.content.Intent;
import android.graphics.Color;
import android.widget.Toast;
 
 
/**
 * 
 * @author Knoll Florian
 * @email myfknoll@gmail.com
 *
 */
public class MenuScrollerActivity extends BaseGameActivity implements IScrollDetectorListener, IOnSceneTouchListener, IClickDetectorListener {
       
        // ===========================================================
        // Constants
        // ===========================================================
        protected static int CAMERA_WIDTH = 480;
        protected static int CAMERA_HEIGHT = 320;
 
        protected static int FONT_SIZE = 24;
        protected static int PADDING = 50;
        
        protected static int MENUITEMS = 7;
        
 
        // ===========================================================
        // Fields
        // ===========================================================
        private Scene mScene;
        private Camera mCamera;
 
        private Font mFont; 
        private BitmapTextureAtlas mFontTexture;     
        
        private BitmapTextureAtlas mMenuTextureAtlas;        
        private TextureRegion mMenuLeftTextureRegion;
        private TextureRegion mMenuRightTextureRegion;
        
        private Sprite menuleft;
        private Sprite menuright;
 
        // Scrolling
        private SurfaceScrollDetector mScrollDetector;
        private ClickDetector mClickDetector;
 
        private float mMinX = 0;
        private float mMaxX = 0;
        private float mCurrentX = 0;
        private int iItemClicked = -1;
        
        private Rectangle scrollBar;        
        private List<TextureRegion> columns = new ArrayList<TextureRegion>();
 
        // ===========================================================
        // Constructors
        // ===========================================================
 
        // ===========================================================
        // Getter & Setter
        // ===========================================================
 
        // ===========================================================
        // Methods for/from SuperClass/Interfaces
        // ===========================================================
 
        @Override
        public void onLoadResources() {
                // Paths
                FontFactory.setAssetBasePath("font/");
                BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("gfx/");
 
                // Font
                this.mFontTexture = new BitmapTextureAtlas(256, 256);
                this.mFont = FontFactory.createFromAsset(this.mFontTexture, this, "Plok.TTF", FONT_SIZE, true, Color.BLACK);
                this.mEngine.getTextureManager().loadTextures(this.mFontTexture);
                this.mEngine.getFontManager().loadFonts(this.mFont);
                
                //Images for the menu
                for (int i = 0; i < MENUITEMS; i++) {                
                    BitmapTextureAtlas mMenuBitmapTextureAtlas = new BitmapTextureAtlas(256,256, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
                    TextureRegion mMenuTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(mMenuBitmapTextureAtlas, this, "menu"+i+".png", 0, 0);
                    
                    this.mEngine.getTextureManager().loadTexture(mMenuBitmapTextureAtlas);
                    columns.add(mMenuTextureRegion);
                    
                    
                }
                //Textures for menu arrows
                this.mMenuTextureAtlas = new BitmapTextureAtlas(128,128, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
                this.mMenuLeftTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(mMenuTextureAtlas, this, "menu_left.png", 0, 0);
                this.mMenuRightTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(mMenuTextureAtlas, this, "menu_right.png",64, 0);
                this.mEngine.getTextureManager().loadTexture(mMenuTextureAtlas);
          
        }
 
        @Override
        public Engine onLoadEngine() {
                this.mCamera = new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
 
                final EngineOptions engineOptions = new EngineOptions(true, ScreenOrientation.LANDSCAPE, new FillResolutionPolicy(), this.mCamera);
                engineOptions.getTouchOptions().setRunOnUpdateThread(true);
 
                final Engine engine = new Engine(engineOptions);
                return engine;
        }
 
        @Override
        public Scene onLoadScene() {
                this.mEngine.registerUpdateHandler(new FPSLogger());
 
                this.mScene = new Scene();
                this.mScene.setBackground(new ColorBackground(0, 0, 0));
               
                this.mScrollDetector = new SurfaceScrollDetector(this);
                this.mClickDetector = new ClickDetector(this);
 
                this.mScene.setOnSceneTouchListener(this);
                this.mScene.setTouchAreaBindingEnabled(true);
                this.mScene.setOnSceneTouchListenerBindingEnabled(true);
 
                CreateMenuBoxes();
 
                return this.mScene;
 
        }
 
        @Override
        public boolean onSceneTouchEvent(final Scene pScene, final TouchEvent pSceneTouchEvent) {
                this.mClickDetector.onTouchEvent(pSceneTouchEvent);
                this.mScrollDetector.onTouchEvent(pSceneTouchEvent);
                return true;
        }
 
        @Override
        public void onScroll(final ScrollDetector pScollDetector, final TouchEvent pTouchEvent, final float pDistanceX, final float pDistanceY) {
 
                //Disable the menu arrows left and right (15px padding)
                if(mCamera.getMinX()<=15)
                     menuleft.setVisible(false);
                 else
                     menuleft.setVisible(true);
                 
                 if(mCamera.getMinX()>mMaxX-15)
                     menuright.setVisible(false);
                 else
                     menuright.setVisible(true);
                     
                //Return if ends are reached
                if ( ((mCurrentX - pDistanceX) < mMinX)  ){                    
                    return;
                }else if((mCurrentX - pDistanceX) > mMaxX){
                    
                    return;
                }
                
                //Center camera to the current point
                this.mCamera.offsetCenter(-pDistanceX,0 );
                mCurrentX -= pDistanceX;
                    
               
                //Set the scrollbar with the camera
                float tempX =mCamera.getCenterX()-CAMERA_WIDTH/2;
                // add the % part to the position
                tempX+= (tempX/(mMaxX+CAMERA_WIDTH))*CAMERA_WIDTH;      
                //set the position
                scrollBar.setPosition(tempX, scrollBar.getY());
                
                //set the arrows for left and right
                menuright.setPosition(mCamera.getCenterX()+CAMERA_WIDTH/2-menuright.getWidth(),menuright.getY());
                menuleft.setPosition(mCamera.getCenterX()-CAMERA_WIDTH/2,menuleft.getY());
                
              
                
                //Because Camera can have negativ X values, so set to 0
                if(this.mCamera.getMinX()<0){
                    this.mCamera.offsetCenter(0,0 );
                    mCurrentX=0;
                }
                
 
        }
 
        @Override
        public void onClick(ClickDetector pClickDetector, TouchEvent pTouchEvent) {
                loadLevel(iItemClicked);
        };
 
        // ===========================================================
        // Methods
        // ===========================================================
        
        private void CreateMenuBoxes() {
            
             int spriteX = PADDING;
             int spriteY = PADDING;
             
             //current item counter
             int iItem = 1;
 
             for (int x = 0; x < columns.size(); x++) {
                 
                 //On Touch, save the clicked item in case it's a click and not a scroll.
                 final int itemToLoad = iItem;
                 
                 Sprite sprite = new Sprite(spriteX,spriteY,columns.get(x)){
                     
                     public boolean onAreaTouched(final TouchEvent pSceneTouchEvent, final float pTouchAreaLocalX, final float pTouchAreaLocalY) {
                         iItemClicked = itemToLoad;
                         return false;
                     }                     
                 };                 
                 iItem++;
                
                 
                 this.mScene.attachChild(sprite);                 
                 this.mScene.registerTouchArea(sprite);                 
   
                 spriteX += 20 + PADDING+sprite.getWidth();
            }
            
             mMaxX = spriteX - CAMERA_WIDTH;
             
             //set the size of the scrollbar
             float scrollbarsize = CAMERA_WIDTH/((mMaxX+CAMERA_WIDTH)/CAMERA_WIDTH);
             scrollBar = new Rectangle(0,CAMERA_HEIGHT-20,scrollbarsize, 20);
             scrollBar.setColor(1,0,0);
             this.mScene.attachChild(scrollBar);
             
             menuleft = new Sprite(0,CAMERA_HEIGHT/2-mMenuLeftTextureRegion.getHeight()/2,mMenuLeftTextureRegion);
             menuright = new Sprite(CAMERA_WIDTH-mMenuRightTextureRegion.getWidth(),CAMERA_HEIGHT/2-mMenuRightTextureRegion.getHeight()/2,mMenuRightTextureRegion);
             this.mScene.attachChild(menuright);
             menuleft.setVisible(false);
             this.mScene.attachChild(menuleft);
        }
        
        
 
        @Override
        public void onLoadComplete() {
 
        }
 
        //Here is where you call the item load.
        private void loadLevel(final int iLevel) {
                if (iLevel != -1) {
                        runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                            
                                        Toast.makeText(MenuScrollerActivity.this, "Load Item" + String.valueOf(iLevel), Toast.LENGTH_SHORT).show();
                                        iItemClicked = -1;
                                }
                        });
                }
        }
}