Thursday 4 April 2013

IndexableListview Example

Create a java file name CustomListIndex.java
=============================
package com.index.table;

import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.view.Display;
import android.view.GestureDetector;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.ListView;
import android.widget.TextView;

import com.index.table.to.Book;

public class CustomListIndex extends Activity {

    private static final String TAG = CustomListIndex.class.getSimpleName();

    protected GestureDetector mGestureDetector;

    protected Vector<Book> userVector;

    protected int totalListSize = 0;
    
    /**
     * list with items for side index
     */
    private ArrayList<Object[]> indexList = null;

    /**
     * list with row number for side index
     */
    protected List<Integer> dealList = new ArrayList<Integer>();

    /**
     * height of left side index
     */
    protected int sideIndexHeight;

    /**
     * number of items in the side index
     */
    private int indexListSize;

    /**
     * x and y coordinates within our side index
     */
    protected static float sideIndexX;
    protected static float sideIndexY;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        Log.i(TAG, TAG);
    }

    /**
     * displayListItem is method used to display the row from the list on scrool
     * or touch.
     */
    public void displayListItem() {
        
        // compute number of pixels for every side index item
        double pixelPerIndexItem = (double) sideIndexHeight / indexListSize;

        // compute the item index for given event position belongs to
        int itemPosition = (int) (sideIndexY / pixelPerIndexItem);

        ListView listView = (ListView) findViewById(R.id.booksLV);

        if (itemPosition < 0) {
            itemPosition = 0;
        } else if (itemPosition >= dealList.size()) {
            itemPosition = dealList.size() - 1;
        }

        int listLocation = dealList.get(itemPosition) + itemPosition;

        if (listLocation > totalListSize) {
            listLocation = totalListSize;
        }

        listView.setSelection(listLocation);
    }

    /**
     * getListArrayIndex consists of index details, to navigate through out the index.
     * 
     * @param strArr , index values
     * @return ArrayList object
     */
    private ArrayList<Object[]> getListArrayIndex(String[] strArr) {
        ArrayList<Object[]> tmpIndexList = new ArrayList<Object[]>();
        Object[] tmpIndexItem = null;

        int tmpPos = 0;
        String tmpLetter = "";
        String currentLetter = null;

        for (int j = 0; j < strArr.length; j++) {
            currentLetter = strArr[j];

            // every time new letters comes
            // save it to index list
            if (!currentLetter.equals(tmpLetter)) {
                tmpIndexItem = new Object[3];
                tmpIndexItem[0] = tmpLetter;
                tmpIndexItem[1] = tmpPos - 1;
                tmpIndexItem[2] = j - 1;

                tmpLetter = currentLetter;
                tmpPos = j + 1;
                tmpIndexList.add(tmpIndexItem);
            }
        }

        // save also last letter
        tmpIndexItem = new Object[3];
        tmpIndexItem[0] = tmpLetter;
        tmpIndexItem[1] = tmpPos - 1;
        tmpIndexItem[2] = strArr.length - 1;
        tmpIndexList.add(tmpIndexItem);

        // and remove first temporary empty entry
        if (tmpIndexList != null && tmpIndexList.size() > 0) {
            tmpIndexList.remove(0);
        }

        return tmpIndexList;
    }

    /**
     * getDisplayListOnChange method display the list from the index.
     * @param displayScreen , specify which screen it belongs
     */
    public void getDisplayListOnChange() 
    {
        LinearLayout sideIndex = (LinearLayout) findViewById(R.id.sideIndex);
        sideIndexHeight = sideIndex.getHeight();
        
        if (sideIndexHeight == 0) {
            Display display = getWindowManager().getDefaultDisplay();
            sideIndexHeight = display.getHeight();
            // Navigation Bar + Tab space comes approximately 80dip
        }    
        sideIndex.removeAllViews();
        /**
         * temporary TextView for every visible item
         */
        TextView tmpTV = null;

        /**
         * we will create the index list
         */
        String[] strArr = new String[userVector.size()];

        int j = 0;
        for (Book user : userVector) {
            strArr[j++] = user.getTitle().substring(0, 1);
        }

        indexList = getListArrayIndex(strArr);

        /**
         * number of items in the index List
         */
        indexListSize = indexList.size();

        /**
         * maximal number of item, which could be displayed
         */
        int indexMaxSize = (int) Math.floor(sideIndexHeight / 25);

        int tmpIndexListSize = indexListSize;

//      /**
//       * handling that case when indexListSize > indexMaxSize, if true display
//       * the half of the side index otherwise full index.
//       */
//      while (tmpIndexListSize > indexMaxSize) {
//          tmpIndexListSize = tmpIndexListSize / 2;
//      }

        /**
         * computing delta (only a part of items will be displayed to save a
         * place, without compact
         */
        double delta = indexListSize / tmpIndexListSize;

        String tmpLetter = null;
        Object[] tmpIndexItem = null;

        for (double i = 1; i <= indexListSize; i = i + delta) 
        {
            tmpIndexItem = indexList.get((int) i - 1);
            tmpLetter = tmpIndexItem[0].toString();
            tmpTV = new TextView(this);
            tmpTV.setTextColor(Color.parseColor("#000000"));
            tmpTV.setText(tmpLetter);
            tmpTV.setGravity(Gravity.CENTER);
            LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT,
                    LayoutParams.WRAP_CONTENT, 1);
            tmpTV.setLayoutParams(params);
            sideIndex.addView(tmpTV);
        }

        sideIndex.setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                sideIndexX = event.getX();
                sideIndexY = event.getY();
                System.out.println("sideIndexX=="+sideIndexX);
                System.out.println("sideIndexY=="+sideIndexY);
                displayListItem();

                return false;
            }
        });
    }

    protected OnClickListener onClicked = new OnClickListener() {
        
        @Override
        public void onClick(View v) {
        }
    };
}
===============================================
Second java file named IndexTableActivity.java

package com.index.table;

import java.util.Vector;

import android.os.Bundle;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.widget.LinearLayout;
import android.widget.ListView;

import com.index.table.service.UserService;
import com.index.table.to.Book;

public class IndexTableActivity extends CustomListIndex
{
    private ListView booksLV;
   
    private UserListAdapter userListAdapter;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        booksLV = (ListView)findViewById(R.id.booksLV);
       
        userVector = UserService.getUserList();
       
        Vector<Book> subsidiesList = getIndexedBooks(userVector);
        totalListSize = subsidiesList.size();
       
        userListAdapter = new UserListAdapter(this, subsidiesList);
        booksLV.setAdapter(userListAdapter);
       
        LinearLayout sideIndex = (LinearLayout) findViewById(R.id.sideIndex);
        sideIndex.setOnClickListener(onClicked);
        sideIndexHeight = sideIndex.getHeight();
        mGestureDetector = new GestureDetector(this,
                new ListIndexGestureListener());
    }
   
    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);

        getDisplayListOnChange();
    }
   
   
    private Vector<Book> getIndexedBooks(
            Vector<Book> booksVector) {
       
        //Retrieve it from DB in shorting order
       
        Vector<Book> v = new Vector<Book>();
        //Add default item
     
        String idx1 = null;
        String idx2 = null;
        for (int i = 0; i < booksVector.size(); i++) {
            Book temp = booksVector.elementAt(i);
            //Insert the alphabets
            idx1 = (temp.getTitle().substring(0, 1)).toLowerCase();
            if(!idx1.equalsIgnoreCase(idx2))
            {
                v.add(new Book(idx1.toUpperCase(), "", "" , "" , ""));
                idx2 = idx1;
                dealList.add(i);
            }
            v.add(temp);
        }      
        return v;
    }
   
    /**
     * ListIndexGestureListener method gets the list on scroll.
     */
    private class ListIndexGestureListener extends
            GestureDetector.SimpleOnGestureListener {
        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2,
                float distanceX, float distanceY) {
            /**
             * we know already coordinates of first touch we know as well a
             * scroll distance
             */
            sideIndexX = sideIndexX - distanceX;
            sideIndexY = sideIndexY - distanceY;

            /**
             * when the user scrolls within our side index, we can show for
             * every position in it a proper item in the list
             */
            if (sideIndexX >= 0 && sideIndexY >= 0) {
                displayListItem();
            }
            return super.onScroll(e1, e2, distanceX, distanceY);
        }
    }
}
===============================================

Third java file named UserListAdapter.java
package com.index.table;

import java.util.Vector;

import android.app.Activity;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.index.table.to.Book;

public class UserListAdapter extends BaseAdapter {

    private static final String TAG = UserListAdapter.class.getName();
    private Activity activity;
    private Vector<Book> items;
   
    public UserListAdapter(Activity activity,
            Vector<Book> items) {
        Log.i(TAG, TAG);
        this.activity = activity;
        this.items = items;
    }
    public View getView(final int position, View convertView, ViewGroup parent) {
        ViewHolder holder;
        if (convertView == null) {
           
            LayoutInflater inflater = activity.getLayoutInflater();
            convertView = inflater.inflate(R.layout.listrow_user, null);
            holder = new ViewHolder();

            holder.name = (TextView) convertView.findViewById(R.id.nameTV);
            holder.headingLL = (LinearLayout)convertView.findViewById(R.id.headingLL);
            holder.headingTV = (TextView)convertView.findViewById(R.id.headingTV);
            holder.nameLL = (LinearLayout)convertView.findViewById(R.id.nameLL);
            convertView.setTag(holder);

        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        if (position < items.size()) {

            final Book book = items.get(position);
            if (book != null
                    && (book.getTitle().length() == 1))
            {
                holder.nameLL.setVisibility(View.GONE);
                holder.headingLL.setVisibility(View.VISIBLE);
                holder.headingTV.setText(book.getTitle());
                holder.headingLL.setBackgroundColor(android.R.color.black);
            }
            else
            {
                holder.nameLL.setVisibility(View.VISIBLE);
                holder.headingLL.setVisibility(View.GONE);
                holder.name.setText(book.getTitle());
               
                View ll = (LinearLayout)holder.name.getParent();
                ll.setFocusable(true);
                ll.setSelected(true);
                ll.setOnClickListener(new OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        Toast.makeText(activity.getApplicationContext(), "Clicked on " + book.getTitle(), Toast.LENGTH_SHORT).show();
                    }
                });
            }
        }
        return convertView;
    }

    private static class ViewHolder {
        TextView name,headingTV;
        LinearLayout nameLL,headingLL;
    }

    @Override
    public int getCount() {
        return items.size();
    }

    @Override
    public Object getItem(int position) {
        return items.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }
}
===========================================
Create new package and a file name UserService.java

package com.index.table.service;

import java.util.Collections;
import java.util.Vector;

import com.index.table.to.Book;

public class UserService {

    public static Vector<Book> getUserList() {
        Vector<Book> bookList = new Vector<Book>();

        Book book = new Book("Things Fall Apart ", "Chinua Achebe ", "1958", " Nigeria ", "English");
        bookList.add(book);
        book = new Book("Fairy tales ", "Hans Christian Andersen ", "183537 ", "Denmark ", "Danish");
        bookList.add(book);
        book = new Book("The Divine Comedy ", "Dante Alighieri ", "12651321 ", "Florence ", "Italian");
        bookList.add(book);
        book = new Book("Epic of Gilgamesh ", "Anonymous ", "18th  17th century BC ", "Sumer and Akkadian Empire ", "Akkadian");
        bookList.add(book);
        book = new Book("Book of Job ", "Anonymous ", "6th 4th century BC ", "Achaemenid Empire ", "Hebrew");
        bookList.add(book);
        book = new Book("One Thousand and One Nights ", "Anonymous ", "7001500 ", "India/Iran/Iraq/Egypt ", "Arabic");
        bookList.add(book);
        book = new Book("Nj�l's Saga ", "Anonymous ", "13th century ", "Iceland ", "Old Norse");
        bookList.add(book);
        book = new Book("Pride and Prejudice ", "Jane Austen ", "1813", " United Kingdom ", "English");
        bookList.add(book);
        book = new Book("Le P�re Goriot ", "Honor� de Balzac ", "1835", " France ", "French");
        bookList.add(book);
        book = new Book("Molloy, Malone Dies, The Unnamable, a trilogy ", "Samuel Beckett ", "1951�53 ", "Republic of Ireland ", "French, English");
        bookList.add(book);
        book = new Book("The Decameron ", "Giovanni Boccaccio ", "1349�53 ", "Ravenna ", "Italian");
        bookList.add(book);
        book = new Book("Ficciones ", "Jorge Luis Borges ", "1944�86 ", "Argentina ", "Spanish");
        bookList.add(book);
        book = new Book("Wuthering Heights ", "Emily Bront� ", "1847", "  United Kingdom ", "English");
        bookList.add(book);
        book = new Book("The Stranger ", "Albert Camus ", "1942", "   Algeria, French Empire ", "French");
        bookList.add(book);
        book = new Book("Poems ", "Paul Celan ", "1952", "    Romania, France ", "German");
        bookList.add(book);
        book = new Book("Journey to the End of the Night ", "Louis-Ferdinand C�line ", "1932", "  France ", "French");
        bookList.add(book);
        book = new Book("Don Quixote ", "Miguel de Cervantes ", "1605 (part 1), 1615 (part 2) ", "Spain ", "Spanish");
        bookList.add(book);
        book = new Book("The Canterbury Tales ", "Geoffrey Chaucer ", "14th century ", "England ", "English");
        bookList.add(book);
        book = new Book("Stories ", "Anton Chekhov ", "1886", "   Russia ", "Russian");
        bookList.add(book);
        book = new Book("Nostromo ", "Joseph Conrad ", "1904", "  United Kingdom ", "English");
        bookList.add(book);
        book = new Book("Great Expectations ", "Charles Dickens ", "1861", "  United Kingdom ", "English");
        bookList.add(book);
        book = new Book("Jacques the Fatalist ", "Denis Diderot ", "1796", "  France ", "French");
        bookList.add(book);
        book = new Book("Berlin Alexanderplatz ", "Alfred D�blin ", "1929", " Germany ", "German");
        bookList.add(book);
        book = new Book("Crime and Punishment ", "Fyodor Dostoyevsky ", "1866", " Russia ", "Russian");
        bookList.add(book);
        book = new Book("The Idiot ", "Fyodor Dostoyevsky ", "1869", "    Russia ", "Russian");
        bookList.add(book);
        book = new Book("The Possessed ", "Fyodor Dostoyevsky ", "1872", "    Russia ", "Russian");
        bookList.add(book);
        book = new Book("The Brothers Karamazov ", "Fyodor Dostoyevsky ", "1880", "   Russia ", "Russian");
        bookList.add(book);
        book = new Book("Middlemarch ", "George Eliot ", "1871", "    United Kingdom ", "English");
        bookList.add(book);
        book = new Book("Invisible Man ", "Ralph Ellison ", "1952", " United States ", "English");
        bookList.add(book);
        book = new Book("Medea ", "Euripides ", "431 BC ", "Athens ", "Classical Greek");
        bookList.add(book);
        book = new Book("Absalom, Absalom! ", "William Faulkner ", "1936", "  United States ", "English");
        bookList.add(book);
        book = new Book("The Sound and the Fury ", "William Faulkner ", "1929", " United States ", "English");
        bookList.add(book);
        book = new Book("Madame Bovary ", "Gustave Flaubert ", "1857", "  France ", "French");
        bookList.add(book);
        book = new Book("Sentimental Education ", "Gustave Flaubert ", "1869", "  France ", "French");
        bookList.add(book);
        book = new Book("Gypsy Ballads ", "Federico Garc�a Lorca ", "1928", " Spain ", "Spanish");
        bookList.add(book);
        book = new Book("One Hundred Years of Solitude ", "Gabriel Garc�a M�rquez ", "1967", "    Colombia ", "Spanish");
        bookList.add(book);
        book = new Book("Love in the Time of Cholera ", "Gabriel Garc�a M�rquez ", "1985", "  Colombia ", "Spanish");
        bookList.add(book);
        book = new Book("Faust ", "Johann Wolfgang von Goethe ", "1832", "    Saxe-Weimar, Germany ", "German");
        bookList.add(book);
        book = new Book("Dead Souls ", "Nikolai Gogol ", "1842", "    Russia ", "Russian");
        bookList.add(book);
        book = new Book("The Tin Drum ", "G�nter Grass ", "1959", "   West Germany ", "German");
        bookList.add(book);
        book = new Book("The Devil to Pay in the Backlands ", "Jo�o Guimar�es Rosa ", "1956", "   Brazil ", "Portuguese");
        bookList.add(book);
        book = new Book("Hunger ", "Knut Hamsun ", "1890", "  Norway ", "Norwegian");
        bookList.add(book);
        book = new Book("The Old Man and the Sea ", "Ernest Hemingway ", "1952", "    United States ", "English");
        bookList.add(book);
        book = new Book("Iliad ", "Homer ", "850�750 BC ", "Possibly Smyrna ", "Classical Greek");
        bookList.add(book);
        book = new Book("Odyssey ", "Homer ", "8th century BC ", "Possibly Smyrna ", "Classical Greek");
        bookList.add(book);
        book = new Book("A Doll's House ", "Henrik Ibsen ", "1879", " Norway ", "Norwegian");
        bookList.add(book);
        book = new Book("Ulysses ", "James Joyce ", "1922", " Irish Free State ", "English");
        bookList.add(book);
        book = new Book("Stories ", "Franz Kafka ", "1924", " Austria ", "German");
        bookList.add(book);
        book = new Book("The Trial ", "Franz Kafka ", "1925", "   Austria ", "German");
        bookList.add(book);
        book = new Book("The Castle ", "Franz Kafka ", "1926", "  Austria ", "German");
        bookList.add(book);
        book = new Book("Shakuntala ", "Kalidasa ", "1st century BC � 4th century AD ", "India ", "Sanskrit");
        bookList.add(book);
        book = new Book("The Sound of the Mountain ", "Yasunari Kawabata ", "1954", " Japan ", "Japanese");
        bookList.add(book);
        book = new Book("Zorba the Greek ", "Nikos Kazantzakis ", "1946", "   Greece ", "Greek");
        bookList.add(book);
        book = new Book("Sons and Lovers ", "D. H. Lawrence ", "1913", "  United Kingdom ", "English");
        bookList.add(book);
        book = new Book("Independent People ", "Halld�r Laxness ", "1934�35 ", "Iceland ", "Icelandic");
        bookList.add(book);
        book = new Book("Poems ", "Giacomo Leopardi ", "1818", "  Italy ", "Italian");
        bookList.add(book);
        book = new Book("The Golden Notebook ", "Doris Lessing ", "1962", "   United Kingdom ", "English");
        bookList.add(book);
        book = new Book("Pippi Longstocking ", "Astrid Lindgren ", "1945", "  Sweden ", "Swedish");
        bookList.add(book);
        book = new Book("A Madman's Diary ", "Lu Xun ", "1918", " China ", "Chinese");
        bookList.add(book);
        book = new Book("Children of Gebelawi ", "Naguib Mahfouz ", "1959", " Egypt ", "Arabic");
        bookList.add(book);
        book = new Book("Buddenbrooks ", "Thomas Mann ", "1901", "    Germany ", "German");
        bookList.add(book);
        book = new Book("The Magic Mountain ", "Thomas Mann ", "1924", "  Germany ", "German");
        bookList.add(book);
        book = new Book("Moby-Dick ", "Herman Melville ", "1851", "   United States ", "English");
        bookList.add(book);
        book = new Book("Essays ", "Michel de Montaigne ", "1595", "  France ", "French");
        bookList.add(book);
        book = new Book("History ", "Elsa Morante ", "1974", "    Italy ", "Italian");
        bookList.add(book);
        book = new Book("Beloved ", "Toni Morrison ", "1987", "   United States ", "English");
        bookList.add(book);
        book = new Book("The Tale of Genji ", "Murasaki Shikibu ", "11th century ", "Japan ", "Japanese");
        bookList.add(book);
        book = new Book("The Man Without Qualities ", "Robert Musil ", "1930�32 ", "Austria ", "German");
        bookList.add(book);
        book = new Book("Lolita ", "Vladimir Nabokov ", "1955", " Russia/United States ", "English");
        bookList.add(book);
        book = new Book("Nineteen Eighty-Four ", "George Orwell ", "1949", "  United Kingdom ", "English");
        bookList.add(book);
        book = new Book("Metamorphoses ", "Ovid ", "1st century AD ", "Roman Empire ", "Classical Latin");
        bookList.add(book);
        book = new Book("The Book of Disquiet ", "Fernando Pessoa ", "1928", "    Portugal ", "Portuguese");
        bookList.add(book);
        book = new Book("Tales ", "Edgar Allan Poe ", "19th century ", "United States ", "English");
        bookList.add(book);
        book = new Book("In Search of Lost Time ", "Marcel Proust ", "1913�27 ", "France ", "French");
        bookList.add(book);
        book = new Book("The Life of Gargantua and of Pantagruel ", "Fran�ois Rabelais ", "1532�34 ", "France ", "French");
        bookList.add(book);
        book = new Book("Pedro P�ramo ", "Juan Rulfo ", "1955", " Mexico ", "Spanish");
        bookList.add(book);
        book = new Book("Masnavi ", "Rumi ", "1258�73 ", "Persia, Mongol Empire ", "Persian");
        bookList.add(book);
        book = new Book("Midnight's Children ", "Salman Rushdie ", "1981", "  United Kingdom ", "English");
        bookList.add(book);
        book = new Book("Bostan ", "Saadi ", "1257", "    Persia, Mongol Empire ", "Persian");
        bookList.add(book);
        book = new Book("Season of Migration to the North ", "Tayeb Salih ", "1971", "    Sudan ", "Arabic");
        bookList.add(book);
        book = new Book("Blindness ", "Jos� Saramago ", "1995", " Portugal ", "Portuguese");
        bookList.add(book);
        book = new Book("Hamlet ", "William Shakespeare ", "1603", "  England ", "English");
        bookList.add(book);
        book = new Book("King Lear ", "William Shakespeare ", "1608", "   England ", "English");
        bookList.add(book);
        book = new Book("Othello ", "William Shakespeare ", "1609", " England ", "English");
        bookList.add(book);
        book = new Book("Oedipus the King ", "Sophocles ", "430 BC ", "Athens ", "Classical Greek");
        bookList.add(book);
        book = new Book("The Red and the Black ", "Stendhal ", "1830", "  France ", "French");
        bookList.add(book);
        book = new Book("Tristram Shandy ", "Laurence Sterne ", "1760", " England ", "English");
        bookList.add(book);
        book = new Book("Confessions of Zeno ", "Italo Svevo ", "1923", " Italy ", "Italian");
        bookList.add(book);
        book = new Book("Gulliver's Travels ", "Jonathan Swift ", "1726", "   Ireland ", "English");
        bookList.add(book);
        book = new Book("War and Peace ", "Leo Tolstoy ", "1865�1869 ", "Russia ", "Russian");
        bookList.add(book);
        book = new Book("Anna Karenina ", "Leo Tolstoy ", "1877", "   Russia ", "Russian");
        bookList.add(book);
        book = new Book("The Death of Ivan Ilyich ", "Leo Tolstoy ", "1886", "    Russia ", "Russian");
        bookList.add(book);
        book = new Book("Adventures of Huckleberry Finn ", "Mark Twain ", "1884", "   United States ", "English");
        bookList.add(book);
        book = new Book("Ramayana ", "Valmiki ", "3rd century BC � 3rd century AD ", "India ", "Sanskrit");
        bookList.add(book);
        book = new Book("Aeneid ", "Virgil ", "29�19 BC ", "Roman Empire ", "Classical Latin");
        bookList.add(book);
        book = new Book("Mahabharata ", "Vyasa ", "4th century BC � 4th century AD ", "India ", "Sanskrit");
        bookList.add(book);
        book = new Book("Leaves of Grass ", "Walt Whitman ", "1855", "    United States ", "English");
        bookList.add(book);
        book = new Book("Mrs Dalloway ", "Virginia Woolf ", "1925", " United Kingdom ", "English");
        bookList.add(book);
        book = new Book("To the Lighthouse ", "Virginia Woolf ", "1927", "    United Kingdom ", "English");
        bookList.add(book);
        book = new Book("Memoirs of Hadrian ", "Marguerite Yourcenar ", "1951", " France ", "French");
        bookList.add(book);
        Collections.sort(bookList);
        return bookList;
    }

}
===========================================
create third packeage and add a file named Book.java

package com.index.table.to;

public class Book implements Comparable<Book>
{   
    private String title;
   
    private String author;
   
    private String year;
   
    private String country;
   
    private String language;

    public Book() {
        // TODO Auto-generated constructor stub
    }
   
    public Book(String title, String author, String year, String country, String language) {
        super();
        this.title = title;
        this.author = author;
        this.year = year;
        this.country = country;
        this.language = language;
    }

    /**
     * @return the title
     */
    public String getTitle() {
        return title;
    }

    /**
     * @param title the title to set
     */
    public void setTitle(String title) {
        this.title = title;
    }

    /**
     * @return the author
     */
    public String getAuthor() {
        return author;
    }

    /**
     * @param author the author to set
     */
    public void setAuthor(String author) {
        this.author = author;
    }

    /**
     * @return the year
     */
    public String getYear() {
        return year;
    }

    /**
     * @param year the year to set
     */
    public void setYear(String year) {
        this.year = year;
    }

    /**
     * @return the country
     */
    public String getCountry() {
        return country;
    }

    /**
     * @param country the country to set
     */
    public void setCountry(String country) {
        this.country = country;
    }

    /**
     * @return the language
     */
    public String getLanguage() {
        return language;
    }

    /**
     * @param language the language to set
     */
    public void setLanguage(String language) {
        this.language = language;
    }

    @Override
    public int compareTo(Book book) {
        return this.getTitle().compareTo(book.getTitle());
    }
}
=========================================

create xml named listrow_user.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/listitem_test"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:clickable="true"
    android:focusable="true"
    android:gravity="center_vertical"
    android:orientation="vertical" >
    <LinearLayout
        android:id="@+id/nameLL"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:background="@color/white"
        android:clickable="true"
        android:focusable="true"
        android:orientation="horizontal" >
        <TextView
            android:id="@+id/nameTV"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="#000000"
            android:layout_marginTop="5dip"
            android:layout_marginRight="5dip"
            android:padding="10dip"
            android:textSize="14dip"
            android:text="@+id/TextView01" >
        </TextView>
    </LinearLayout>
    <LinearLayout
        android:id="@+id/headingLL"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/black" >
        <TextView
            android:id="@+id/headingTV"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="16dip"
            android:paddingLeft="10dip"
            android:textColor="@color/black"
            android:text="@+id/TextView01" >
        </TextView>
    </LinearLayout>
</LinearLayout>
================================================
create second xml named main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:background="#acacb7"
        android:orientation="horizontal" >

        <ListView
            android:id="@+id/booksLV"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:cacheColorHint="#00000000"
            android:divider="@color/gray"
            android:dividerHeight="1px" >
        </ListView>

        <LinearLayout
            android:id="@+id/sideIndex"
            android:layout_width="20dip"
            android:layout_height="fill_parent"
            android:background="@android:color/white"
            android:gravity="center_horizontal"
            android:orientation="vertical" >
        </LinearLayout>
    </LinearLayout>   

</LinearLayout>

========================================
in manifest.xml add

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.index.table"
    android:versionCode="1"
    android:versionName="1.0" >
    <uses-sdk android:minSdkVersion="8" />
    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <activity
            android:label="@string/app_name"
            android:name=".IndexTableActivity" >
            <intent-filter >
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

ListView SectionHeader

Create class  SectionedAdapter.java
========================
import java.util.ArrayList;
import java.util.List;

import android.view.View;
import android.view.ViewGroup;
import android.widget.Adapter;
import android.widget.BaseAdapter;

abstract public class SectionedAdapter extends BaseAdapter {
    abstract protected View getHeaderView(String caption, int index,
        View convertView, ViewGroup parent);

    private final List<Section> sections = new ArrayList<Section>();
    private static int TYPE_SECTION_HEADER = 0;

    public SectionedAdapter() {
    super();
    }

    public void addSection(String caption, Adapter adapter) {
    sections.add(new Section(caption, adapter));
    }

    public Object getItem(int position) {
    for (Section section : this.sections) {
        if (position == 0) {
        return (section);
        }

        int size = section.adapter.getCount() + 1;

        if (position < size) {
        return (section.adapter.getItem(position - 1));
        }

        position -= size;
    }

    return (null);
    }

    public int getCount() {
    int total = 0;

    for (Section section : this.sections) {
        total += section.adapter.getCount() + 1; // add one for header
    }

    return (total);
    }

    @Override
    public int getViewTypeCount() {
    int total = 1; // one for the header, plus those from sections

    for (Section section : this.sections) {
        total += section.adapter.getViewTypeCount();
    }

    return (total);
    }

    @Override
    public int getItemViewType(int position) {
    int typeOffset = TYPE_SECTION_HEADER + 1; // start counting from here

    for (Section section : this.sections) {
        if (position == 0) {
        return (TYPE_SECTION_HEADER);
        }

        int size = section.adapter.getCount() + 1;

        if (position < size) {
        return (typeOffset + section.adapter
            .getItemViewType(position - 1));
        }

        position -= size;
        typeOffset += section.adapter.getViewTypeCount();
    }

    return (-1);
    }

    public boolean areAllItemsSelectable() {
    return (false);
    }

    @Override
    public boolean isEnabled(int position) {
    return (getItemViewType(position) != TYPE_SECTION_HEADER);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
    int sectionIndex = 0;

    for (Section section : this.sections) {
        if (position == 0) {
        return (getHeaderView(section.caption, sectionIndex,
            convertView, parent));
        }

        int size = section.adapter.getCount() + 1;

        if (position < size) {
        return (section.adapter.getView(position - 1, convertView,
            parent));
        }

        position -= size;
        sectionIndex++;
    }

    return (null);
    }

    @Override
    public long getItemId(int position) {
    return (position);
    }

    class Section {
    String caption;
    Adapter adapter;

    Section(String caption, Adapter adapter) {
        this.caption = caption;
        this.adapter = adapter;
    }
    }
}

======================================================
Create another class  SectionedDemo.java

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import android.app.ListActivity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;

public class SectionedDemo extends ListActivity {
    private static String[] items = { "Muscle Stiffness", "Vision Problems",
        "Weaknesss", "Depression" };

    @Override
    public void onCreate(Bundle icicle) {
    super.onCreate(icicle);
    setContentView(R.layout.main);

    adapter.addSection("Wed Nov 3, 2010", new ArrayAdapter<String>(this,
        android.R.layout.simple_list_item_1, items));

    List<String> list = Arrays.asList(items);

    Collections.shuffle(list);

    adapter.addSection("Mon Nov 1, 2010", new ArrayAdapter<String>(this,
        android.R.layout.simple_list_item_1, list));

    list = Arrays.asList(items);

    Collections.shuffle(list);

    adapter.addSection("Tues  Oct, 31, 2010", new ArrayAdapter<String>(
        this, android.R.layout.simple_list_item_1, list));

    setListAdapter(adapter);
    }

    SectionedAdapter adapter = new SectionedAdapter() {
    @Override
    protected View getHeaderView(String caption, int index,
        View convertView, ViewGroup parent) {
        TextView result = (TextView) convertView;

        if (convertView == null) {
        result = (TextView) getLayoutInflater().inflate(
            R.layout.section_header, null);
        }

        result.setText(caption);

        return (result);
    }
    };
}
=============================================
Create xml file main.xml
<?xml version="1.0" encoding="utf-8"?>
<ListView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@android:id/list"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:drawSelectorOnTop="true"
/>
==============================================
Create another xml named section_header.xml

<TextView   
    xmlns:android="http://schemas.android.com/apk/res/android"   
    android:layout_width="fill_parent"   
    android:layout_height="wrap_content"   
    android:gravity="center"   
    style="?android:attr/listSeparatorTextViewStyle" />

Tuesday 2 April 2013

CoverFlow example

Here is some example links for coverFlow

1)http://www.coderzheaven.com/2012/12/17/coverflow-android-complete-implementation-source-code/
2)https://github.com/ManishaPatel/FancyCoverFlow
create class CoverAbsSpinner.java
======================
import android.content.Context;
import android.database.DataSetObserver;
import android.graphics.Rect;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.SparseArray;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Interpolator;
import android.widget.AbsSpinner;
import android.widget.SpinnerAdapter;

/**
 * An abstract base class for spinner widgets. SDK users will probably not
 * need to use this class.
 *
 * @attr ref android.R.styleable#AbsSpinner_entries
 */
public abstract class CoverAbsSpinner  extends CoverAdapterView<SpinnerAdapter> {

    SpinnerAdapter mAdapter;

    int mHeightMeasureSpec;
    int mWidthMeasureSpec;
    boolean mBlockLayoutRequests;
    int mSelectionLeftPadding = 0;
    int mSelectionTopPadding = 0;
    int mSelectionRightPadding = 0;
    int mSelectionBottomPadding = 0;
    Rect mSpinnerPadding = new Rect();
    View mSelectedView = null;
    Interpolator mInterpolator;

    RecycleBin mRecycler = new RecycleBin();
    private DataSetObserver mDataSetObserver;


    /** Temporary frame to hold a child View's frame rectangle */
    private Rect mTouchFrame;

    public CoverAbsSpinner(Context context) {
        super(context);
        initAbsSpinner();
    }

    public CoverAbsSpinner(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CoverAbsSpinner(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initAbsSpinner();

//        TypedArray a = context.obtainStyledAttributes(attrs,
//                com.android.internal.R.styleable.CoverAbsSpinner, defStyle, 0);
//
//        CharSequence[] entries = a.getTextArray(R.styleable.AbsSpinner_entries);
//        if (entries != null) {
//            ArrayAdapter<CharSequence> adapter =
//                    new ArrayAdapter<CharSequence>(context,
//                            R.layout.simple_spinner_item, entries);
//            adapter.setDropDownViewResource(R.layout.simple_spinner_dropdown_item);
//            setAdapter(adapter);
//        }

//        a.recycle();
    }

    /**
     * Common code for different constructor flavors
     */
    private void initAbsSpinner() {
        setFocusable(true);
        setWillNotDraw(false);
    }


    /**
     * The Adapter is used to provide the data which backs this Spinner.
     * It also provides methods to transform spinner items based on their position
     * relative to the selected item.
     * @param adapter The SpinnerAdapter to use for this Spinner
     */
    @Override
    public void setAdapter(SpinnerAdapter adapter) {
        if (null != mAdapter) {
            mAdapter.unregisterDataSetObserver(mDataSetObserver);
            resetList();
        }
       
        mAdapter = adapter;
       
        mOldSelectedPosition = INVALID_POSITION;
        mOldSelectedRowId = INVALID_ROW_ID;
       
        if (mAdapter != null) {
            mOldItemCount = mItemCount;
            mItemCount = mAdapter.getCount();
            checkFocus();

            mDataSetObserver = new AdapterDataSetObserver();
            mAdapter.registerDataSetObserver(mDataSetObserver);

            int position = mItemCount > 0 ? 0 : INVALID_POSITION;

            setSelectedPositionInt(position);
            setNextSelectedPositionInt(position);
           
            if (mItemCount == 0) {
                // Nothing selected
                checkSelectionChanged();
            }
           
        } else {
            checkFocus();           
            resetList();
            // Nothing selected
            checkSelectionChanged();
        }

        requestLayout();
    }

    /**
     * Clear out all children from the list
     */
    void resetList() {
        mDataChanged = false;
        mNeedSync = false;
       
        removeAllViewsInLayout();
        mOldSelectedPosition = INVALID_POSITION;
        mOldSelectedRowId = INVALID_ROW_ID;
       
        setSelectedPositionInt(INVALID_POSITION);
        setNextSelectedPositionInt(INVALID_POSITION);
        invalidate();
    }

    /**
     * @see android.view.View#measure(int, int)
     *
     * Figure out the dimensions of this Spinner. The width comes from
     * the widthMeasureSpec as Spinnners can't have their width set to
     * UNSPECIFIED. The height is based on the height of the selected item
     * plus padding.
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize;
        int heightSize;

        mSpinnerPadding.left = getPaddingLeft() > mSelectionLeftPadding ? getPaddingLeft()
                : mSelectionLeftPadding;
        mSpinnerPadding.top = getPaddingTop() > mSelectionTopPadding ? getPaddingTop()
                : mSelectionTopPadding;
        mSpinnerPadding.right = getPaddingRight() > mSelectionRightPadding ? getPaddingRight()
                : mSelectionRightPadding;
        mSpinnerPadding.bottom = getPaddingBottom() > mSelectionBottomPadding ? getPaddingBottom()
                : mSelectionBottomPadding;

        if (mDataChanged) {
            handleDataChanged();
        }
       
        int preferredHeight = 0;
        int preferredWidth = 0;
        boolean needsMeasuring = true;
       
        int selectedPosition = getSelectedItemPosition();
        if (selectedPosition >= 0 && mAdapter != null) {
            // Try looking in the recycler. (Maybe we were measured once already)
            View view = mRecycler.get(selectedPosition);
            if (view == null) {
                // Make a new one
                view = mAdapter.getView(selectedPosition, null, this);
            }

            if (view != null) {
                // Put in recycler for re-measuring and/or layout
                mRecycler.put(selectedPosition, view);
            }

            if (view != null) {
                if (view.getLayoutParams() == null) {
                    mBlockLayoutRequests = true;
                    view.setLayoutParams(generateDefaultLayoutParams());
                    mBlockLayoutRequests = false;
                }
                measureChild(view, widthMeasureSpec, heightMeasureSpec);
               
                preferredHeight = getChildHeight(view) + mSpinnerPadding.top + mSpinnerPadding.bottom;
                preferredWidth = getChildWidth(view) + mSpinnerPadding.left + mSpinnerPadding.right;
               
                needsMeasuring = false;
            }
        }
       
        if (needsMeasuring) {
            // No views -- just use padding
            preferredHeight = mSpinnerPadding.top + mSpinnerPadding.bottom;
            if (widthMode == MeasureSpec.UNSPECIFIED) {
                preferredWidth = mSpinnerPadding.left + mSpinnerPadding.right;
            }
        }

        preferredHeight = Math.max(preferredHeight, getSuggestedMinimumHeight());
        preferredWidth = Math.max(preferredWidth, getSuggestedMinimumWidth());

        heightSize = resolveSize(preferredHeight, heightMeasureSpec);
        widthSize = resolveSize(preferredWidth, widthMeasureSpec);

        setMeasuredDimension(widthSize, heightSize);
        mHeightMeasureSpec = heightMeasureSpec;
        mWidthMeasureSpec = widthMeasureSpec;
    }

   
    int getChildHeight(View child) {
        return child.getMeasuredHeight();
    }
   
    int getChildWidth(View child) {
        return child.getMeasuredWidth();
    }
   
    @Override
    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
        return new ViewGroup.LayoutParams(
                ViewGroup.LayoutParams.FILL_PARENT,
                ViewGroup.LayoutParams.WRAP_CONTENT);
    }
   
    void recycleAllViews() {
        int childCount = getChildCount();
        final CoverAbsSpinner.RecycleBin recycleBin = mRecycler;

        // All views go in recycler
        for (int i=0; i<childCount; i++) {
            View v = getChildAt(i);
            int index = mFirstPosition + i;
            recycleBin.put(index, v);
        } 
    }
   
    @Override
    void handleDataChanged() {
        // FIXME -- this is called from both measure and layout.
        // This is harmless right now, but we don't want to do redundant work if
        // this gets more complicated
       super.handleDataChanged();
    }
   
 

    /**
     * Jump directly to a specific item in the adapter data.
     */
    public void setSelection(int position, boolean animate) {
        // Animate only if requested position is already on screen somewhere
        boolean shouldAnimate = animate && mFirstPosition <= position &&
                position <= mFirstPosition + getChildCount() - 1;
        setSelectionInt(position, shouldAnimate);
    }
   

    @Override
    public void setSelection(int position) {
        setNextSelectedPositionInt(position);
        requestLayout();
        invalidate();
    }
   

    /**
     * Makes the item at the supplied position selected.
     *
     * @param position Position to select
     * @param animate Should the transition be animated
     *
     */
    void setSelectionInt(int position, boolean animate) {
        if (position != mOldSelectedPosition) {
            mBlockLayoutRequests = true;
            int delta  = position - mSelectedPosition;
            setNextSelectedPositionInt(position);
            layout(delta, animate);
            mBlockLayoutRequests = false;
        }
    }

    abstract void layout(int delta, boolean animate);

    @Override
    public View getSelectedView() {
        if (mItemCount > 0 && mSelectedPosition >= 0) {
            return getChildAt(mSelectedPosition - mFirstPosition);
        } else {
            return null;
        }
    }
  
    /**
     * Override to prevent spamming ourselves with layout requests
     * as we place views
     *
     * @see android.view.View#requestLayout()
     */
    @Override
    public void requestLayout() {
        if (!mBlockLayoutRequests) {
            super.requestLayout();
        }
    }



    @Override
    public SpinnerAdapter getAdapter() {
        return mAdapter;
    }

    @Override
    public int getCount() {
        return mItemCount;
    }

    /**
     * Maps a point to a position in the list.
     *
     * @param x X in local coordinate
     * @param y Y in local coordinate
     * @return The position of the item which contains the specified point, or
     *         {@link #INVALID_POSITION} if the point does not intersect an item.
     */
    public int pointToPosition(int x, int y) {
        Rect frame = mTouchFrame;
        if (frame == null) {
            mTouchFrame = new Rect();
            frame = mTouchFrame;
        }

        final int count = getChildCount();
        for (int i = count - 1; i >= 0; i--) {
            View child = getChildAt(i);
            if (child.getVisibility() == View.VISIBLE) {
                child.getHitRect(frame);
                if (frame.contains(x, y)) {
                    return mFirstPosition + i;
                }
            }
        }
        return INVALID_POSITION;
    }
   
    static class SavedState extends BaseSavedState {
        long selectedId;
        int position;

        /**
         * Constructor called from {@link AbsSpinner#onSaveInstanceState()}
         */
        SavedState(Parcelable superState) {
            super(superState);
        }
       
        /**
         * Constructor called from {@link #CREATOR}
         */
        private SavedState(Parcel in) {
            super(in);
            selectedId = in.readLong();
            position = in.readInt();
        }

        @Override
        public void writeToParcel(Parcel out, int flags) {
            super.writeToParcel(out, flags);
            out.writeLong(selectedId);
            out.writeInt(position);
        }

        @Override
        public String toString() {
            return "AbsSpinner.SavedState{"
                    + Integer.toHexString(System.identityHashCode(this))
                    + " selectedId=" + selectedId
                    + " position=" + position + "}";
        }

        public static final Parcelable.Creator<SavedState> CREATOR
                = new Parcelable.Creator<SavedState>() {
            public SavedState createFromParcel(Parcel in) {
                return new SavedState(in);
            }

            public SavedState[] newArray(int size) {
                return new SavedState[size];
            }
        };
    }

    @Override
    public Parcelable onSaveInstanceState() {
        Parcelable superState = super.onSaveInstanceState();
        SavedState ss = new SavedState(superState);
        ss.selectedId = getSelectedItemId();
        if (ss.selectedId >= 0) {
            ss.position = getSelectedItemPosition();
        } else {
            ss.position = INVALID_POSITION;
        }
        return ss;
    }

    @Override
    public void onRestoreInstanceState(Parcelable state) {
        SavedState ss = (SavedState) state;
 
        super.onRestoreInstanceState(ss.getSuperState());

        if (ss.selectedId >= 0) {
            mDataChanged = true;
            mNeedSync = true;
            mSyncRowId = ss.selectedId;
            mSyncPosition = ss.position;
            mSyncMode = SYNC_SELECTED_POSITION;
            requestLayout();
        }
    }

    class RecycleBin {
        private SparseArray<View> mScrapHeap = new SparseArray<View>();

        public void put(int position, View v) {
            mScrapHeap.put(position, v);
        }
       
        View get(int position) {
            // System.out.print("Looking for " + position);
            View result = mScrapHeap.get(position);
            if (result != null) {
                // System.out.println(" HIT");
                mScrapHeap.delete(position);
            } else {
                // System.out.println(" MISS");
            }
            return result;
        }
       
        View peek(int position) {
            // System.out.print("Looking for " + position);
            return mScrapHeap.get(position);
        }
       
        void clear() {
            final SparseArray<View> scrapHeap = mScrapHeap;
            final int count = scrapHeap.size();
            for (int i = 0; i < count; i++) {
                final View view = scrapHeap.valueAt(i);
                if (view != null) {
                    removeDetachedView(view, true);
                }
            }
            scrapHeap.clear();
        }
    }
}

Create second class CoverAdapterView.java
===========================
import android.content.Context;
import android.database.DataSetObserver;
import android.os.Handler;
import android.os.Parcelable;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.SparseArray;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.SoundEffectConstants;
import android.view.View;
import android.view.ViewDebug;
import android.view.ViewGroup;
import android.widget.Adapter;
import android.widget.Gallery;
import android.widget.GridView;
import android.widget.ListView;
import android.widget.Spinner;


/**
 * An AdapterView is a view whose children are determined by an {@link Adapter}.
 *
 * <p>
 * See {@link ListView}, {@link GridView}, {@link Spinner} and
 *      {@link Gallery} for commonly used subclasses of AdapterView.
 */
public abstract class CoverAdapterView<T extends Adapter> extends ViewGroup {

    /**
     * The item view type returned by {@link Adapter#getItemViewType(int)} when
     * the adapter does not want the item's view recycled.
     */
    public static final int ITEM_VIEW_TYPE_IGNORE = -1;

    /**
     * The item view type returned by {@link Adapter#getItemViewType(int)} when
     * the item is a header or footer.
     */
    public static final int ITEM_VIEW_TYPE_HEADER_OR_FOOTER = -2;

    /**
     * The position of the first child displayed
     */
    @ViewDebug.ExportedProperty
    int mFirstPosition = 0;

    /**
     * The offset in pixels from the top of the AdapterView to the top
     * of the view to select during the next layout.
     */
    int mSpecificTop;

    /**
     * Position from which to start looking for mSyncRowId
     */
    int mSyncPosition;

    /**
     * Row id to look for when data has changed
     */
    long mSyncRowId = INVALID_ROW_ID;

    /**
     * Height of the view when mSyncPosition and mSyncRowId where set
     */
    long mSyncHeight;

    /**
     * True if we need to sync to mSyncRowId
     */
    boolean mNeedSync = false;

    /**
     * Indicates whether to sync based on the selection or position. Possible
     * values are {@link #SYNC_SELECTED_POSITION} or
     * {@link #SYNC_FIRST_POSITION}.
     */
    int mSyncMode;

    /**
     * Our height after the last layout
     */
    private int mLayoutHeight;

    /**
     * Sync based on the selected child
     */
    static final int SYNC_SELECTED_POSITION = 0;

    /**
     * Sync based on the first child displayed
     */
    static final int SYNC_FIRST_POSITION = 1;

    /**
     * Maximum amount of time to spend in {@link #findSyncPosition()}
     */
    static final int SYNC_MAX_DURATION_MILLIS = 100;

    /**
     * Indicates that this view is currently being laid out.
     */
    boolean mInLayout = false;

    /**
     * The listener that receives notifications when an item is selected.
     */
    OnItemSelectedListener mOnItemSelectedListener;

    /**
     * The listener that receives notifications when an item is clicked.
     */
    OnItemClickListener mOnItemClickListener;

    /**
     * The listener that receives notifications when an item is long clicked.
     */
    OnItemLongClickListener mOnItemLongClickListener;

    /**
     * True if the data has changed since the last layout
     */
    boolean mDataChanged;

    /**
     * The position within the adapter's data set of the item to select
     * during the next layout.
     */
    @ViewDebug.ExportedProperty   
    int mNextSelectedPosition = INVALID_POSITION;

    /**
     * The item id of the item to select during the next layout.
     */
    long mNextSelectedRowId = INVALID_ROW_ID;

    /**
     * The position within the adapter's data set of the currently selected item.
     */
    @ViewDebug.ExportedProperty   
    int mSelectedPosition = INVALID_POSITION;

    /**
     * The item id of the currently selected item.
     */
    long mSelectedRowId = INVALID_ROW_ID;

    /**
     * View to show if there are no items to show.
     */
    View mEmptyView;

    /**
     * The number of items in the current adapter.
     */
    @ViewDebug.ExportedProperty
    int mItemCount;

    /**
     * The number of items in the adapter before a data changed event occured.
     */
    int mOldItemCount;

    /**
     * Represents an invalid position. All valid positions are in the range 0 to 1 less than the
     * number of items in the current adapter.
     */
    public static final int INVALID_POSITION = -1;

    /**
     * Represents an empty or invalid row id
     */
    public static final long INVALID_ROW_ID = Long.MIN_VALUE;

    /**
     * The last selected position we used when notifying
     */
    int mOldSelectedPosition = INVALID_POSITION;
   
    /**
     * The id of the last selected position we used when notifying
     */
    long mOldSelectedRowId = INVALID_ROW_ID;

    /**
     * Indicates what focusable state is requested when calling setFocusable().
     * In addition to this, this view has other criteria for actually
     * determining the focusable state (such as whether its empty or the text
     * filter is shown).
     *
     * @see #setFocusable(boolean)
     * @see #checkFocus()
     */
    private boolean mDesiredFocusableState;
    private boolean mDesiredFocusableInTouchModeState;

    private SelectionNotifier mSelectionNotifier;
    /**
     * When set to true, calls to requestLayout() will not propagate up the parent hierarchy.
     * This is used to layout the children during a layout pass.
     */
    boolean mBlockLayoutRequests = false;

    public CoverAdapterView(Context context) {
        super(context);
    }

    public CoverAdapterView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public CoverAdapterView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }


    /**
     * Interface definition for a callback to be invoked when an item in this
     * AdapterView has been clicked.
     */
    public interface OnItemClickListener {

        /**
         * Callback method to be invoked when an item in this AdapterView has
         * been clicked.
         * <p>
         * Implementers can call getItemAtPosition(position) if they need
         * to access the data associated with the selected item.
         *
         * @param parent The AdapterView where the click happened.
         * @param view The view within the AdapterView that was clicked (this
         *            will be a view provided by the adapter)
         * @param position The position of the view in the adapter.
         * @param id The row id of the item that was clicked.
         */
        void onItemClick(CoverAdapterView<?> parent, View view, int position, long id);

 
    }

    /**
     * Register a callback to be invoked when an item in this AdapterView has
     * been clicked.
     *
     * @param listener The callback that will be invoked.
     */
    public void setOnItemClickListener(OnItemClickListener listener) {
        mOnItemClickListener = listener;
    }

    /**
     * @return The callback to be invoked with an item in this AdapterView has
     *         been clicked, or null id no callback has been set.
     */
    public final OnItemClickListener getOnItemClickListener() {
        return mOnItemClickListener;
    }

    /**
     * Call the OnItemClickListener, if it is defined.
     *
     * @param view The view within the AdapterView that was clicked.
     * @param position The position of the view in the adapter.
     * @param id The row id of the item that was clicked.
     * @return True if there was an assigned OnItemClickListener that was
     *         called, false otherwise is returned.
     */
    public boolean performItemClick(View view, int position, long id) {
        if (mOnItemClickListener != null) {
            playSoundEffect(SoundEffectConstants.CLICK);
            mOnItemClickListener.onItemClick(this, view, position, id);
            return true;
        }

        return false;
    }

    /**
     * Interface definition for a callback to be invoked when an item in this
     * view has been clicked and held.
     */
    public interface OnItemLongClickListener {
        /**
         * Callback method to be invoked when an item in this view has been
         * clicked and held.
         *
         * Implementers can call getItemAtPosition(position) if they need to access
         * the data associated with the selected item.
         *
         * @param coverFlow The AbsListView where the click happened
         * @param view The view within the AbsListView that was clicked
         * @param position The position of the view in the list
         * @param id The row id of the item that was clicked
         *
         * @return true if the callback consumed the long click, false otherwise
         */
        boolean onItemLongClick(CoverFlow coverFlow, View view, int position, long id);
    }


    /**
     * Register a callback to be invoked when an item in this AdapterView has
     * been clicked and held
     *
     * @param listener The callback that will run
     */
    public void setOnItemLongClickListener(OnItemLongClickListener listener) {
        if (!isLongClickable()) {
            setLongClickable(true);
        }
        mOnItemLongClickListener = listener;
    }

    /**
     * @return The callback to be invoked with an item in this AdapterView has
     *         been clicked and held, or null id no callback as been set.
     */
    public final OnItemLongClickListener getOnItemLongClickListener() {
        return mOnItemLongClickListener;
    }

    /**
     * Interface definition for a callback to be invoked when
     * an item in this view has been selected.
     */
    public interface OnItemSelectedListener {
        /**
         * Callback method to be invoked when an item in this view has been
         * selected.
         *
         * Impelmenters can call getItemAtPosition(position) if they need to access the
         * data associated with the selected item.
         *
         * @param parent The AdapterView where the selection happened
         * @param view The view within the AdapterView that was clicked
         * @param position The position of the view in the adapter
         * @param id The row id of the item that is selected
         */
        void onItemSelected(CoverAdapterView<?> parent, View view, int position, long id);

        /**
         * Callback method to be invoked when the selection disappears from this
         * view. The selection can disappear for instance when touch is activated
         * or when the adapter becomes empty.
         *
         * @param parent The AdapterView that now contains no selected item.
         */
        void onNothingSelected(CoverAdapterView<?> parent);
    }


    /**
     * Register a callback to be invoked when an item in this AdapterView has
     * been selected.
     *
     * @param listener The callback that will run
     */
    public void setOnItemSelectedListener(OnItemSelectedListener listener) {
        mOnItemSelectedListener = listener;
    }

    public final OnItemSelectedListener getOnItemSelectedListener() {
        return mOnItemSelectedListener;
    }

    /**
     * Extra menu information provided to the
     * {@link android.view.View.OnCreateContextMenuListener#onCreateContextMenu(ContextMenu, View, ContextMenuInfo) }
     * callback when a context menu is brought up for this AdapterView.
     *
     */
    public static class AdapterContextMenuInfo implements ContextMenu.ContextMenuInfo {

        public AdapterContextMenuInfo(View targetView, int position, long id) {
            this.targetView = targetView;
            this.position = position;
            this.id = id;
        }

        /**
         * The child view for which the context menu is being displayed. This
         * will be one of the children of this AdapterView.
         */
        public View targetView;

        /**
         * The position in the adapter for which the context menu is being
         * displayed.
         */
        public int position;

        /**
         * The row id of the item for which the context menu is being displayed.
         */
        public long id;
    }

    /**
     * Returns the adapter currently associated with this widget.
     *
     * @return The adapter used to provide this view's content.
     */
    public abstract T getAdapter();

    /**
     * Sets the adapter that provides the data and the views to represent the data
     * in this widget.
     *
     * @param adapter The adapter to use to create this view's content.
     */
    public abstract void setAdapter(T adapter);

    /**
     * This method is not supported and throws an UnsupportedOperationException when called.
     *
     * @param child Ignored.
     *
     * @throws UnsupportedOperationException Every time this method is invoked.
     */
    @Override
    public void addView(View child) {
        throw new UnsupportedOperationException("addView(View) is not supported in AdapterView");
    }

    /**
     * This method is not supported and throws an UnsupportedOperationException when called.
     *
     * @param child Ignored.
     * @param index Ignored.
     *
     * @throws UnsupportedOperationException Every time this method is invoked.
     */
    @Override
    public void addView(View child, int index) {
        throw new UnsupportedOperationException("addView(View, int) is not supported in AdapterView");
    }

    /**
     * This method is not supported and throws an UnsupportedOperationException when called.
     *
     * @param child Ignored.
     * @param params Ignored.
     *
     * @throws UnsupportedOperationException Every time this method is invoked.
     */
    @Override
    public void addView(View child, LayoutParams params) {
        throw new UnsupportedOperationException("addView(View, LayoutParams) "
                + "is not supported in AdapterView");
    }

    /**
     * This method is not supported and throws an UnsupportedOperationException when called.
     *
     * @param child Ignored.
     * @param index Ignored.
     * @param params Ignored.
     *
     * @throws UnsupportedOperationException Every time this method is invoked.
     */
    @Override
    public void addView(View child, int index, LayoutParams params) {
        throw new UnsupportedOperationException("addView(View, int, LayoutParams) "
                + "is not supported in AdapterView");
    }

    /**
     * This method is not supported and throws an UnsupportedOperationException when called.
     *
     * @param child Ignored.
     *
     * @throws UnsupportedOperationException Every time this method is invoked.
     */
    @Override
    public void removeView(View child) {
        throw new UnsupportedOperationException("removeView(View) is not supported in AdapterView");
    }

    /**
     * This method is not supported and throws an UnsupportedOperationException when called.
     *
     * @param index Ignored.
     *
     * @throws UnsupportedOperationException Every time this method is invoked.
     */
    @Override
    public void removeViewAt(int index) {
        throw new UnsupportedOperationException("removeViewAt(int) is not supported in AdapterView");
    }

    /**
     * This method is not supported and throws an UnsupportedOperationException when called.
     *
     * @throws UnsupportedOperationException Every time this method is invoked.
     */
    @Override
    public void removeAllViews() {
        throw new UnsupportedOperationException("removeAllViews() is not supported in AdapterView");
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        mLayoutHeight = getHeight();
    }

    /**
     * Return the position of the currently selected item within the adapter's data set
     *
     * @return int Position (starting at 0), or {@link #INVALID_POSITION} if there is nothing selected.
     */
    //@ViewDebug.CapturedViewProperty
    public int getSelectedItemPosition() {
        return mNextSelectedPosition;
    }

    /**
     * @return The id corresponding to the currently selected item, or {@link #INVALID_ROW_ID}
     * if nothing is selected.
     */
    //@ViewDebug.CapturedViewProperty
    public long getSelectedItemId() {
        return mNextSelectedRowId;
    }

    /**
     * @return The view corresponding to the currently selected item, or null
     * if nothing is selected
     */
    public abstract View getSelectedView();

    /**
     * @return The data corresponding to the currently selected item, or
     * null if there is nothing selected.
     */
    public Object getSelectedItem() {
        T adapter = getAdapter();
        int selection = getSelectedItemPosition();
        if (adapter != null && adapter.getCount() > 0 && selection >= 0) {
            return adapter.getItem(selection);
        } else {
            return null;
        }
    }

    /**
     * @return The number of items owned by the Adapter associated with this
     *         AdapterView. (This is the number of data items, which may be
     *         larger than the number of visible view.)
     */
    //@ViewDebug.CapturedViewProperty
    public int getCount() {
        return mItemCount;
    }

    /**
     * Get the position within the adapter's data set for the view, where view is a an adapter item
     * or a descendant of an adapter item.
     *
     * @param view an adapter item, or a descendant of an adapter item. This must be visible in this
     *        AdapterView at the time of the call.
     * @return the position within the adapter's data set of the view, or {@link #INVALID_POSITION}
     *         if the view does not correspond to a list item (or it is not currently visible).
     */
    public int getPositionForView(View view) {
        View listItem = view;
        try {
            View v;
            while (!(v = (View) listItem.getParent()).equals(this)) {
                listItem = v;
            }
        } catch (ClassCastException e) {
            // We made it up to the window without find this list view
            return INVALID_POSITION;
        }

        // Search the children for the list item
        final int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {
            if (getChildAt(i).equals(listItem)) {
                return mFirstPosition + i;
            }
        }

        // Child not found!
        return INVALID_POSITION;
    }

    /**
     * Returns the position within the adapter's data set for the first item
     * displayed on screen.
     *
     * @return The position within the adapter's data set
     */
    public int getFirstVisiblePosition() {
        return mFirstPosition;
    }

    /**
     * Returns the position within the adapter's data set for the last item
     * displayed on screen.
     *
     * @return The position within the adapter's data set
     */
    public int getLastVisiblePosition() {
        return mFirstPosition + getChildCount() - 1;
    }

    /**
     * Sets the currently selected item
     * @param position Index (starting at 0) of the data item to be selected.
     */
    public abstract void setSelection(int position);

    /**
     * Sets the view to show if the adapter is empty
     */
    public void setEmptyView(View emptyView) {
        mEmptyView = emptyView;

        final T adapter = getAdapter();
        final boolean empty = ((adapter == null) || adapter.isEmpty());
        updateEmptyStatus(empty);
    }

    /**
     * When the current adapter is empty, the AdapterView can display a special view
     * call the empty view. The empty view is used to provide feedback to the user
     * that no data is available in this AdapterView.
     *
     * @return The view to show if the adapter is empty.
     */
    public View getEmptyView() {
        return mEmptyView;
    }

    /**
     * Indicates whether this view is in filter mode. Filter mode can for instance
     * be enabled by a user when typing on the keyboard.
     *
     * @return True if the view is in filter mode, false otherwise.
     */
    boolean isInFilterMode() {
        return false;
    }

    @Override
    public void setFocusable(boolean focusable) {
        final T adapter = getAdapter();
        final boolean empty = adapter == null || adapter.getCount() == 0;

        mDesiredFocusableState = focusable;
        if (!focusable) {
            mDesiredFocusableInTouchModeState = false;
        }

        super.setFocusable(focusable && (!empty || isInFilterMode()));
    }

    @Override
    public void setFocusableInTouchMode(boolean focusable) {
        final T adapter = getAdapter();
        final boolean empty = adapter == null || adapter.getCount() == 0;

        mDesiredFocusableInTouchModeState = focusable;
        if (focusable) {
            mDesiredFocusableState = true;
        }

        super.setFocusableInTouchMode(focusable && (!empty || isInFilterMode()));
    }

    void checkFocus() {
        final T adapter = getAdapter();
        final boolean empty = adapter == null || adapter.getCount() == 0;
        final boolean focusable = !empty || isInFilterMode();
        // The order in which we set focusable in touch mode/focusable may matter
        // for the client, see View.setFocusableInTouchMode() comments for more
        // details
        super.setFocusableInTouchMode(focusable && mDesiredFocusableInTouchModeState);
        super.setFocusable(focusable && mDesiredFocusableState);
        if (mEmptyView != null) {
            updateEmptyStatus((adapter == null) || adapter.isEmpty());
        }
    }

    /**
     * Update the status of the list based on the empty parameter.  If empty is true and
     * we have an empty view, display it.  In all the other cases, make sure that the listview
     * is VISIBLE and that the empty view is GONE (if it's not null).
     */
    private void updateEmptyStatus(boolean empty) {
        if (isInFilterMode()) {
            empty = false;
        }

        if (empty) {
            if (mEmptyView != null) {
                mEmptyView.setVisibility(View.VISIBLE);
                setVisibility(View.GONE);
            } else {
                // If the caller just removed our empty view, make sure the list view is visible
                setVisibility(View.VISIBLE);
            }

            // We are now GONE, so pending layouts will not be dispatched.
            // Force one here to make sure that the state of the list matches
            // the state of the adapter.
            if (mDataChanged) {          
                this.onLayout(false, getLeft(), getTop(), getRight(), getBottom());
            }
        } else {
            if (mEmptyView != null) mEmptyView.setVisibility(View.GONE);
            setVisibility(View.VISIBLE);
        }
    }

    /**
     * Gets the data associated with the specified position in the list.
     *
     * @param position Which data to get
     * @return The data associated with the specified position in the list
     */
    public Object getItemAtPosition(int position) {
        T adapter = getAdapter();
        return (adapter == null || position < 0) ? null : adapter.getItem(position);
    }

    public long getItemIdAtPosition(int position) {
        T adapter = getAdapter();
        return (adapter == null || position < 0) ? INVALID_ROW_ID : adapter.getItemId(position);
    }

    @Override
    public void setOnClickListener(OnClickListener l) {
        throw new RuntimeException("Don't call setOnClickListener for an AdapterView. "
                + "You probably want setOnItemClickListener instead");
    }

    /**
     * Override to prevent freezing of any views created by the adapter.
     */
    @Override
    protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
        dispatchFreezeSelfOnly(container);
    }

    /**
     * Override to prevent thawing of any views created by the adapter.
     */
    @Override
    protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
        dispatchThawSelfOnly(container);
    }

    class AdapterDataSetObserver extends DataSetObserver {

        private Parcelable mInstanceState = null;

        @Override
        public void onChanged() {
            mDataChanged = true;
            mOldItemCount = mItemCount;
            mItemCount = getAdapter().getCount();

            // Detect the case where a cursor that was previously invalidated has
            // been repopulated with new data.
            if (CoverAdapterView.this.getAdapter().hasStableIds() && mInstanceState != null
                    && mOldItemCount == 0 && mItemCount > 0) {
             CoverAdapterView.this.onRestoreInstanceState(mInstanceState);
                mInstanceState = null;
            } else {
                rememberSyncState();
            }
            checkFocus();
            requestLayout();
        }

        @Override
        public void onInvalidated() {
            mDataChanged = true;

            if (CoverAdapterView.this.getAdapter().hasStableIds()) {
                // Remember the current state for the case where our hosting activity is being
                // stopped and later restarted
                mInstanceState = CoverAdapterView.this.onSaveInstanceState();
            }

            // Data is invalid so we should reset our state
            mOldItemCount = mItemCount;
            mItemCount = 0;
            mSelectedPosition = INVALID_POSITION;
            mSelectedRowId = INVALID_ROW_ID;
            mNextSelectedPosition = INVALID_POSITION;
            mNextSelectedRowId = INVALID_ROW_ID;
            mNeedSync = false;
            checkSelectionChanged();

            checkFocus();
            requestLayout();
        }

        public void clearSavedState() {
            mInstanceState = null;
        }
    }

    private class SelectionNotifier extends Handler implements Runnable {
        public void run() {
            if (mDataChanged) {
                // Data has changed between when this SelectionNotifier
                // was posted and now. We need to wait until the AdapterView
                // has been synched to the new data.
                post(this);
            } else {
                fireOnSelected();
            }
        }
    }

    void selectionChanged() {
        if (mOnItemSelectedListener != null) {
            if (mInLayout || mBlockLayoutRequests) {
                // If we are in a layout traversal, defer notification
                // by posting. This ensures that the view tree is
                // in a consistent state and is able to accomodate
                // new layout or invalidate requests.
                if (mSelectionNotifier == null) {
                    mSelectionNotifier = new SelectionNotifier();
                }
                mSelectionNotifier.post(mSelectionNotifier);
            } else {
                fireOnSelected();
            }
        }
    }

    private void fireOnSelected() {
        if (mOnItemSelectedListener == null)
            return;

        int selection = this.getSelectedItemPosition();
        if (selection >= 0) {
            View v = getSelectedView();
            mOnItemSelectedListener.onItemSelected(this, v, selection,
                    getAdapter().getItemId(selection));
        } else {
            mOnItemSelectedListener.onNothingSelected(this);
        }
    }

    @Override
    protected boolean canAnimate() {
        return super.canAnimate() && mItemCount > 0;
    }

    void handleDataChanged() {
        final int count = mItemCount;
        boolean found = false;

        if (count > 0) {

            int newPos;

            // Find the row we are supposed to sync to
            if (mNeedSync) {
                // Update this first, since setNextSelectedPositionInt inspects
                // it
                mNeedSync = false;

                // See if we can find a position in the new data with the same
                // id as the old selection
                newPos = findSyncPosition();
                if (newPos >= 0) {
                    // Verify that new selection is selectable
                    int selectablePos = lookForSelectablePosition(newPos, true);
                    if (selectablePos == newPos) {
                        // Same row id is selected
                        setNextSelectedPositionInt(newPos);
                        found = true;
                    }
                }
            }
            if (!found) {
                // Try to use the same position if we can't find matching data
                newPos = getSelectedItemPosition();

                // Pin position to the available range
                if (newPos >= count) {
                    newPos = count - 1;
                }
                if (newPos < 0) {
                    newPos = 0;
                }

                // Make sure we select something selectable -- first look down
                int selectablePos = lookForSelectablePosition(newPos, true);
                if (selectablePos < 0) {
                    // Looking down didn't work -- try looking up
                    selectablePos = lookForSelectablePosition(newPos, false);
                }
                if (selectablePos >= 0) {
                    setNextSelectedPositionInt(selectablePos);
                    checkSelectionChanged();
                    found = true;
                }
            }
        }
        if (!found) {
            // Nothing is selected
            mSelectedPosition = INVALID_POSITION;
            mSelectedRowId = INVALID_ROW_ID;
            mNextSelectedPosition = INVALID_POSITION;
            mNextSelectedRowId = INVALID_ROW_ID;
            mNeedSync = false;
            checkSelectionChanged();
        }
    }

    void checkSelectionChanged() {
        if ((mSelectedPosition != mOldSelectedPosition) || (mSelectedRowId != mOldSelectedRowId)) {
            selectionChanged();
            mOldSelectedPosition = mSelectedPosition;
            mOldSelectedRowId = mSelectedRowId;
        }
    }

    /**
     * Searches the adapter for a position matching mSyncRowId. The search starts at mSyncPosition
     * and then alternates between moving up and moving down until 1) we find the right position, or
     * 2) we run out of time, or 3) we have looked at every position
     *
     * @return Position of the row that matches mSyncRowId, or {@link #INVALID_POSITION} if it can't
     *         be found
     */
    int findSyncPosition() {
        int count = mItemCount;

        if (count == 0) {
            return INVALID_POSITION;
        }

        long idToMatch = mSyncRowId;
        int seed = mSyncPosition;

        // If there isn't a selection don't hunt for it
        if (idToMatch == INVALID_ROW_ID) {
            return INVALID_POSITION;
        }

        // Pin seed to reasonable values
        seed = Math.max(0, seed);
        seed = Math.min(count - 1, seed);

        long endTime = SystemClock.uptimeMillis() + SYNC_MAX_DURATION_MILLIS;

        long rowId;

        // first position scanned so far
        int first = seed;

        // last position scanned so far
        int last = seed;

        // True if we should move down on the next iteration
        boolean next = false;

        // True when we have looked at the first item in the data
        boolean hitFirst;

        // True when we have looked at the last item in the data
        boolean hitLast;

        // Get the item ID locally (instead of getItemIdAtPosition), so
        // we need the adapter
        T adapter = getAdapter();
        if (adapter == null) {
            return INVALID_POSITION;
        }

        while (SystemClock.uptimeMillis() <= endTime) {
            rowId = adapter.getItemId(seed);
            if (rowId == idToMatch) {
                // Found it!
                return seed;
            }

            hitLast = last == count - 1;
            hitFirst = first == 0;

            if (hitLast && hitFirst) {
                // Looked at everything
                break;
            }

            if (hitFirst || (next && !hitLast)) {
                // Either we hit the top, or we are trying to move down
                last++;
                seed = last;
                // Try going up next time
                next = false;
            } else if (hitLast || (!next && !hitFirst)) {
                // Either we hit the bottom, or we are trying to move up
                first--;
                seed = first;
                // Try going down next time
                next = true;
            }

        }

        return INVALID_POSITION;
    }

    /**
     * Find a position that can be selected (i.e., is not a separator).
     *
     * @param position The starting position to look at.
     * @param lookDown Whether to look down for other positions.
     * @return The next selectable position starting at position and then searching either up or
     *         down. Returns {@link #INVALID_POSITION} if nothing can be found.
     */
    int lookForSelectablePosition(int position, boolean lookDown) {
        return position;
    }

    /**
     * Utility to keep mSelectedPosition and mSelectedRowId in sync
     * @param position Our current position
     */
    void setSelectedPositionInt(int position) {
        mSelectedPosition = position;
        mSelectedRowId = getItemIdAtPosition(position);
    }

    /**
     * Utility to keep mNextSelectedPosition and mNextSelectedRowId in sync
     * @param position Intended value for mSelectedPosition the next time we go
     * through layout
     */
    void setNextSelectedPositionInt(int position) {
        mNextSelectedPosition = position;
        mNextSelectedRowId = getItemIdAtPosition(position);
        // If we are trying to sync to the selection, update that too
        if (mNeedSync && mSyncMode == SYNC_SELECTED_POSITION && position >= 0) {
            mSyncPosition = position;
            mSyncRowId = mNextSelectedRowId;
        }
    }

    /**
     * Remember enough information to restore the screen state when the data has
     * changed.
     *
     */
    void rememberSyncState() {
        if (getChildCount() > 0) {
            mNeedSync = true;
            mSyncHeight = mLayoutHeight;
            if (mSelectedPosition >= 0) {
                // Sync the selection state
                View v = getChildAt(mSelectedPosition - mFirstPosition);
                mSyncRowId = mNextSelectedRowId;
                mSyncPosition = mNextSelectedPosition;
                if (v != null) {
                    mSpecificTop = v.getTop();
                }
                mSyncMode = SYNC_SELECTED_POSITION;
            } else {
                // Sync the based on the offset of the first view
                View v = getChildAt(0);
                T adapter = getAdapter();
                if (mFirstPosition >= 0 && mFirstPosition < adapter.getCount()) {
                    mSyncRowId = adapter.getItemId(mFirstPosition);
                } else {
                    mSyncRowId = NO_ID;
                }
                mSyncPosition = mFirstPosition;
                if (v != null) {
                    mSpecificTop = v.getTop();
                }
                mSyncMode = SYNC_FIRST_POSITION;
            }
        }
    }
}

Create third class CoverFlow.java
====================

import android.R;
import android.content.Context;
import android.graphics.Camera;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.GestureDetector;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.SoundEffectConstants;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.animation.Transformation;
import android.widget.Gallery;
import android.widget.ImageView;
import android.widget.Scroller;

/**
 * A view that shows items in a center-locked, horizontally scrolling list. In
 * a Coverflow like Style.
 * <p>
 * The default values for the Gallery assume you will be using
 * {@link android.R.styleable#Theme_galleryItemBackground} as the background for
 * each View given to the Gallery from the Adapter. If you are not doing this,
 * you may need to adjust some Gallery properties, such as the spacing.
 * <p>
 * Views given to the Gallery should use {@link Gallery.LayoutParams} as their
 * layout parameters type.
 *
 * @attr ref android.R.styleable#Gallery_animationDuration
 * @attr ref android.R.styleable#Gallery_spacing
 * @attr ref android.R.styleable#Gallery_gravity
 */

public class CoverFlow extends CoverAbsSpinner implements GestureDetector.OnGestureListener {

    private static final String TAG = "CoverFlow";

    private static final boolean localLOGV = false;

    /**
     * Duration in milliseconds from the start of a scroll during which we're
     * unsure whether the user is scrolling or flinging.
     */
    private static final int SCROLL_TO_FLING_UNCERTAINTY_TIMEOUT = 250;

    /**
     * Horizontal spacing between items.
     */
   
    private int mSpacing = 0;

    /**
     * How long the transition animation should run when a child view changes
     * position, measured in milliseconds.
     */
    private int mAnimationDuration = 2000;

    /**
     * The alpha of items that are not selected.
     */
    private float mUnselectedAlpha;
   
    /**
     * Left most edge of a child seen so far during layout.
     */
    private int mLeftMost;

    /**
     * Right most edge of a child seen so far during layout.
     */
    private int mRightMost;

    private int mGravity;

    /**
     * Helper for detecting touch gestures.
     */
    private GestureDetector mGestureDetector;

    /**
     * The position of the item that received the user's down touch.
     */
    private int mDownTouchPosition;

    /**
     * The view of the item that received the user's down touch.
     */
    private View mDownTouchView;
   
    /**
     * Executes the delta scrolls from a fling or scroll movement.
     */
    private FlingRunnable mFlingRunnable = new FlingRunnable();

    /**
     * Sets mSuppressSelectionChanged = false. This is used to set it to false
     * in the future. It will also trigger a selection changed.
     */
    private Runnable mDisableSuppressSelectionChangedRunnable = new Runnable() {
        public void run() {
            mSuppressSelectionChanged = false;
            selectionChanged();
        }
    };
   
    /**
     * When fling runnable runs, it resets this to false. Any method along the
     * path until the end of its run() can set this to true to abort any
     * remaining fling. For example, if we've reached either the leftmost or
     * rightmost item, we will set this to true.
     */
    private boolean mShouldStopFling;
   
    /**
     * The currently selected item's child.
     */
    private View mSelectedChild;
   
    /**
     * Whether to continuously callback on the item selected listener during a
     * fling.
     */
    private boolean mShouldCallbackDuringFling = true;

    /**
     * Whether to callback when an item that is not selected is clicked.
     */
    private boolean mShouldCallbackOnUnselectedItemClick = true;

    /**
     * If true, do not callback to item selected listener.
     */
    private boolean mSuppressSelectionChanged;

    /**
     * If true, we have received the "invoke" (center or enter buttons) key
     * down. This is checked before we action on the "invoke" key up, and is
     * subsequently cleared.
     */
    private boolean mReceivedInvokeKeyDown;
   
    private AdapterContextMenuInfo mContextMenuInfo;

    /**
     * If true, this onScroll is the first for this user's drag (remember, a
     * drag sends many onScrolls).
     */
    private boolean mIsFirstScroll;

    /**
     * Graphics Camera used for transforming the matrix of ImageViews
     */
    private Camera mCamera = new Camera();

    /**
     * The maximum angle the Child ImageView will be rotated by
     */   
    private int mMaxRotationAngle = 60;
   
    /**
     * The maximum zoom on the centre Child
     */
    private static int mMaxZoom = -120;
  
    public CoverFlow(Context context) {
        this(context, null);
    }

    public CoverFlow(Context context, AttributeSet attrs) {
        this(context, attrs, R.attr.galleryStyle);
    }

    public CoverFlow(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
       
        mGestureDetector = new GestureDetector(this);
        mGestureDetector.setIsLongpressEnabled(true);
       
//        TypedArray a = context.obtainStyledAttributes(
//                attrs, com.android.internal.R.styleable.Gallery, defStyle, 0);
//
//        int index = a.getInt(com.android.internal.R.styleable.Gallery_gravity, -1);
//        if (index >= 0) {
//            setGravity(index);
//        }
//
//        int animationDuration =
//                a.getInt(com.android.internal.R.styleable.Gallery_animationDuration, -1);
//        if (animationDuration > 0) {
//            setAnimationDuration(animationDuration);
//        }
//
//        int spacing =
//                a.getDimensionPixelOffset(com.android.internal.R.styleable.Gallery_spacing, 0);
//        setSpacing(spacing);
//
//        float unselectedAlpha = a.getFloat(
//                com.android.internal.R.styleable.Gallery_unselectedAlpha, 0.5f);
//        setUnselectedAlpha(unselectedAlpha);
//       
//        a.recycle();
//
//        // We draw the selected item last (because otherwise the item to the
//        // right overlaps it)
//        mGroupFlags |= FLAG_USE_CHILD_DRAWING_ORDER;
//       
//        mGroupFlags |= FLAG_SUPPORT_STATIC_TRANSFORMATIONS;
    }

    /**
     * Whether or not to callback on any {@link #getOnItemSelectedListener()}
     * while the items are being flinged. If false, only the final selected item
     * will cause the callback. If true, all items between the first and the
     * final will cause callbacks.
     *
     * @param shouldCallback Whether or not to callback on the listener while
     *            the items are being flinged.
     */
    public void setCallbackDuringFling(boolean shouldCallback) {
        mShouldCallbackDuringFling = shouldCallback;
    }

    /**
     * Whether or not to callback when an item that is not selected is clicked.
     * If false, the item will become selected (and re-centered). If true, the
     * {@link #getOnItemClickListener()} will get the callback.
     *
     * @param shouldCallback Whether or not to callback on the listener when a
     *            item that is not selected is clicked.
     * @hide
     */
    public void setCallbackOnUnselectedItemClick(boolean shouldCallback) {
        mShouldCallbackOnUnselectedItemClick = shouldCallback;
    }
   
    /**
     * Sets how long the transition animation should run when a child view
     * changes position. Only relevant if animation is turned on.
     *
     * @param animationDurationMillis The duration of the transition, in
     *        milliseconds.
     *
     * @attr ref android.R.styleable#Gallery_animationDuration
     */
    public void setAnimationDuration(int animationDurationMillis) {
        mAnimationDuration = animationDurationMillis;
    }

    /**
     * Sets the spacing between items in a Gallery
     *
     * @param spacing The spacing in pixels between items in the Gallery
     *
     * @attr ref android.R.styleable#Gallery_spacing
     */
    public void setSpacing(int spacing) {
        mSpacing = spacing;
    }

    /**
     * Sets the alpha of items that are not selected in the Gallery.
     *
     * @param unselectedAlpha the alpha for the items that are not selected.
     *
     * @attr ref android.R.styleable#Gallery_unselectedAlpha
     */
    public void setUnselectedAlpha(float unselectedAlpha) {
        mUnselectedAlpha = unselectedAlpha;
    }

    @Override
    protected boolean getChildStaticTransformation(View child, Transformation t) {
       
        t.clear();
        t.setAlpha(child == mSelectedChild ? 1.0f : mUnselectedAlpha);
       
        return true;
    }

    @Override
    protected int computeHorizontalScrollExtent() {
        // Only 1 item is considered to be selected
        return 1;
    }

    @Override
    protected int computeHorizontalScrollOffset() {
        // Current scroll position is the same as the selected position
        return getSelectedItemPosition();
    }

    @Override
    protected int computeHorizontalScrollRange() {
        // Scroll range is the same as the item count
        return getCount();
    }

    @Override
    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
        return p instanceof LayoutParams;
    }

    @Override
    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
        return new LayoutParams(p);
    }

    @Override
    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new LayoutParams(getContext(), attrs);
    }

    @Override
    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
        /*
         * Gallery expects Gallery.LayoutParams.
         */
        return new CoverFlow.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
                ViewGroup.LayoutParams.WRAP_CONTENT);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
       
        /*
         * Remember that we are in layout to prevent more layout request from
         * being generated.
         */
        mInLayout = true;
        layout(0, false);
        mInLayout = false;
    }

   
    int getChildHeight(View child) {
        return child.getMeasuredHeight();
    }
   
    /**
     * Tracks a motion scroll. In reality, this is used to do just about any
     * movement to items (touch scroll, arrow-key scroll, set an item as selected).
     *
     * @param deltaX Change in X from the previous event.
     */
    void trackMotionScroll(int deltaX) {

        if (getChildCount() == 0) {
            return;
        }
       
        boolean toLeft = deltaX < 0;
       
        int limitedDeltaX = getLimitedMotionScrollAmount(toLeft, deltaX);
        if (limitedDeltaX != deltaX) {
            // The above call returned a limited amount, so stop any scrolls/flings
            mFlingRunnable.endFling(false);
            onFinishedMovement();
        }
       
        offsetChildrenLeftAndRight(limitedDeltaX, toLeft);
       
        detachOffScreenChildren(toLeft);
       
        if (toLeft) {
            // If moved left, there will be empty space on the right
            fillToGalleryRight();
        } else {
            // Similarly, empty space on the left
            fillToGalleryLeft();
        }
       
        // Clear unused views
        mRecycler.clear();
       
        setSelectionToCenterChild();
       
        invalidate();
    }

    int getLimitedMotionScrollAmount(boolean motionToLeft, int deltaX) {
        int extremeItemPosition = motionToLeft ? mItemCount - 1 : 0;
        View extremeChild = getChildAt(extremeItemPosition - mFirstPosition);
       
        if (extremeChild == null) {
            return deltaX;
        }
       
        int extremeChildCenter = getCenterOfView(extremeChild);
        int galleryCenter = getCenterOfGallery();
       
        if (motionToLeft) {
            if (extremeChildCenter <= galleryCenter) {
               
                // The extreme child is past his boundary point!
                return 0;
            }
        } else {
            if (extremeChildCenter >= galleryCenter) {

                // The extreme child is past his boundary point!
                return 0;
            }
        }
       
        int centerDifference = galleryCenter - extremeChildCenter;

        return motionToLeft
                ? Math.max(centerDifference, deltaX)
                : Math.min(centerDifference, deltaX);
    }

    /**
     * Offset the horizontal location of all children of this view by the
     * specified number of pixels.
     * Modified to also rotate and scale images depending on screen position.
     *
     * @param offset the number of pixels to offset
     */
    private void offsetChildrenLeftAndRight(int offset, boolean toLeft) {
     
     ImageView child;
     int childCount = getChildCount();
     int rotationAngle = 0;
     int childCenter;
     int galleryCenter = getCenterOfGallery();
     float childWidth;
    
        for (int i = childCount - 1; i >= 0; i--) {
         child = (ImageView) getChildAt(i);
         childCenter = getCenterOfView(child);
         childWidth = child.getWidth() ;
        
         if (childCenter == galleryCenter) {
          transformImageBitmap(child, 0,  false, 0);
         } else {     
          rotationAngle = (int) (((float) (galleryCenter - childCenter)/ childWidth) *  mMaxRotationAngle);
       if (Math.abs(rotationAngle) > mMaxRotationAngle) {
        rotationAngle = (rotationAngle < 0) ? -mMaxRotationAngle : mMaxRotationAngle;  
       }
       transformImageBitmap(child, 0, false, rotationAngle);        
         }         
            child.offsetLeftAndRight(offset);
        }
    }
   
    /**
     * @return The center of this Gallery.
     */
    private int getCenterOfGallery() {
        return (getWidth() - getPaddingLeft() - getPaddingRight()) / 2 + getPaddingLeft();
    }
   
    /**
     * @return The center of the given view.
     */
    private static int getCenterOfView(View view) {
        return view.getLeft() + view.getWidth() / 2;
    }
   
    /**
     * Detaches children that are off the screen (i.e.: Gallery bounds).
     *
     * @param toLeft Whether to detach children to the left of the Gallery, or
     *            to the right.
     */
    private void detachOffScreenChildren(boolean toLeft) {
        int numChildren = getChildCount();
        int firstPosition = mFirstPosition;
        int start = 0;
        int count = 0;

        if (toLeft) {
            final int galleryLeft = getPaddingLeft();
            for (int i = 0; i < numChildren; i++) {
                final View child = getChildAt(i);
                if (child.getRight() >= galleryLeft) {
                    break;
                } else {
                    count++;
                    mRecycler.put(firstPosition + i, child);
                }
            }
        } else {
            final int galleryRight = getWidth() - getPaddingRight();
            for (int i = numChildren - 1; i >= 0; i--) {
                final View child = getChildAt(i);
                if (child.getLeft() <= galleryRight) {
                    break;
                } else {
                    start = i;
                    count++;
                    mRecycler.put(firstPosition + i, child);
                }
            }
        }

        detachViewsFromParent(start, count);
       
        if (toLeft) {
            mFirstPosition += count;
        }
    }
   
    /**
     * Scrolls the items so that the selected item is in its 'slot' (its center
     * is the gallery's center).
     */
    private void scrollIntoSlots() {
       
        if (getChildCount() == 0 || mSelectedChild == null) return;
       
        int selectedCenter = getCenterOfView(mSelectedChild);
        int targetCenter = getCenterOfGallery();
       
        int scrollAmount = targetCenter - selectedCenter;
        if (scrollAmount != 0) {
            mFlingRunnable.startUsingDistance(scrollAmount);
        } else {
            onFinishedMovement();
        }
    }

    private void onFinishedMovement() {
        if (mSuppressSelectionChanged) {
            mSuppressSelectionChanged = false;
           
            // We haven't been callbacking during the fling, so do it now
            super.selectionChanged();
        }
        invalidate();
    }
   
    @Override
    void selectionChanged() {
        if (!mSuppressSelectionChanged) {
            super.selectionChanged();
        }
    }

    /**
     * Looks for the child that is closest to the center and sets it as the
     * selected child.
     */
    private void setSelectionToCenterChild() {
       
        View selView = mSelectedChild;
        if (mSelectedChild == null) return;
       
        int galleryCenter = getCenterOfGallery();
       
        // Common case where the current selected position is correct
        if (selView.getLeft() <= galleryCenter && selView.getRight() >= galleryCenter) {
            return;
        }
       
        // TODO better search
        int closestEdgeDistance = Integer.MAX_VALUE;
        int newSelectedChildIndex = 0;
        for (int i = getChildCount() - 1; i >= 0; i--) {
           
            View child = getChildAt(i);
           
            if (child.getLeft() <= galleryCenter && child.getRight() >=  galleryCenter) {
                // This child is in the center
                newSelectedChildIndex = i;
                break;
            }
           
            int childClosestEdgeDistance = Math.min(Math.abs(child.getLeft() - galleryCenter),
                    Math.abs(child.getRight() - galleryCenter));
            if (childClosestEdgeDistance < closestEdgeDistance) {
                closestEdgeDistance = childClosestEdgeDistance;
                newSelectedChildIndex = i;
            }
        }
       
        int newPos = mFirstPosition + newSelectedChildIndex;
       
        if (newPos != mSelectedPosition) {
            setSelectedPositionInt(newPos);
            setNextSelectedPositionInt(newPos);
            checkSelectionChanged();
        }
    }

    /**
     * Creates and positions all views for this Gallery.
     * <p>
     * We layout rarely, most of the time {@link #trackMotionScroll(int)} takes
     * care of repositioning, adding, and removing children.
     *
     * @param delta Change in the selected position. +1 means the selection is
     *            moving to the right, so views are scrolling to the left. -1
     *            means the selection is moving to the left.
     */
    @Override
    void layout(int delta, boolean animate) {

        int childrenLeft = mSpinnerPadding.left;
        int childrenWidth = getRight() - getLeft() - mSpinnerPadding.left - mSpinnerPadding.right;

        if (mDataChanged) {
            handleDataChanged();
        }

        // Handle an empty gallery by removing all views.
        if (mItemCount == 0) {
            resetList();
            return;
        }

        // Update to the new selected position.
        if (mNextSelectedPosition >= 0) {
            setSelectedPositionInt(mNextSelectedPosition);
        }

        // All views go in recycler while we are in layout
        recycleAllViews();

        // Clear out old views
        //removeAllViewsInLayout();
        detachAllViewsFromParent();

        /*
         * These will be used to give initial positions to views entering the
         * gallery as we scroll
         */
        mRightMost = 0;
        mLeftMost = 0;

        // Make selected view and center it
       
        /*
         * mFirstPosition will be decreased as we add views to the left later
         * on. The 0 for x will be offset in a couple lines down.
         */ 
        mFirstPosition = mSelectedPosition;
        View sel = makeAndAddView(mSelectedPosition, 0, 0, true);
       
        // Put the selected child in the center
        int selectedOffset = childrenLeft + (childrenWidth / 2) - (sel.getWidth() / 2);
        sel.offsetLeftAndRight(selectedOffset);

        fillToGalleryRight();
        fillToGalleryLeft();
       
        // Flush any cached views that did not get reused above
        mRecycler.clear();

        invalidate();
        checkSelectionChanged();

        mDataChanged = false;
        mNeedSync = false;
        setNextSelectedPositionInt(mSelectedPosition);
       
        updateSelectedItemMetadata();
    }

    private void fillToGalleryLeft() {
        int itemSpacing = mSpacing;
        int galleryLeft = getPaddingLeft();
       
        // Set state for initial iteration
        View prevIterationView = getChildAt(0);
        int curPosition;
        int curRightEdge;
       
        if (prevIterationView != null) {
            curPosition = mFirstPosition - 1;
            curRightEdge = prevIterationView.getLeft() - itemSpacing;
        } else {
            // No children available!
            curPosition = 0;
            curRightEdge = getRight() - getLeft() - getPaddingRight();
            mShouldStopFling = true;
        }
               
        while (curRightEdge > galleryLeft && curPosition >= 0) {
            prevIterationView = makeAndAddView(curPosition, curPosition - mSelectedPosition,
                    curRightEdge, false);

            // Remember some state
            mFirstPosition = curPosition;
           
            // Set state for next iteration
            curRightEdge = prevIterationView.getLeft() - itemSpacing;
            curPosition--;
        }
    }
   
    private void fillToGalleryRight() {
        int itemSpacing = mSpacing;
        int galleryRight = getRight() - getLeft() - getPaddingRight();
        int numChildren = getChildCount();
        int numItems = mItemCount;
       
        // Set state for initial iteration
        View prevIterationView = getChildAt(numChildren - 1);
        int curPosition;
        int curLeftEdge;
       
        if (prevIterationView != null) {
            curPosition = mFirstPosition + numChildren;
            curLeftEdge = prevIterationView.getRight() + itemSpacing;
        } else {
            mFirstPosition = curPosition = mItemCount - 1;
            curLeftEdge = getPaddingLeft();
            mShouldStopFling = true;
        }
               
        while (curLeftEdge < galleryRight && curPosition < numItems) {
            prevIterationView = makeAndAddView(curPosition, curPosition - mSelectedPosition,
                    curLeftEdge, true);

            // Set state for next iteration
            curLeftEdge = prevIterationView.getRight() + itemSpacing;
            curPosition++;
        }
    }

    /**
     * Transform the Image Bitmap by the Angle passed
     *
     * @param imageView ImageView the ImageView whose bitmap we want to rotate
     * @param offset Offset from the selected position
     * @param initialLayout Is this a called from an initial layout
     * @param rotationAngle the Angle by which to rotate the Bitmap
     */
    static private void transformImageBitmap(ImageView imageView,int offset,
       boolean initialLayout, int rotationAngle) {
        Camera camera = new Camera();
        Matrix imageMatrix;
        int imageHeight;
        int imageWidth;
        int bitMapHeight;
        int bitMapWidth;
        float scaleWidth;
        float scaleHeight;
     
        imageMatrix = imageView.getImageMatrix();
               
        camera.translate(0.0f, 0.0f, 100.0f);
       
        if (initialLayout) {
         if(offset < 0) {        
          camera.rotateY(rotationAngle);
         } else if (offset > 0) {
          camera.rotateY(-rotationAngle);
         } else {
          //Just zoom in a little for the central View
          camera.translate(0.0f, 0.0f, mMaxZoom);
         
         }
        } else {
         if (offset == 0) {
          //As the angle of the view gets less, zoom in
          int rotation = Math.abs(rotationAngle);
          if ( rotation < 30 ) {
           float zoomAmount = (float) (mMaxZoom +  (rotation * 1.5));
           camera.translate(0.0f, 0.0f, zoomAmount);         
          }
          camera.rotateY(rotationAngle);
         }
        }
        
        camera.getMatrix(imageMatrix);              
       
        imageHeight = imageView.getLayoutParams().height;
        imageWidth = imageView.getLayoutParams().width;
        bitMapHeight = imageView.getDrawable().getIntrinsicHeight();
        bitMapWidth = imageView.getDrawable().getIntrinsicWidth();
        scaleHeight = ((float) imageHeight) / bitMapHeight;
        scaleWidth = ((float) imageWidth) / bitMapWidth;
       
        imageMatrix.preTranslate(-(imageWidth/2), -(imageHeight/2));
        imageMatrix.preScale(scaleWidth, scaleHeight); 
        imageMatrix.postTranslate((imageWidth/2), (imageHeight/2));
      
    }
    /**
     * Obtain a view, either by pulling an existing view from the recycler or by
     * getting a new one from the adapter. If we are animating, make sure there
     * is enough information in the view's layout parameters to animate from the
     * old to new positions.
     *
     * @param position Position in the gallery for the view to obtain
     * @param offset Offset from the selected position
     * @param x X-coordinate indicating where this view should be placed. This
     *        will either be the left or right edge of the view, depending on
     *        the fromLeft parameter
     * @param fromLeft Are we positioning views based on the left edge? (i.e.,
     *        building from left to right)?
     * @return A view that has been added to the gallery
     */
    private View makeAndAddView(int position, int offset, int x,
            boolean fromLeft) {

        ImageView child;
       
        if (!mDataChanged) {
            child = (ImageView) mRecycler.get(position);
           
            if (child != null) {
                // Can reuse an existing view
                int childLeft = child.getLeft();
               
                // Remember left and right edges of where views have been placed
                mRightMost = Math.max(mRightMost, childLeft
                        + child.getMeasuredWidth());
                mLeftMost = Math.min(mLeftMost, childLeft);

                transformImageBitmap(child, offset, true, mMaxRotationAngle);
                // Position the view
                setUpChild(child, offset, x, fromLeft);

                return child;
            }
        }

        // Nothing found in the recycler -- ask the adapter for a view
        child = (ImageView) mAdapter.getView(position, null, this);
       
        //Make sure we set anti-aliasing otherwise we get jaggies
        BitmapDrawable drawable = (BitmapDrawable) child.getDrawable();
        drawable.setAntiAlias(true);
       
        Drawable imageDrawable = child.getDrawable();
        //imageDrawable.mutate();
          
        transformImageBitmap(child, offset, true, mMaxRotationAngle);
        // Position the view
        setUpChild(child, offset, x, fromLeft);

        return child;
    }

    /**
     * Helper for makeAndAddView to set the position of a view and fill out its
     * layout paramters.
     *
     * @param child The view to position
     * @param offset Offset from the selected position
     * @param x X-coordintate indicating where this view should be placed. This
     *        will either be the left or right edge of the view, depending on
     *        the fromLeft paramter
     * @param fromLeft Are we posiitoning views based on the left edge? (i.e.,
     *        building from left to right)?
     */
    private void setUpChild(View child, int offset, int x, boolean fromLeft) {

        // Respect layout params that are already in the view. Otherwise
        // make some up...
        CoverFlow.LayoutParams lp = (CoverFlow.LayoutParams)
            child.getLayoutParams();
        if (lp == null) {
            lp = (CoverFlow.LayoutParams) generateDefaultLayoutParams();
        }

        addViewInLayout(child, fromLeft ? -1 : 0, lp);

        child.setSelected(offset == 0);

        // Get measure specs
        int childHeightSpec = ViewGroup.getChildMeasureSpec(mHeightMeasureSpec,
                mSpinnerPadding.top + mSpinnerPadding.bottom, lp.height);
        int childWidthSpec = ViewGroup.getChildMeasureSpec(mWidthMeasureSpec,
                mSpinnerPadding.left + mSpinnerPadding.right, lp.width);

        // Measure child
        child.measure(childWidthSpec, childHeightSpec);

        int childLeft;
        int childRight;

        // Position vertically based on gravity setting
        int childTop = calculateTop(child, true);
        int childBottom = childTop + child.getMeasuredHeight();

        int width = child.getMeasuredWidth();
        if (fromLeft) {
            childLeft = x;
            childRight = childLeft + width;
        } else {
            childLeft = x - width;
            childRight = x;
        }

        child.layout(childLeft, childTop, childRight, childBottom);
    }

    /**
     * Figure out vertical placement based on mGravity
     *
     * @param child Child to place
     * @return Where the top of the child should be
     */
    private int calculateTop(View child, boolean duringLayout) {
        int myHeight = duringLayout ? getMeasuredHeight() : getHeight();
        int childHeight = duringLayout ? child.getMeasuredHeight() : child.getHeight();
       
        int childTop = 0;

        switch (mGravity) {
        case Gravity.TOP:
            childTop = mSpinnerPadding.top;
            break;
        case Gravity.CENTER_VERTICAL:
            int availableSpace = myHeight - mSpinnerPadding.bottom
                    - mSpinnerPadding.top - childHeight;
            childTop = mSpinnerPadding.top + (availableSpace / 2);
            break;
        case Gravity.BOTTOM:
            childTop = myHeight - mSpinnerPadding.bottom - childHeight;
            break;
        }
        return childTop;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        // Give everything to the gesture detector
       boolean retValue = mGestureDetector.onTouchEvent(event);

        int action = event.getAction();
        if (action == MotionEvent.ACTION_UP) {
            // Helper method for lifted finger
            onUp();
        } else if (action == MotionEvent.ACTION_CANCEL) {
            onCancel();
        }
       
        //return retValue;
        return true;
    }
   
    /**
     * {@inheritDoc}
     */
    public boolean onSingleTapUp(MotionEvent e) {

        if (mDownTouchPosition >= 0) {
           
            // An item tap should make it selected, so scroll to this child.
            scrollToChild(mDownTouchPosition - mFirstPosition);

            // Also pass the click so the client knows, if it wants to.
            if (mShouldCallbackOnUnselectedItemClick || mDownTouchPosition == mSelectedPosition) {
                performItemClick(mDownTouchView, mDownTouchPosition, mAdapter
                        .getItemId(mDownTouchPosition));
            }
           
            return true;
        }
       
        return false;
    }

    /**
     * {@inheritDoc}
     */
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
       
        if (!mShouldCallbackDuringFling) {
            // We want to suppress selection changes
           
            // Remove any future code to set mSuppressSelectionChanged = false
            removeCallbacks(mDisableSuppressSelectionChangedRunnable);

            // This will get reset once we scroll into slots
            if (!mSuppressSelectionChanged) mSuppressSelectionChanged = true;
        }
       
        // Fling the gallery!
        mFlingRunnable.startUsingVelocity((int) -velocityX);
       
        return true;
    }

    /**
     * {@inheritDoc}
     */
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {

        if (localLOGV) Log.v(TAG, String.valueOf(e2.getX() - e1.getX()));
       
        /*
         * Now's a good time to tell our parent to stop intercepting our events!
         * The user has moved more than the slop amount, since GestureDetector
         * ensures this before calling this method. Also, if a parent is more
         * interested in this touch's events than we are, it would have
         * intercepted them by now (for example, we can assume when a Gallery is
         * in the ListView, a vertical scroll would not end up in this method
         * since a ListView would have intercepted it by now).
         */
        getParent().requestDisallowInterceptTouchEvent(true);
       
        // As the user scrolls, we want to callback selection changes so related-
        // info on the screen is up-to-date with the gallery's selection
        if (!mShouldCallbackDuringFling) {
            if (mIsFirstScroll) {
                /*
                 * We're not notifying the client of selection changes during
                 * the fling, and this scroll could possibly be a fling. Don't
                 * do selection changes until we're sure it is not a fling.
                 */
                if (!mSuppressSelectionChanged) mSuppressSelectionChanged = true;
                postDelayed(mDisableSuppressSelectionChangedRunnable, SCROLL_TO_FLING_UNCERTAINTY_TIMEOUT);
            }
        } else {
            if (mSuppressSelectionChanged) mSuppressSelectionChanged = false;
        }
       
        // Track the motion
        trackMotionScroll(-1 * (int) distanceX);
      
        mIsFirstScroll = false;
        return true;
    }
   
    /**
     * {@inheritDoc}
     */
    public boolean onDown(MotionEvent e) {

        // Kill any existing fling/scroll
        mFlingRunnable.stop(false);

        // Get the item's view that was touched
        mDownTouchPosition = pointToPosition((int) e.getX(), (int) e.getY());
       
        if (mDownTouchPosition >= 0) {
            mDownTouchView = getChildAt(mDownTouchPosition - mFirstPosition);
            mDownTouchView.setPressed(true);
        }
       
        // Reset the multiple-scroll tracking state
        mIsFirstScroll = true;
       
        // Must return true to get matching events for this down event.
        return true;
    }

    /**
     * Called when a touch event's action is MotionEvent.ACTION_UP.
     */
    void onUp() {
       
        if (mFlingRunnable.mScroller.isFinished()) {
            scrollIntoSlots();
        }
       
        dispatchUnpress();
    }
   
    /**
     * Called when a touch event's action is MotionEvent.ACTION_CANCEL.
     */
    void onCancel() {
        onUp();
    }
   
    /**
     * {@inheritDoc}
     */
    public void onLongPress(MotionEvent e) {
       
        if (mDownTouchPosition < 0) {
            return;
        }
       
        //performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
        long id = getItemIdAtPosition(mDownTouchPosition);
        dispatchLongPress(mDownTouchView, mDownTouchPosition, id);
    }

    // Unused methods from GestureDetector.OnGestureListener below
   
    /**
     * {@inheritDoc}
     */
    public void onShowPress(MotionEvent e) {
    }

    // Unused methods from GestureDetector.OnGestureListener above
   
    private void dispatchPress(View child) {
       
        if (child != null) {
            child.setPressed(true);
        }
       
        setPressed(true);
    }
   
    private void dispatchUnpress() {
       
        for (int i = getChildCount() - 1; i >= 0; i--) {
            getChildAt(i).setPressed(false);
        }
       
        setPressed(false);
    }
   
    @Override
    public void dispatchSetSelected(boolean selected) {
        /*
         * We don't want to pass the selected state given from its parent to its
         * children since this widget itself has a selected state to give to its
         * children.
         */
    }

    @Override
    protected void dispatchSetPressed(boolean pressed) {
       
        // Show the pressed state on the selected child
        if (mSelectedChild != null) {
            mSelectedChild.setPressed(pressed);
        }
    }

    @Override
    protected ContextMenuInfo getContextMenuInfo() {
        return mContextMenuInfo;
    }

    @Override
    public boolean showContextMenuForChild(View originalView) {

        final int longPressPosition = getPositionForView(originalView);
        if (longPressPosition < 0) {
            return false;
        }
       
        final long longPressId = mAdapter.getItemId(longPressPosition);
        return dispatchLongPress(originalView, longPressPosition, longPressId);
    }

    @Override
    public boolean showContextMenu() {
       
        if (isPressed() && mSelectedPosition >= 0) {
            int index = mSelectedPosition - mFirstPosition;
            View v = getChildAt(index);
            return dispatchLongPress(v, mSelectedPosition, mSelectedRowId);
        }       
       
        return false;
    }

    private boolean dispatchLongPress(View view, int position, long id) {
        boolean handled = false;
       
        if (mOnItemLongClickListener != null) {
            handled = mOnItemLongClickListener.onItemLongClick(this, mDownTouchView,
                    mDownTouchPosition, id);
        }

        if (!handled) {
            mContextMenuInfo = new AdapterContextMenuInfo(view, position, id);
            handled = super.showContextMenuForChild(this);
        }

        if (handled) {
            //performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
        }
       
        return handled;
    }
   
    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        // Gallery steals all key events
        return event.dispatch(this);
    }

    /**
     * Handles left, right, and clicking
     * @see android.view.View#onKeyDown
     */
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        switch (keyCode) {
           
        case KeyEvent.KEYCODE_DPAD_LEFT:
            if (movePrevious()) {
                playSoundEffect(SoundEffectConstants.NAVIGATION_LEFT);
            }
            return true;

        case KeyEvent.KEYCODE_DPAD_RIGHT:
            if (moveNext()) {
                playSoundEffect(SoundEffectConstants.NAVIGATION_RIGHT);
            }
            return true;

        case KeyEvent.KEYCODE_DPAD_CENTER:
        case KeyEvent.KEYCODE_ENTER:
            mReceivedInvokeKeyDown = true;
            // fallthrough to default handling
        }
       
        return super.onKeyDown(keyCode, event);
    }

    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        switch (keyCode) {
        case KeyEvent.KEYCODE_DPAD_CENTER:
        case KeyEvent.KEYCODE_ENTER: {
           
            if (mReceivedInvokeKeyDown) {
                if (mItemCount > 0) {
   
                    dispatchPress(mSelectedChild);
                    postDelayed(new Runnable() {
                        public void run() {
                            dispatchUnpress();
                        }
                    }, ViewConfiguration.getPressedStateDuration());
   
                    int selectedIndex = mSelectedPosition - mFirstPosition;
                    performItemClick(getChildAt(selectedIndex), mSelectedPosition, mAdapter
                            .getItemId(mSelectedPosition));
                }
            }
           
            // Clear the flag
            mReceivedInvokeKeyDown = false;
           
            return true;
        }
        }

        return super.onKeyUp(keyCode, event);
    }
   
    boolean movePrevious() {
        if (mItemCount > 0 && mSelectedPosition > 0) {
            scrollToChild(mSelectedPosition - mFirstPosition - 1);
            return true;
        } else {
            return false;
        }
    }

    boolean moveNext() {
        if (mItemCount > 0 && mSelectedPosition < mItemCount - 1) {
            scrollToChild(mSelectedPosition - mFirstPosition + 1);
            return true;
        } else {
            return false;
        }
    }

    private boolean scrollToChild(int childPosition) {
        View child = getChildAt(childPosition);
       
        if (child != null) {
            int distance = getCenterOfGallery() - getCenterOfView(child);
            mFlingRunnable.startUsingDistance(distance);
            return true;
        }
       
        return false;
    }
   
    @Override
    void setSelectedPositionInt(int position) {
        super.setSelectedPositionInt(position);

        // Updates any metadata we keep about the selected item.
        updateSelectedItemMetadata();
    }

    private void updateSelectedItemMetadata() {
       
        View oldSelectedChild = mSelectedChild;

        View child = mSelectedChild = getChildAt(mSelectedPosition - mFirstPosition);
        if (child == null) {
            return;
        }

        child.setSelected(true);
        child.setFocusable(true);

        if (hasFocus()) {
            child.requestFocus();
        }

        // We unfocus the old child down here so the above hasFocus check
        // returns true
        if (oldSelectedChild != null) {

            // Make sure its drawable state doesn't contain 'selected'
            oldSelectedChild.setSelected(false);
           
            // Make sure it is not focusable anymore, since otherwise arrow keys
            // can make this one be focused
            oldSelectedChild.setFocusable(false);
        }
       
    }
   
    /**
     * Describes how the child views are aligned.
     * @param gravity
     *
     * @attr ref android.R.styleable#Gallery_gravity
     */
    public void setGravity(int gravity)
    {
        if (mGravity != gravity) {
            mGravity = gravity;
            requestLayout();
        }
    }

    @Override
    protected int getChildDrawingOrder(int childCount, int i) {
        int selectedIndex = mSelectedPosition - mFirstPosition;
       
        // Just to be safe
        if (selectedIndex < 0) return i;
       
        if (i == childCount - 1) {
            // Draw the selected child last
            return selectedIndex;
        } else if (i >= selectedIndex) {
            // Move the children to the right of the selected child earlier one
            return i + 1;
        } else {
            // Keep the children to the left of the selected child the same
            return i;
        }
    }

    @Override
    protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
        super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
       
        /*
         * The gallery shows focus by focusing the selected item. So, give
         * focus to our selected item instead. We steal keys from our
         * selected item elsewhere.
         */
        if (gainFocus && mSelectedChild != null) {
            mSelectedChild.requestFocus(direction);
        }

    }

    /**
     * Responsible for fling behavior. Use {@link #startUsingVelocity(int)} to
     * initiate a fling. Each frame of the fling is handled in {@link #run()}.
     * A FlingRunnable will keep re-posting itself until the fling is done.
     *
     */
    private class FlingRunnable implements Runnable {
        /**
         * Tracks the decay of a fling scroll
         */
        private Scroller mScroller;

        /**
         * X value reported by mScroller on the previous fling
         */
        private int mLastFlingX;

        public FlingRunnable() {
            mScroller = new Scroller(getContext());
        }

        private void startCommon() {
            // Remove any pending flings
            removeCallbacks(this);
        }
       
        public void startUsingVelocity(int initialVelocity) {
            if (initialVelocity == 0) return;
           
            startCommon();
           
            int initialX = initialVelocity < 0 ? Integer.MAX_VALUE : 0;
            mLastFlingX = initialX;
            mScroller.fling(initialX, 0, initialVelocity, 0,
                    0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE);
            post(this);
        }

        public void startUsingDistance(int distance) {
            if (distance == 0) return;
           
            startCommon();
           
            mLastFlingX = 0;
            mScroller.startScroll(0, 0, -distance, 0, mAnimationDuration);
            post(this);
        }
       
        public void stop(boolean scrollIntoSlots) {
            removeCallbacks(this);
            endFling(scrollIntoSlots);
        }
       
        private void endFling(boolean scrollIntoSlots) {
            /*
             * Force the scroller's status to finished (without setting its
             * position to the end)
             */
            mScroller.forceFinished(true);
           
            if (scrollIntoSlots) scrollIntoSlots();
        }

        public void run() {

            if (mItemCount == 0) {
                endFling(true);
                return;
            }

            mShouldStopFling = false;
           
            final Scroller scroller = mScroller;
            boolean more = scroller.computeScrollOffset();
            final int x = scroller.getCurrX();

            // Flip sign to convert finger direction to list items direction
            // (e.g. finger moving down means list is moving towards the top)
            int delta = mLastFlingX - x;

            // Pretend that each frame of a fling scroll is a touch scroll
            if (delta > 0) {
                // Moving towards the left. Use first view as mDownTouchPosition
                mDownTouchPosition = mFirstPosition;

                // Don't fling more than 1 screen
                delta = Math.min(getWidth() - getPaddingLeft() - getPaddingRight() - 1, delta);
            } else {
                // Moving towards the right. Use last view as mDownTouchPosition
                int offsetToLast = getChildCount() - 1;
                mDownTouchPosition = mFirstPosition + offsetToLast;

                // Don't fling more than 1 screen
                delta = Math.max(-(getWidth() - getPaddingRight() - getPaddingLeft() - 1), delta);
            }

            trackMotionScroll(delta);

            if (more && !mShouldStopFling) {
                mLastFlingX = x;
                post(this);
            } else {
               endFling(true);
            }
        }
       
    }
   
    /**
     * Gallery extends LayoutParams to provide a place to hold current
     * Transformation information along with previous position/transformation
     * info.
     *
     */
    public static class LayoutParams extends ViewGroup.LayoutParams {
        public LayoutParams(Context c, AttributeSet attrs) {
            super(c, attrs);
        }

        public LayoutParams(int w, int h) {
            super(w, h);
        }

        public LayoutParams(ViewGroup.LayoutParams source) {
            super(source);
        }
    }
}










Create fourth class MainActivity.java
=======================
public class MainActivity extends Activity {
    private WebView mWebViewReferenzen =null;
    private String StrImageLink="";
    private ImageView imgAndroidMarket;
    private ImageView imageView;
    private ArrayList<String> alstId = null, alstImageURL = null, alstDescription = null,alstLink=null;
    /** Called when the activity is first created. */
   
 @Override
 public void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
     requestWindowFeature(Window.FEATURE_NO_TITLE);
     setContentView(R.layout.xmainactivity);
    // getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
    
     alstId = new ArrayList<String>();
     alstImageURL = new ArrayList<String>();
     alstDescription = new ArrayList<String>();
     alstLink = new ArrayList<String>();
     imgAndroidMarket = (ImageView)findViewById(R.id.imgAndroidMarket);
     imgAndroidMarket.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            SetMarketIntent();   
        }
    });
     mWebViewReferenzen = (WebView)findViewById(R.id.mWebViewReferenzen);
    mWebViewReferenzen.getSettings().setJavaScriptEnabled(true);
    mWebViewReferenzen.getSettings().setSupportZoom(true);
    mWebViewReferenzen.setBackgroundColor(Color.TRANSPARENT);
   
    if(GlobalClass.CheckNetwork(this)){
        new GetReferenzenData().execute();       
    }
 }

 private void Coverflow(){
     FrameLayout frmlayout = (FrameLayout)findViewById(R.id.frmLayout);
     CoverFlow coverFlow;
     coverFlow = new CoverFlow(this);
//     coverFlow.setOnItemClickListener(new OnItemClickListener() {
//
//         @Override
//         public void onItemClick(CoverAdapterView<?> parent, View view,int position, long id) {
////             Toast.makeText(getApplicationContext(), "Click " + position,Toast.LENGTH_SHORT).show();
//              SetDiscription(position);
//         }
//     });
    
     final ImageAdapter coverImageAdapter =  new ImageAdapter(this);
    
     coverImageAdapter.createReflectedImages();   
     coverFlow.setAdapter(coverImageAdapter);
    
     coverFlow.setSpacing(-10);
     int index=Math.round(alstImageURL.size()/2);
     coverFlow.setSelection(index, true);
     coverImageAdapter.SetGrow(index);
     SetDiscription(index);
     strMarketURL=alstLink.get(index);    
     frmlayout.addView(coverFlow);
    
     coverFlow.setOnItemSelectedListener(new OnItemSelectedListener() {
        @Override
        public void onItemSelected(CoverAdapterView<?> parent, View view,int position, long id) {
            coverImageAdapter.SetGrow(position);
            SetDiscription(position);
            strMarketURL=alstLink.get(position);   
            System.out.println("Strmarketlink====="+strMarketURL);
            //market://details?id=com.drc.globaljob
        }

        @Override
        public void onNothingSelected(CoverAdapterView<?> parent) {
        }     
    }); 
 }

 private void SetDiscription(int index){
     WebSettings settings = mWebViewReferenzen.getSettings();
     settings.setDefaultTextEncodingName("utf-8");
     String Discription = "<font color = '#FFFFFF'>"+alstDescription.get(index).toString().trim()+"</font>";
     Discription = webViewLoadData(Discription);
     System.out.println("Discription==="+Discription);
     mWebViewReferenzen.loadData(Discription, "text/html", "utf-8");
 }

 private String strMarketURL = "";
 private void SetMarketIntent(){
     if(!strMarketURL.equals("") && GlobalClass.CheckNetwork(this)){
         Intent intent = new Intent(Intent.ACTION_VIEW);
         intent.setData(Uri.parse(strMarketURL));
         startActivity(intent);   
     }
 }

//*********************************************************************************************************************************
//This class used for get bitmap
 private class GetBitmapAll extends AsyncTask<String, String, Boolean>{
     private ProcessDialog mProcessDialog = null;
   
     @Override
    protected void onPreExecute() {
        mProcessDialog = new ProcessDialog(MainActivity.this, "Produkte", "Loading...");
        super.onPreExecute();
    }

    @Override
    protected Boolean doInBackground(String... params) {
        Boolean Status = false;
        try{
             bmpAllImage = new Bitmap[alstImageURL.size()];
             for(int i=0;i < alstImageURL.size();i++){
                 bmpAllImage[i] = GlobalClass.ImageShrink(GlobalClass.GETHTTPConnectionBitmap(StrImageLink + alstImageURL.get(i).toString().trim(),getApplicationContext()), Constant.SCALE_WIDTH, Constant.SCALE_HEIGHT);
                 android.os.SystemClock.sleep(1000);
                 // bmpAllImage[i]=BitmapImageUtil.loadFrom((StrImageLink + alstImageURL.get(i).toString().trim()), MainActivity.this, R.drawable.imgdefaultbigimage);
             }
             Status = true;
        }
        catch (Exception e) {
            e.printStackTrace();
            Status = false;
        }
        return Status;
    }
   
    @Override
    protected void onPostExecute(Boolean result) {
        mProcessDialog.dismiss();
        if(result){
            Coverflow();
        }
        super.onPostExecute(result);
    }
 }
 
 //****************************************************************************************************************************
 //Adapter class to show image in imageview
 private Bitmap bmpAllImage[];
 public class ImageAdapter extends BaseAdapter {
     int mGalleryItemBackground;
     private Context mContext;

//     private FileInputStream fis;      
/*     private Integer[] mImageIds = {
       R.drawable.kasabian_kasabian,
             R.drawable.starssailor_silence_is_easy,
             R.drawable.killers_day_and_age,
             R.drawable.garbage_bleed_like_me,
             R.drawable.death_cub_for_cutie_the_photo_album,
             R.drawable.kasabian_kasabian,
             R.drawable.massive_attack_collected,
             R.drawable.muse_the_resistance,
             R.drawable.starssailor_silence_is_easy
     };
*/
     public ImageView[] mImages;
    
     public ImageAdapter(Context c) {
         mContext = c;
         mImages = new ImageView[alstImageURL.size()];
     }
    
     public void SetGrow(int position){
         for(int i=0;i< mImages.length;i++){
             mImages[i].setBackgroundResource(0);
         }        
         mImages[position].setBackgroundResource(R.drawable.glow_img);
     }
    
     public boolean createReflectedImages() {
          //The gap we want between the reflection and the original image
          final int reflectionGap = 4;

//          int index = 0;
          for (int i=0 ;i < bmpAllImage.length;i++) {
//          for (Bitmap originalImage : bmpAllImage) {
              Bitmap originalImage = bmpAllImage[i];
             
//               int width = originalImage.getWidth();
//               int height = originalImage.getHeight();

//               //This will not scale but will flip on the Y axis
//               Matrix matrix = new Matrix();
//               matrix.preScale(1, -1);
//              
//               //Create a Bitmap with the flip matrix applied to it.
//               //We only want the bottom half of the image
//               Bitmap reflectionImage = Bitmap.createBitmap(originalImage, 0, height/2, width, height/2, matrix, false);
//                        
//               //Create a new bitmap with same width but taller to fit reflection
//               Bitmap bitmapWithReflection = Bitmap.createBitmap(width
//                 , (height + height/2), Config.ARGB_8888);
//            
//              //Create a new Canvas with the bitmap that's big enough for
//              //the image plus gap plus reflection
//              Canvas canvas = new Canvas(bitmapWithReflection);
//              //Draw in the original image
//              canvas.drawBitmap(originalImage, 0, 0, null);
//              //Draw in the gap
//              Paint deafaultPaint = new Paint();
//              canvas.drawRect(0, height, width, height + reflectionGap, deafaultPaint);
//              //Draw in the reflection
//              canvas.drawBitmap(reflectionImage,0, height + reflectionGap, null);
//             
//              //Create a shader that is a linear gradient that covers the reflection
//              Paint paint = new Paint();
//              LinearGradient shader = new LinearGradient(0, originalImage.getHeight(), 0,
//                bitmapWithReflection.getHeight() + reflectionGap, 0x70ffffff, 0x00ffffff,
//                TileMode.CLAMP);
//              //Set the paint to use this shader (linear gradient)
//              paint.setShader(shader);
//              //Set the Transfer mode to be porter duff and destination in
//              paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
//              //Draw a rectangle using the paint with our linear gradient
//              canvas.drawRect(0, height, width,
//                bitmapWithReflection.getHeight() + reflectionGap, paint);
             
              imageView = new ImageView(mContext);
              imageView.setImageBitmap(originalImage);             
              imageView.setLayoutParams(new CoverFlow.LayoutParams(Constant.SCALE_WIDTH,Constant.SCALE_HEIGHT));
              imageView.setScaleType(ScaleType.MATRIX);   
              mImages[i] = imageView;   
          }
       return true;
     }

     public int getCount() {
         return alstId.size();
     }

     public Object getItem(int position) {
         return position;
     }

     public long getItemId(int position) {
         return position;
     }

     public View getView(int position, View convertView, ViewGroup parent) {

      //Use this code if you want to load from resources
         //ImageView i = new ImageView(mContext);
         //i.setImageResource(mImageIds[position]);
         //i.setLayoutParams(new CoverFlow.LayoutParams(130, 130));
         //i.setScaleType(ImageView.ScaleType.MATRIX);        
         //return i;      
      return mImages[position];
     }
   /** Returns the size (0.0f to 1.0f) of the views
      * depending on the 'offset' to the center. */
      public float getScale(boolean focused, int offset) {
        /* Formula: 1 / (2 ^ offset) */
          return Math.max(0, 1.0f / (float)Math.pow(2, Math.abs(offset)));
      }
 }

    @Override
    protected void onDestroy() {
        if(bmpAllImage!=null){
            for(int i=0;i< bmpAllImage.length;i++){
                if(bmpAllImage[i]!=null){
                    bmpAllImage[i].recycle();
                }
            }
        }
        System.gc();
        Log.i("App Solution","Referenzen Destroy");
        super.onDestroy();
    }

//********************************************************************************************************************************
    ///This class id used for get referenzen data
    private class GetReferenzenData extends AsyncTask<String,JSONObject,JSONObject>{
        private ProcessDialog mProcessDialog = null;
        @Override
        protected void onPreExecute() {
            mProcessDialog = new ProcessDialog(MainActivity.this, "Produkte", "Loading...");
            super.onPreExecute();           
        }
        @Override
        protected JSONObject doInBackground(String... params) {
            if(GlobalClass.CheckNetworkNoMessage(MainActivity.this)){
                String strURL = getResources().getString(R.string.Referenzen_URL);

                String[] Key={Constant.KEY_VERSION};
                String[] Value={Constant.VALUE_ANDROID};                            
                                
                try {
                    return new JSONObject(GlobalClass.POSTHTTPConnection(strURL,Key,Value));
            } catch (Exception e) {
                    e.printStackTrace();
                    return null;
                } 
            }
            else{
                return null;
            }
        }   
       
        @Override
        protected void onPostExecute(JSONObject mJsonObject) {
            super.onPostExecute(mJsonObject);
            mProcessDialog.dismiss();
            if(mJsonObject!=null){
            try {
                    System.out.println("Referengen response====" +mJsonObject);
                    StrImageLink=mJsonObject.getString("download_link");
                    JSONArray subJArray = mJsonObject.getJSONArray("Data_array");           
                        if(subJArray !=null){
                        for(int i=0;i<subJArray.length();i++){
                                JSONObject JReferenzenDescription = subJArray.getJSONObject(i);                                   
                                alstId.add(JReferenzenDescription.getString("uid").toString().trim());
                                alstImageURL.add(JReferenzenDescription.getString("image_url").toString().trim());
                                alstDescription.add(JReferenzenDescription.getString("description").toString().trim());
                                alstLink.add(JReferenzenDescription.getString("link").toString().trim());
                            }

                            new GetBitmapAll().execute("Save Bitmap");
                        }
                } catch (JSONException e) {                           
                        e.printStackTrace();
                     Log.e("App Solution",""+e.getMessage().toString());
                }   
            }     
            else{
                Toast.makeText(MainActivity.this,Constant.NETWORK_NOT_AVAILABLE,Toast.LENGTH_SHORT).show();
            }
        }       
    }
   
//**************************************************************************************************************************
//This function is used to set text 
    public static String webViewLoadData(String strDiscription) {
        StringBuilder buf = new StringBuilder(strDiscription.length());
        for (char c : strDiscription.toCharArray()) {
                switch (c) {
                case 'ä':
                        buf.append("&#228;");
                        break;
                case 'ö':
                        buf.append("&ouml;");
                        break;
                case 'À':
                        buf.append("&#192;");
                        break;
                case 'Á':
                        buf.append("&#193;");
                        break;
                case 'Ü':
                        buf.append("&#220;");
                        break;
            
                case 'Ã':
                        buf.append("&#195");
                        break;
                case '´':
                        buf.append("&#180;");
                        break;
                case 'è':
                        buf.append("&#232;");
                        break;
                case 'é':
                        buf.append("&#233;");
                        break;
                case 'Ö':
                        buf.append("&#214;");
                        break;
                case '#':
                        buf.append("%23");
                        break;
                case '%':
                        buf.append("%25");
                        break;
                case '\'':
                        buf.append("%27");
                        break;
                case '?':
                        buf.append("%3f");
                        break;
                case 'ü':
                        buf.append("&#252;");
                        break;
                case '¤':
                        buf.append("&#226;");
                        break;
                case '€':
                        buf.append("&#128;");
                        break;
                case '–':
                        buf.append("&#150;");
                        break; 
                case '“':
                        buf.append("&#147;");
                        break;
                default:
                        buf.append(c);
                        break;
                }
            }
            String strTemp = buf.toString();
            System.out.println(" Decode :"+strTemp);
            return strTemp;
    }
}