Monday, July 22, 2013

Android Quiz timer task example


Android Quiz timer task example

Ex. application for 4 questions and answers with time period, 
Each question having 30 sec time to answer, if not answer show an alert your time up, when user click OK shift to next question.
When user answer the question show the next question with reset the time period.
user can allow to increase the timer for each click 30 sec. 

Please check the bellow code snippet for reference.

   


QuizTimerActivity.Java:
------------------------

package com.example.test;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.TextView;

public class QuizTimerActivity extends Activity {
private Context mContext;
private int TIME = 30, remaining_sec = 0;
private CountDownTimer countDownTimer;
private TextView textView_timer, currentqusView;
private int totalQus = 4, currentQus = 1;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = this;
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                                WindowManager.LayoutParams.FLAG_FULLSCREEN);

        setContentView(R.layout.timer_layout);
        mContext = this;
textView_timer = (TextView) findViewById(R.id.textView);
currentqusView = (TextView) findViewById(R.id.currentqus);
}

public void getStart(View view){
currentqusView.setText("Current Question: "+currentQus);
TIME = 30;
timerTask();
}

public void getStop(View view){
if(countDownTimer!= null){
countDownTimer.cancel();
countDownTimer = null;
}
}

public void getReStart(View view){
currentQus = 1;
currentqusView.setText("Current Question: "+currentQus);
TIME = 30;
timerTask();
}

public void getIncrease(View view){
TIME = remaining_sec + 30;
timerTask();
}

public void getAns1(View view){
if(countDownTimer!= null){
countDownTimer.cancel();
countDownTimer = null;
}
if(currentQus < totalQus){
currentQus = currentQus + 1;
currentqusView.setText("Current Question: "+currentQus);
TIME = 30;
timerTask();
}
}
public void getAns2(View view){
if(countDownTimer!= null){
countDownTimer.cancel();
countDownTimer = null;
}
if(currentQus < totalQus){
currentQus = currentQus + 1;
currentqusView.setText("Current Question: "+currentQus);
TIME = 30;
timerTask();
}
}

public void getAns3(View view){
if(countDownTimer!= null){
countDownTimer.cancel();
countDownTimer = null;
}
if(currentQus < totalQus){
currentQus = currentQus + 1;
currentqusView.setText("Current Question: "+currentQus);
TIME = 30;
timerTask();
}
}

public void getAns4(View view){
if(countDownTimer!= null){
countDownTimer.cancel();
countDownTimer = null;
}
if(currentQus < totalQus){
currentQus = currentQus + 1;
currentqusView.setText("Current Question: "+currentQus);
TIME = 30;
timerTask();
}
}

public void dialogAlert(String message){
AlertDialog.Builder adb = new AlertDialog.Builder(mContext);
        adb.setTitle(R.string.app_name);
        adb.setMessage(message);
        adb.setNeutralButton("OK",
                new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog,int which) {
                    currentQus = currentQus + 1;
                    currentqusView.setText("Current Question: "+currentQus);
                TIME = 30;
                timerTask();
                        dialog.cancel();
                    }
                });
        AlertDialog ad = adb.create();
        ad.show();
}

public void timerTask(){
if(countDownTimer!= null){
countDownTimer.cancel();
countDownTimer = null;
}
countDownTimer =  new CountDownTimer(TIME * 1000, 1000) {
            public void onTick(long millisUntilFinished) {
          remaining_sec = (int) millisUntilFinished/1000;
          textView_timer.setText(""+remaining_sec);
          System.out.println("TIME---" + TIME + "remaining_sec---" + remaining_sec);
            }
            public void onFinish() {
            TIME = 0;
            dialogAlert("Time finished");
            }
         }.start();
}
}



timer_layout.xml:
------------------


<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <LinearLayout
        android:id="@+id/scroll"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#ffffff"
        android:orientation="vertical" >
       
        <TextView
            android:id="@+id/currentqus"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="Current Question : ?"
            android:textColor="#000000"
            android:textSize="30sp" />

        <TextView
            android:id="@+id/textView"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="Your Time here"
            android:gravity="center"
            android:textColor="#000000"
            android:textSize="30sp" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:padding="10dp" >

            <Button
                android:id="@+id/button5"
                style="?android:attr/buttonStyleSmall"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:onClick="getAns1"
                android:layout_weight="1"
                android:text="Ans1" />

            <Button
                android:id="@+id/button6"
                style="?android:attr/buttonStyleSmall"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:onClick="getAns2"
                android:layout_weight="1"
                android:text="Ans2" />

            <Button
                android:id="@+id/button7"
                style="?android:attr/buttonStyleSmall"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:onClick="getAns3"
                android:text="Ans3" />

            <Button
                android:id="@+id/button8"
                style="?android:attr/buttonStyleSmall"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:onClick="getAns4"
                android:text="Ans4" />
        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:padding="10dp" >

            <Button
                android:id="@+id/button2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:onClick="getStart"
                android:text="Start" />

            <Button
                android:id="@+id/button1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:onClick="getStop"
                android:text="Stop" />

            <Button
                android:id="@+id/button3"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:onClick="getReStart"
                android:text="ReStart" />

            <Button
                android:id="@+id/button4"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:onClick="getIncrease"
                android:text="Increase" />
        </LinearLayout>
    </LinearLayout>

</ScrollView>




Saturday, June 15, 2013

An useful CommonMethods like getLatitudeLongitudeFromAddress etc

An useful CommonMethods like getLatitudeLongitudeFromAddress etc

An useful CommonMethods like validateEmail, getAddressFromGeo ......
please use this class and call the methods where you want

ex: CommonMethods.validateEmail(abc@gmail.com);

public class CommonMethods {

public static boolean validateEmail(String email) {
final Pattern EMAIL_ADDRESS_PATTERN = Pattern.compile(
         "[a-zA-Z0-9\\+\\.\\_\\%\\-\\+]{1,256}" +
         "\\@" +
         "[a-zA-Z0-9][a-zA-Z0-9\\-]{0,64}" +
         "(" +
         "\\." +
         "[a-zA-Z0-9][a-zA-Z0-9\\-]{0,25}" +
         ")+"
     );
try {
return EMAIL_ADDRESS_PATTERN.matcher(email).matches();
   }
   catch( NullPointerException exception ) {
       return false;
   }
}

/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
    /*::  This function get address from geo location (latitude and longitude):*/
    /*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
    public static List<Address> getAddressFromGeo(Context context, Double latitude, Double longitude) {
    List<Address> address = null;
    try {
List<Address> addresses = new Geocoder(context, Locale.getDefault()).getFromLocation(latitude, longitude, 1);
address = addresses;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return address;
    }

public static double[] getGPS(Context context) {
    LocationManager lm = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE);
List<String> providers = lm.getProviders(true);

/* Loop over the array backwards, and if you get an accurate location, then break out the loop*/
Location l = null;

for (int i=providers.size()-1; i>=0; i--) {
l = lm.getLastKnownLocation(providers.get(i));
if (l != null) break;
}

double[] gps = new double[2];
if (l != null) {
gps[0] = l.getLatitude();
gps[1] = l.getLongitude();
}
return gps;
}

public static String getMonth(int month) {
   return new DateFormatSymbols().getMonths()[month-1];
}

/**
* returns the string, the first char uppercase
*
* @param target
* @return
*/
public final static String asUpperCaseFirstChar(final String target) {
   if ((target == null) || (target.length() == 0)) {
       return target;
   }
   return Character.toUpperCase(target.charAt(0))
           + (target.length() > 1 ? target.substring(1) : "");
}

public static String convertURL(String str) {
   String url = null;
   try{
   url = new String(str.trim().replace(" ", "%20").replace("&", "%26")
           .replace(",", "%2c").replace("(", "%28").replace(")", "%29")
           .replace("!", "%21").replace("=", "%3D").replace("<", "%3C")
           .replace(">", "%3E").replace("#", "%23").replace("$", "%24")
           .replace("'", "%27").replace("*", "%2A").replace("-", "%2D")
           .replace(".", "%2E").replace("/", "%2F").replace(":", "%3A")
           .replace(";", "%3B").replace("?", "%3F").replace("@", "%40")
           .replace("[", "%5B").replace("\\", "%5C").replace("]", "%5D")
           .replace("_", "%5F").replace("`", "%60").replace("{", "%7B")
           .replace("|", "%7C").replace("}", "%7D"));
   }catch(Exception e){
       e.printStackTrace();
   }
   return url;
}

public static Address getLatitudeLongitudeFromAddress(Context context, String addressval, String zipcode) {
Geocoder coder = new Geocoder(context);
List<Address> address;
Log.d("address",addressval );
try {
if(!zipcode.equals("") && !zipcode.equals("null") && !zipcode.equals(null)) {
address = coder.getFromLocationName(zipcode, 5);
} else {
address = coder.getFromLocationName(addressval,5);
System.out.println("address" + address.get(0) );
}
   if (address != null && !address.isEmpty()) {
   Address location = address.get(0);
   location.getLatitude();
   location.getLongitude();
   return location;
   } else
    return null;
} catch(Exception e) {
e.printStackTrace();
}
return null;
}

public static Bitmap getResizedBitmap(Bitmap bm, int newHeight, int newWidth) {
        int width = bm.getWidth();
        int height = bm.getHeight();
        float scaleWidth = ((float) newWidth) / width;
        float scaleHeight = ((float) newHeight) / height;
        // CREATE A MATRIX FOR THE MANIPULATION
        Matrix matrix = new Matrix();
        // RESIZE THE BIT MAP
        matrix.postScale(scaleWidth, scaleHeight);


        // RECREATE THE NEW BITMAP
        Bitmap resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, false);
        return resizedBitmap;
    }

public static Bitmap ShrinkBitmap(String file, int width, int height){  
        BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options();
        bmpFactoryOptions.inJustDecodeBounds = true;
        Bitmap bitmap   = BitmapFactory.decodeFile(file, bmpFactoryOptions);
       
        int heightRatio = (int)Math.ceil(bmpFactoryOptions.outHeight/(float)height);
        int widthRatio  = (int)Math.ceil(bmpFactoryOptions.outWidth/(float)width);
       
        if (heightRatio > 1 || widthRatio > 1){
           if (heightRatio > widthRatio){
            bmpFactoryOptions.inSampleSize = heightRatio;
           }else {
         bmpFactoryOptions.inSampleSize = widthRatio;
           }
        }        
        bmpFactoryOptions.inJustDecodeBounds = false;
        bitmap = BitmapFactory.decodeFile(file, bmpFactoryOptions);
        return bitmap;
    }

public static String getPath(Uri uri, Activity activity) {
   String[] projection = { MediaStore.Images.Media.DATA };
   Cursor cursor = activity.managedQuery(uri, projection, null, null, null);
   int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
   cursor.moveToFirst();
   return cursor.getString(column_index);
}

/**
* Gets the last image id from the media store
* @return
*/
public static String getLastImageId(Activity activity) {
   final String[] imageColumns = { MediaStore.Images.Media._ID, MediaStore.Images.Media.DATA };
   final String imageOrderBy = MediaStore.Images.Media._ID+" DESC";
   Cursor imageCursor = activity.managedQuery(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, imageColumns, null, null, imageOrderBy);
   if(imageCursor.moveToFirst()){
       int id = imageCursor.getInt(imageCursor.getColumnIndex(MediaStore.Images.Media._ID));
       String fullPath = imageCursor.getString(imageCursor.getColumnIndex(MediaStore.Images.Media.DATA));
       Log.d("Camera", "getLastImageId::id " + id);
       Log.d("Camera", "getLastImageId::path " + fullPath);
       imageCursor.close();
       return fullPath;
   } else {
       return "";
   }
}

public static String getFileExtension(String url) {
int slashIndex = url.lastIndexOf('/');
int dotIndex = url.lastIndexOf('.', slashIndex);
String filenameWithoutExtension = "";
if (dotIndex == -1)
{
 filenameWithoutExtension = url.substring(slashIndex + 1);
}
else
{
 filenameWithoutExtension = url.substring(slashIndex + 1, dotIndex);
}
return filenameWithoutExtension;
}

public static boolean checkImageExtension(String extension) {
String[] exten = {"bmp", "dds", "dng", "gif", "jpg", "png", "psd", "pspimage", "tga", "thm", "jpeg", "yuv"};
for (String val : exten) {
   if (extension.toLowerCase().contains(val)) {
    return true;
   }
}
return false;
}

public static boolean checkFileExtension(String extension) {
String[] exten = {"doc", "docx", "log", "msg", "odt", "pages", "rtf", "tex", "txt", "wpd", "wps"};
for (String val : exten) {
   if (extension.toLowerCase().contains(val)) {
    return true;
   }
}
return false;
}

//CommonMethods
public static double distance(double lat1, double lon1, double lat2, double lon2) {
     double theta = lon1 - lon2;
     double dist = Math.sin(deg2rad(lat1)) * Math.sin(deg2rad(lat2)) + Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * Math.cos(deg2rad(theta));
     dist = Math.acos(dist);
     dist = rad2deg(dist);
     dist = dist * 60 * 1.1515;
     return (dist);
}

public static double distFrom(double lat1, double lng1, double lat2,
double lng2) {
double earthRadius = 6371;
double dLat = Math.toRadians(lat2 - lat1);
double dLng = Math.toRadians(lng2 - lng1);
double a = Math.sin(dLat / 2) * Math.sin(dLat / 2)
+ Math.cos(Math.toRadians(lat1))
* Math.cos(Math.toRadians(lat2)) * Math.sin(dLng / 2)
* Math.sin(dLng / 2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
double dist = earthRadius * c;

//Log.d("dist: " , ""+ dist + "--" + lat1 +"," + lng1 +  "--" + lat2 +"," + lng2 );
return (dist);

}

public static float metresToMiles(float metres) {

return (float) (metres * 0.000621371192);
}

public static float metresToKm(float metres) {

return (float) (metres * 0.001);
}

public static float Round(float Rval, int Rpl) {
float p = (float) Math.pow(10, Rpl);
Rval = Rval * p;
float tmp = Math.round(Rval);
return (float) tmp / p;
}
public static double deg2rad(double deg) {
return (deg * Math.PI / 180.0);
    }
public static double rad2deg(double rad) {
return (rad * 180.0 / Math.PI);
    }

public static JSONObject getLocationInfo(String address) {

HttpGet httpGet = new HttpGet("http://maps.google."
+ "com/maps/api/geocode/json?address=" + address
+ "ka&sensor=false");
HttpClient client = new DefaultHttpClient();
HttpResponse response;
StringBuilder stringBuilder = new StringBuilder();

try {
response = client.execute(httpGet);
HttpEntity entity = response.getEntity();
InputStream stream = entity.getContent();
int b;
while ((b = stream.read()) != -1) {
stringBuilder.append((char) b);
}
} catch (ClientProtocolException e) {
} catch (IOException e) {
}

JSONObject jsonObject = new JSONObject();
try {
jsonObject = new JSONObject(stringBuilder.toString());
} catch (JSONException e) {
e.printStackTrace();
}

return jsonObject;
}

public static GeoPoint getGeoPoint(JSONObject jsonObject) {
double lon = 0.0;
Double lat = 0.0;
try {
lon = ((JSONArray)jsonObject.get("results")).getJSONObject(0).getJSONObject("geometry").getJSONObject("location").getDouble("lng");
lat = ((JSONArray)jsonObject.get("results")).getJSONObject(0).getJSONObject("geometry").getJSONObject("location").getDouble("lat");
} catch (JSONException e) {
e.printStackTrace();
}

return new GeoPoint((int) (lat * 1E6), (int) (lon * 1E6));

}


}

Android replace FRENCH characters to English characters

Android replace FRENCH characters to English characters
String french = "Tapez les mots français ici ............";
String english =slugify(french);

public  String slugify(String name) {
String[] hel=name.split("(?!^)");

for(int i=0;i<hel.length;i++){
if(hel[i].contains("é")||hel[i].contains("è")||hel[i].contains("à")||hel[i].contains("ù")||hel[i].contains("â")
||hel[i].contains("ê")||hel[i].contains("î")||hel[i].contains("ô")||hel[i].contains("û")||hel[i].contains("ë")
||hel[i].contains("ï")||hel[i].contains("ç")||hel[i].contains("æ")||hel[i].contains("œ")||hel[i].contains("ü")
||hel[i].contains("À")||hel[i].contains("Â")||hel[i].contains("Æ")||hel[i].contains("Ç")
||hel[i].contains("È")||hel[i].contains("É")||hel[i].contains("Ê")||hel[i].contains("Ë")||hel[i].contains("Î")
||hel[i].contains("Ï")||hel[i].contains("Ô")||hel[i].contains("Œ")||hel[i].contains("Ù")||hel[i].contains("Û")||hel[i].contains("Ü")){
name=name.replace("é", "e");
name=name.replace("è", "e");
name=name.replace("à", "a");
name=name.replace("ù", "u");
name=name.replace("â", "a");
name=name.replace("ê", "e");
name=name.replace("î", "i");
name=name.replace("ô", "o");
name=name.replace("û", "u");
name=name.replace("ë", "e");
name=name.replace("ï", "i");
name=name.replace("ç", "c");
name=name.replace("æ", "ae");
name=name.replace("œ", "oe");
name=name.replace("ü", "u");

name=name.replace("À", "A");
name=name.replace("Â", "A");
name=name.replace("Æ", "AE");
name=name.replace("Ç", "C");
name=name.replace("È", "E");
name=name.replace("É", "E");
name=name.replace("Ê", "E");
name=name.replace("Ë", "E");
name=name.replace("Î", "I");
name=name.replace("Ï", "I");
name=name.replace("Ô", "O");
name=name.replace("Œ", "OE");
name=name.replace("Ù", "U");
name=name.replace("Û", "U");
name=name.replace("Ü", "U");
}
}


String subjectString = "öäü";
        subjectString = Normalizer.normalize(subjectString, Normalizer.Form.NFD);
        String resultString = subjectString.replaceAll("[^\\x00-\\x7F]", "");
        System.out.println(resultString);
       
        String s = "Papier, produit de pâte à papier, non précisé";
        String r = s.replaceAll("\\P{InBasic_Latin}", "");
        System.out.println("-----------"+r);

Thursday, June 13, 2013

Sorting the list Objects Based on Date Wise (format):

Sorting the list Objects Based on Date Wise (format):

POJO Class Or Persist Class:
----------------------------
public class News {
public String getTitle() {
return title;
}
public String getDate() {
return date;
}
public String getDescription() {
return description;
}
public News(String title, String date, String description) {
super();
this.title = title;
this.date = date;
this.description = description;
}
private String title, date, description;
}


In Your Activity Class:
-------------------------
private SimpleDateFormat formatter, FORMATTER;
FORMATTER = new SimpleDateFormat("MMMMM dd, yyyy", Locale.ENGLISH);
private ArrayList<News> newsList = new ArrayList<News>();

newsList.add(new News("Title1", "January 26, 2013"), "DESC 1");
newsList.add(new News("Title2", "August 15, 2011"), "DESC 2");
newsList.add(new News("Title3", "October 02, 2012"), "DESC 3");
newsList.add(new News("Title4", "November 05, 2013"), "DESC 4");
newsList.add(new News("Title5", "August 15, 2012"), "DESC 5");

after finishing adding to list:
/* sorting of objects begin here  */  
Collections.sort(newsList, new customComparator());


Make this class as Sub Class of your activity class.
public class customComparator implements Comparator {
   public int compare(Object  object1, Object  object2) {
    News e1 = (News) object1;
    News e2 = (News) object2;
   
    Date d1 = null;
       Date d2 = null;
       try {
           d1 = FORMATTER.parse(e1.getDate());
           d2 = FORMATTER.parse(e2.getDate());
       } catch (ParseException e) {
           e.printStackTrace();
       }
       return (d1.getTime() > d2.getTime() ? -1 : 1);     //descending
   //  return (d1.getTime() > d2.getTime() ? 1 : -1);     //ascending
   }
}

Wednesday, June 12, 2013

Sending BitMap Between Activities:

Sending BitMap Between Activities:

In Activity 1 :
do like this---------------->
Which image you want to send to next activity
bitmap = ((BitmapDrawable)imageView.getDrawable()).getBitmap(); // here imageView is an XML related image view.
       
Intent intent = new Intent(mContext, NextActivity.class);
        ByteArrayOutputStream bs = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, bs);
        intent.putExtra("byteArray", bs.toByteArray());
        startActivity(intent);


In Activity 2 :
try{
        if(getIntent().hasExtra("byteArray")) {
        bitmap = BitmapFactory.decodeByteArray(getIntent().getByteArrayExtra("byteArray"),0,getIntent().getByteArrayExtra("byteArray").length);      
                imageView.setImageBitmap(bitmap); // here imageView Activity 2 related imageView
            }
        }catch (Exception e) {
e.printStackTrace();
}

Monday, January 7, 2013

Timer Whell like Iphone


                                   Timer Whell like as Iphone
Timer selection wheel like as in Iphone scroll wheel view.
copy all these files and test the application you fee; beret,


layout_bg.xml:
-------------

<?xml version="1.0" encoding="utf-8"?>

<!-- 
    Android Wheel Control.
    http://android-devblog.blogspot.com/2010/05/wheel-ui-contol.html

    Copyright 2010 Yuri Kanivets
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
-->

<shape xmlns:android="http://schemas.android.com/apk/res/android">
        <gradient
                android:startColor="#FF000000"
                android:centerColor="#FF000000"
                android:endColor="#FF777777"
                android:angle="90" />
</shape>


wheel_bg.xml:
------------


<!-- 
    Android Wheel Control.
    http://android-devblog.blogspot.com/2010/05/wheel-ui-contol.html
   
    Copyright 2010 Yuri Kanivets
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<gradient android:startColor="#333" android:centerColor="#DDD" android:endColor="#333" android:angle="90"/>
<stroke android:width="1dp" android:color="#FF333333"/>
</shape>
</item>
<item android:left="4dp" android:right="4dp" android:top="1dp" android:bottom="1dp">
<shape android:shape="rectangle">
<gradient android:startColor="#AAA" android:centerColor="#FFF" android:endColor="#AAA" android:angle="90"/>
</shape>
</item>
</layer-list>


wheel_val.xml:
-------------


<?xml version="1.0" encoding="utf-8"?>

<!--
    Android Wheel Control.
    http://android-devblog.blogspot.com/2010/05/wheel-ui-contol.html
 
    Copyright 2010 Yuri Kanivets
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
-->

<shape xmlns:android="http://schemas.android.com/apk/res/android">
        <gradient
                android:startColor="#70222222"
                android:centerColor="#70222222"
                android:endColor="#70EEEEEE"
                android:angle="90" />

        <stroke android:width="1dp" android:color="#70333333" />
</shape>



time_layout.xml:
----------------


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <LinearLayout
        android:id="@+id/timer_lt"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:background="@drawable/layout_bg"
        android:orientation="vertical" >

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:paddingLeft="12dp"
            android:paddingRight="12dp"
            android:paddingTop="20dp" >

            <kankan.wheel.WheelView
                android:id="@+id/hour"
                android:layout_width="140dp"
                android:layout_height="wrap_content" />

            <kankan.wheel.WheelView
                android:id="@+id/mins"
                android:layout_width="140dp"
                android:layout_height="wrap_content" />
        </LinearLayout>
    </LinearLayout>

    <RelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="40dp"
        android:layout_above="@+id/timer_lt"
        android:background="#000000"
        android:orientation="vertical" >

        <TextView
            android:id="@+id/textView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:layout_centerVertical="true"
            android:text="set timer"
            android:textColor="@android:color/white"
            android:textSize="18dp" />
    </RelativeLayout>

</RelativeLayout>


AndroidManifest.xml:
------------------

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="kankan.wheel"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="15" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".TimeActivity"
            android:label="@string/title_activity_main" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>



WheelView.java:
--------------


/*
 *  Android Wheel Control.
 *  https://code.google.com/p/android-wheel/
 *
 *  Copyright 2011 Yuri Kanivets
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package kankan.wheel;

import java.util.LinkedList;
import java.util.List;

import kankan.wheel.R;
import kankan.wheel.WheelViewAdapter;
import android.content.Context;
import android.database.DataSetObserver;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.GradientDrawable.Orientation;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.view.animation.Interpolator;
import android.widget.LinearLayout;

/**
 * Numeric wheel view.
 *
 * @author Yuri Kanivets
 */
public class WheelView extends View {

/** Top and bottom shadows colors */
private static final int[] SHADOWS_COLORS = new int[] { 0xFF111111,
0x00AAAAAA, 0x00AAAAAA };

/** Top and bottom items offset (to hide that) */
private static final int ITEM_OFFSET_PERCENT = 10;

/** Left and right padding value */
private static final int PADDING = 10;

/** Default count of visible items */
private static final int DEF_VISIBLE_ITEMS = 5;

// Wheel Values
private int currentItem = 0;

// Count of visible items
private int visibleItems = DEF_VISIBLE_ITEMS;

// Item height
private int itemHeight = 0;

// Center Line
private Drawable centerDrawable;

// Shadows drawables
private GradientDrawable topShadow;
private GradientDrawable bottomShadow;

// Scrolling
private WheelScroller scroller;
    private boolean isScrollingPerformed;
    private int scrollingOffset;

// Cyclic
boolean isCyclic = false;

// Items layout
private LinearLayout itemsLayout;

// The number of first item in layout
private int firstItem;

// View adapter
private WheelViewAdapter viewAdapter;

// Recycle
private WheelRecycle recycle = new WheelRecycle(this);

// Listeners
private List<OnWheelChangedListener> changingListeners = new LinkedList<OnWheelChangedListener>();
private List<OnWheelScrollListener> scrollingListeners = new LinkedList<OnWheelScrollListener>();
    private List<OnWheelClickedListener> clickingListeners = new LinkedList<OnWheelClickedListener>();

/**
* Constructor
*/
public WheelView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initData(context);
}

/**
* Constructor
*/
public WheelView(Context context, AttributeSet attrs) {
super(context, attrs);
initData(context);
}

/**
* Constructor
*/
public WheelView(Context context) {
super(context);
initData(context);
}

/**
* Initializes class data
* @param context the context
*/
private void initData(Context context) {
   scroller = new WheelScroller(getContext(), scrollingListener);
}

// Scrolling listener
WheelScroller.ScrollingListener scrollingListener = new WheelScroller.ScrollingListener() {
        public void onStarted() {
            isScrollingPerformed = true;
            notifyScrollingListenersAboutStart();
        }
       
        public void onScroll(int distance) {
            doScroll(distance);
           
            int height = getHeight();
            if (scrollingOffset > height) {
                scrollingOffset = height;
                scroller.stopScrolling();
            } else if (scrollingOffset < -height) {
                scrollingOffset = -height;
                scroller.stopScrolling();
            }
        }
       
        public void onFinished() {
            if (isScrollingPerformed) {
                notifyScrollingListenersAboutEnd();
                isScrollingPerformed = false;
            }
           
            scrollingOffset = 0;
            invalidate();
        }

        public void onJustify() {
            if (Math.abs(scrollingOffset) > WheelScroller.MIN_DELTA_FOR_SCROLLING) {
                scroller.scroll(scrollingOffset, 0);
            }
        }
    };

/**
* Set the the specified scrolling interpolator
* @param interpolator the interpolator
*/
public void setInterpolator(Interpolator interpolator) {
scroller.setInterpolator(interpolator);
}

/**
* Gets count of visible items
*
* @return the count of visible items
*/
public int getVisibleItems() {
return visibleItems;
}

/**
* Sets the desired count of visible items.
* Actual amount of visible items depends on wheel layout parameters.
* To apply changes and rebuild view call measure().
*
* @param count the desired count for visible items
*/
public void setVisibleItems(int count) {
visibleItems = count;
}

/**
* Gets view adapter
* @return the view adapter
*/
public WheelViewAdapter getViewAdapter() {
return viewAdapter;
}

// Adapter listener
    private DataSetObserver dataObserver = new DataSetObserver() {
        @Override
        public void onChanged() {
            invalidateWheel(false);
        }

        @Override
        public void onInvalidated() {
            invalidateWheel(true);
        }
    };

/**
* Sets view adapter. Usually new adapters contain different views, so
* it needs to rebuild view by calling measure().
*
* @param viewAdapter the view adapter
*/
public void setViewAdapter(WheelViewAdapter viewAdapter) {
   if (this.viewAdapter != null) {
       this.viewAdapter.unregisterDataSetObserver(dataObserver);
   }
        this.viewAdapter = viewAdapter;
        if (this.viewAdapter != null) {
            this.viewAdapter.registerDataSetObserver(dataObserver);
        }
       
        invalidateWheel(true);
}

/**
* Adds wheel changing listener
* @param listener the listener
*/
public void addChangingListener(OnWheelChangedListener listener) {
changingListeners.add(listener);
}

/**
* Removes wheel changing listener
* @param listener the listener
*/
public void removeChangingListener(OnWheelChangedListener listener) {
changingListeners.remove(listener);
}

/**
* Notifies changing listeners
* @param oldValue the old wheel value
* @param newValue the new wheel value
*/
protected void notifyChangingListeners(int oldValue, int newValue) {
for (OnWheelChangedListener listener : changingListeners) {
listener.onChanged(this, oldValue, newValue);
}
}

/**
* Adds wheel scrolling listener
* @param listener the listener
*/
public void addScrollingListener(OnWheelScrollListener listener) {
scrollingListeners.add(listener);
}

/**
* Removes wheel scrolling listener
* @param listener the listener
*/
public void removeScrollingListener(OnWheelScrollListener listener) {
scrollingListeners.remove(listener);
}

/**
* Notifies listeners about starting scrolling
*/
protected void notifyScrollingListenersAboutStart() {
for (OnWheelScrollListener listener : scrollingListeners) {
listener.onScrollingStarted(this);
}
}

/**
* Notifies listeners about ending scrolling
*/
protected void notifyScrollingListenersAboutEnd() {
for (OnWheelScrollListener listener : scrollingListeners) {
listener.onScrollingFinished(this);
}
}

    /**
     * Adds wheel clicking listener
     * @param listener the listener
     */
    public void addClickingListener(OnWheelClickedListener listener) {
        clickingListeners.add(listener);
    }

    /**
     * Removes wheel clicking listener
     * @param listener the listener
     */
    public void removeClickingListener(OnWheelClickedListener listener) {
        clickingListeners.remove(listener);
    }
   
    /**
     * Notifies listeners about clicking
     */
    protected void notifyClickListenersAboutClick(int item) {
        for (OnWheelClickedListener listener : clickingListeners) {
            listener.onItemClicked(this, item);
        }
    }

/**
* Gets current value
*
* @return the current value
*/
public int getCurrentItem() {
return currentItem;
}

/**
* Sets the current item. Does nothing when index is wrong.
*
* @param index the item index
* @param animated the animation flag
*/
public void setCurrentItem(int index, boolean animated) {
if (viewAdapter == null || viewAdapter.getItemsCount() == 0) {
return; // throw?
}

int itemCount = viewAdapter.getItemsCount();
if (index < 0 || index >= itemCount) {
if (isCyclic) {
while (index < 0) {
index += itemCount;
}
index %= itemCount;
} else{
return; // throw?
}
}
if (index != currentItem) {
if (animated) {
   int itemsToScroll = index - currentItem;
   if (isCyclic) {
       int scroll = itemCount + Math.min(index, currentItem) - Math.max(index, currentItem);
       if (scroll < Math.abs(itemsToScroll)) {
           itemsToScroll = itemsToScroll < 0 ? scroll : -scroll;
       }
   }
scroll(itemsToScroll, 0);
} else {
scrollingOffset = 0;

int old = currentItem;
currentItem = index;

notifyChangingListeners(old, currentItem);

invalidate();
}
}
}

/**
* Sets the current item w/o animation. Does nothing when index is wrong.
*
* @param index the item index
*/
public void setCurrentItem(int index) {
setCurrentItem(index, false);
}

/**
* Tests if wheel is cyclic. That means before the 1st item there is shown the last one
* @return true if wheel is cyclic
*/
public boolean isCyclic() {
return isCyclic;
}

/**
* Set wheel cyclic flag
* @param isCyclic the flag to set
*/
public void setCyclic(boolean isCyclic) {
this.isCyclic = isCyclic;
invalidateWheel(false);
}

/**
* Invalidates wheel
* @param clearCaches if true then cached views will be clear
*/
    public void invalidateWheel(boolean clearCaches) {
        if (clearCaches) {
            recycle.clearAll();
            if (itemsLayout != null) {
                itemsLayout.removeAllViews();
            }
            scrollingOffset = 0;
        } else if (itemsLayout != null) {
            // cache all items
       recycle.recycleItems(itemsLayout, firstItem, new ItemsRange());        
        }
       
        invalidate();
}

/**
* Initializes resources
*/
private void initResourcesIfNecessary() {
if (centerDrawable == null) {
centerDrawable = getContext().getResources().getDrawable(R.drawable.wheel_val);
}

if (topShadow == null) {
topShadow = new GradientDrawable(Orientation.TOP_BOTTOM, SHADOWS_COLORS);
}

if (bottomShadow == null) {
bottomShadow = new GradientDrawable(Orientation.BOTTOM_TOP, SHADOWS_COLORS);
}

setBackgroundResource(R.drawable.wheel_bg);
}

/**
* Calculates desired height for layout
*
* @param layout
*            the source layout
* @return the desired layout height
*/
private int getDesiredHeight(LinearLayout layout) {
if (layout != null && layout.getChildAt(0) != null) {
itemHeight = layout.getChildAt(0).getMeasuredHeight();
}

int desired = itemHeight * visibleItems - itemHeight * ITEM_OFFSET_PERCENT / 50;

return Math.max(desired, getSuggestedMinimumHeight());
}

/**
* Returns height of wheel item
* @return the item height
*/
private int getItemHeight() {
if (itemHeight != 0) {
return itemHeight;
}

if (itemsLayout != null && itemsLayout.getChildAt(0) != null) {
itemHeight = itemsLayout.getChildAt(0).getHeight();
return itemHeight;
}

return getHeight() / visibleItems;
}

/**
* Calculates control width and creates text layouts
* @param widthSize the input layout width
* @param mode the layout mode
* @return the calculated control width
*/
private int calculateLayoutWidth(int widthSize, int mode) {
initResourcesIfNecessary();

// TODO: make it static
itemsLayout.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
   itemsLayout.measure(MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.UNSPECIFIED),
               MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
int width = itemsLayout.getMeasuredWidth();

if (mode == MeasureSpec.EXACTLY) {
width = widthSize;
} else {
width += 2 * PADDING;

// Check against our minimum width
width = Math.max(width, getSuggestedMinimumWidth());

if (mode == MeasureSpec.AT_MOST && widthSize < width) {
width = widthSize;
}
}

        itemsLayout.measure(MeasureSpec.makeMeasureSpec(width - 2 * PADDING, MeasureSpec.EXACTLY),
                MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));

return width;
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);

buildViewForMeasuring();

int width = calculateLayoutWidth(widthSize, widthMode);

int height;
if (heightMode == MeasureSpec.EXACTLY) {
height = heightSize;
} else {
height = getDesiredHeight(itemsLayout);

if (heightMode == MeasureSpec.AT_MOST) {
height = Math.min(height, heightSize);
}
}

setMeasuredDimension(width, height);
}

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
    layout(r - l, b - t);
    }

    /**
     * Sets layouts width and height
     * @param width the layout width
     * @param height the layout height
     */
    private void layout(int width, int height) {
int itemsWidth = width - 2 * PADDING;

itemsLayout.layout(0, 0, itemsWidth, height);
    }

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);

if (viewAdapter != null && viewAdapter.getItemsCount() > 0) {
       updateView();

       drawItems(canvas);
       drawCenterRect(canvas);
}

        drawShadows(canvas);
}

/**
* Draws shadows on top and bottom of control
* @param canvas the canvas for drawing
*/
private void drawShadows(Canvas canvas) {
int height = (int)(1.5 * getItemHeight());
topShadow.setBounds(0, 0, getWidth(), height);
topShadow.draw(canvas);

bottomShadow.setBounds(0, getHeight() - height, getWidth(), getHeight());
bottomShadow.draw(canvas);
}

/**
* Draws items
* @param canvas the canvas for drawing
*/
private void drawItems(Canvas canvas) {
canvas.save();

int top = (currentItem - firstItem) * getItemHeight() + (getItemHeight() - getHeight()) / 2;
canvas.translate(PADDING, - top + scrollingOffset);

itemsLayout.draw(canvas);

canvas.restore();
}

/**
* Draws rect for current value
* @param canvas the canvas for drawing
*/
private void drawCenterRect(Canvas canvas) {
int center = getHeight() / 2;
int offset = (int) (getItemHeight() / 2 * 1.2);
centerDrawable.setBounds(0, center - offset, getWidth(), center + offset);
centerDrawable.draw(canvas);
}

@Override
public boolean onTouchEvent(MotionEvent event) {
if (!isEnabled() || getViewAdapter() == null) {
return true;
}

switch (event.getAction()) {
   case MotionEvent.ACTION_MOVE:
       if (getParent() != null) {
           getParent().requestDisallowInterceptTouchEvent(true);
       }
       break;
     
   case MotionEvent.ACTION_UP:
       if (!isScrollingPerformed) {
           int distance = (int) event.getY() - getHeight() / 2;
           if (distance > 0) {
               distance += getItemHeight() / 2;
           } else {
                        distance -= getItemHeight() / 2;
           }
           int items = distance / getItemHeight();
           if (items != 0 && isValidItemIndex(currentItem + items)) {
                   notifyClickListenersAboutClick(currentItem + items);
           }
       }
       break;
}

return scroller.onTouchEvent(event);
}

/**
* Scrolls the wheel
* @param delta the scrolling value
*/
private void doScroll(int delta) {
scrollingOffset += delta;

int itemHeight = getItemHeight();
int count = scrollingOffset / itemHeight;

int pos = currentItem - count;
int itemCount = viewAdapter.getItemsCount();

   int fixPos = scrollingOffset % itemHeight;
   if (Math.abs(fixPos) <= itemHeight / 2) {
       fixPos = 0;
   }
if (isCyclic && itemCount > 0) {
   if (fixPos > 0) {
       pos--;
                count++;
   } else if (fixPos < 0) {
       pos++;
       count--;
   }
// fix position by rotating
while (pos < 0) {
pos += itemCount;
}
pos %= itemCount;
} else {
//
if (pos < 0) {
count = currentItem;
pos = 0;
} else if (pos >= itemCount) {
count = currentItem - itemCount + 1;
pos = itemCount - 1;
} else if (pos > 0 && fixPos > 0) {
                pos--;
                count++;
            } else if (pos < itemCount - 1 && fixPos < 0) {
                pos++;
                count--;
            }
}

int offset = scrollingOffset;
if (pos != currentItem) {
setCurrentItem(pos, false);
} else {
invalidate();
}

// update offset
scrollingOffset = offset - count * itemHeight;
if (scrollingOffset > getHeight()) {
scrollingOffset = scrollingOffset % getHeight() + getHeight();
}
}

/**
* Scroll the wheel
* @param itemsToSkip items to scroll
* @param time scrolling duration
*/
public void scroll(int itemsToScroll, int time) {
int distance = itemsToScroll * getItemHeight() - scrollingOffset;
        scroller.scroll(distance, time);
}

/**
* Calculates range for wheel items
* @return the items range
*/
private ItemsRange getItemsRange() {
        if (getItemHeight() == 0) {
            return null;
        }
       
int first = currentItem;
int count = 1;

while (count * getItemHeight() < getHeight()) {
first--;
count += 2; // top + bottom items
}

if (scrollingOffset != 0) {
if (scrollingOffset > 0) {
first--;
}
count++;

// process empty items above the first or below the second
int emptyItems = scrollingOffset / getItemHeight();
first -= emptyItems;
count += Math.asin(emptyItems);
}
return new ItemsRange(first, count);
}

/**
* Rebuilds wheel items if necessary. Caches all unused items.
*
* @return true if items are rebuilt
*/
private boolean rebuildItems() {
boolean updated = false;
ItemsRange range = getItemsRange();
if (itemsLayout != null) {
int first = recycle.recycleItems(itemsLayout, firstItem, range);
updated = firstItem != first;
firstItem = first;
} else {
createItemsLayout();
updated = true;
}

if (!updated) {
updated = firstItem != range.getFirst() || itemsLayout.getChildCount() != range.getCount();
}

if (firstItem > range.getFirst() && firstItem <= range.getLast()) {
for (int i = firstItem - 1; i >= range.getFirst(); i--) {
if (!addViewItem(i, true)) {
   break;
}
firstItem = i;
}
} else {
   firstItem = range.getFirst();
}

int first = firstItem;
for (int i = itemsLayout.getChildCount(); i < range.getCount(); i++) {
if (!addViewItem(firstItem + i, false) && itemsLayout.getChildCount() == 0) {
   first++;
}
}
firstItem = first;

return updated;
}

/**
* Updates view. Rebuilds items and label if necessary, recalculate items sizes.
*/
private void updateView() {
if (rebuildItems()) {
calculateLayoutWidth(getWidth(), MeasureSpec.EXACTLY);
layout(getWidth(), getHeight());
}
}

/**
* Creates item layouts if necessary
*/
private void createItemsLayout() {
if (itemsLayout == null) {
itemsLayout = new LinearLayout(getContext());
itemsLayout.setOrientation(LinearLayout.VERTICAL);
}
}

/**
* Builds view for measuring
*/
private void buildViewForMeasuring() {
// clear all items
if (itemsLayout != null) {
recycle.recycleItems(itemsLayout, firstItem, new ItemsRange());
} else {
createItemsLayout();
}

// add views
int addItems = visibleItems / 2;
for (int i = currentItem + addItems; i >= currentItem - addItems; i--) {
if (addViewItem(i, true)) {
   firstItem = i;
}
}
}

/**
* Adds view for item to items layout
* @param index the item index
* @param first the flag indicates if view should be first
* @return true if corresponding item exists and is added
*/
private boolean addViewItem(int index, boolean first) {
View view = getItemView(index);
if (view != null) {
if (first) {
itemsLayout.addView(view, 0);
} else {
itemsLayout.addView(view);
}

return true;
}

return false;
}

/**
* Checks whether intem index is valid
* @param index the item index
* @return true if item index is not out of bounds or the wheel is cyclic
*/
private boolean isValidItemIndex(int index) {
   return viewAdapter != null && viewAdapter.getItemsCount() > 0 &&
       (isCyclic || index >= 0 && index < viewAdapter.getItemsCount());
}

/**
* Returns view for specified item
* @param index the item index
* @return item view or empty view if index is out of bounds
*/
    private View getItemView(int index) {
if (viewAdapter == null || viewAdapter.getItemsCount() == 0) {
return null;
}
int count = viewAdapter.getItemsCount();
if (!isValidItemIndex(index)) {
return viewAdapter.getEmptyItem(recycle.getEmptyItem(), itemsLayout);
} else {
while (index < 0) {
index = count + index;
}
}

index %= count;
return viewAdapter.getItem(index, recycle.getItem(), itemsLayout);
}

/**
* Stops scrolling
*/
public void stopScrolling() {
   scroller.stopScrolling();
}
}



WheelViewAdapter.java:
---------------------
/*
 *  Copyright 2011 Yuri Kanivets
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package kankan.wheel;

import android.database.DataSetObserver;
import android.view.View;
import android.view.ViewGroup;

/**
 * Wheel items adapter interface
 */
public interface WheelViewAdapter {
        /**
         * Gets items count
         * @return the count of wheel items
         */
        public int getItemsCount();
       
        /**
         * Get a View that displays the data at the specified position in the data set
         *
         * @param index the item index
         * @param convertView the old view to reuse if possible
         * @param parent the parent that this view will eventually be attached to
         * @return the wheel item View
         */
        public View getItem(int index, View convertView, ViewGroup parent);

        /**
         * Get a View that displays an empty wheel item placed before the first or after
         * the last wheel item.
         *
         * @param convertView the old view to reuse if possible
     * @param parent the parent that this view will eventually be attached to
         * @return the empty item View
         */
        public View getEmptyItem(View convertView, ViewGroup parent);
       
        /**
         * Register an observer that is called when changes happen to the data used by this adapter.
         * @param observer the observer to be registered
         */
        public void registerDataSetObserver(DataSetObserver observer);
       
        /**
         * Unregister an observer that has previously been registered
         * @param observer the observer to be unregistered
         */
        void unregisterDataSetObserver (DataSetObserver observer);
}




WheelScroller.java:
------------------


/*
 *  Android Wheel Control.
 *  https://code.google.com/p/android-wheel/
 *
 *  Copyright 2011 Yuri Kanivets
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package kankan.wheel;

import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.animation.Interpolator;
import android.widget.Scroller;

/**
 * Scroller class handles scrolling events and updates the
 */
public class WheelScroller {
    /**
     * Scrolling listener interface
     */
    public interface ScrollingListener {
        /**
         * Scrolling callback called when scrolling is performed.
         * @param distance the distance to scroll
         */
        void onScroll(int distance);

        /**
         * Starting callback called when scrolling is started
         */
        void onStarted();
       
        /**
         * Finishing callback called after justifying
         */
        void onFinished();
       
        /**
         * Justifying callback called to justify a view when scrolling is ended
         */
        void onJustify();
    }
   
    /** Scrolling duration */
    private static final int SCROLLING_DURATION = 400;

    /** Minimum delta for scrolling */
    public static final int MIN_DELTA_FOR_SCROLLING = 1;

    // Listener
    private ScrollingListener listener;
   
    // Context
    private Context context;
   
    // Scrolling
    private GestureDetector gestureDetector;
    private Scroller scroller;
    private int lastScrollY;
    private float lastTouchedY;
    private boolean isScrollingPerformed;

    /**
     * Constructor
     * @param context the current context
     * @param listener the scrolling listener
     */
    public WheelScroller(Context context, ScrollingListener listener) {
        gestureDetector = new GestureDetector(context, gestureListener);
        gestureDetector.setIsLongpressEnabled(false);
       
        scroller = new Scroller(context);

        this.listener = listener;
        this.context = context;
    }
   
    /**
     * Set the the specified scrolling interpolator
     * @param interpolator the interpolator
     */
    public void setInterpolator(Interpolator interpolator) {
        scroller.forceFinished(true);
        scroller = new Scroller(context, interpolator);
    }
   
    /**
     * Scroll the wheel
     * @param distance the scrolling distance
     * @param time the scrolling duration
     */
    public void scroll(int distance, int time) {
        scroller.forceFinished(true);

        lastScrollY = 0;
       
        scroller.startScroll(0, 0, 0, distance, time != 0 ? time : SCROLLING_DURATION);
        setNextMessage(MESSAGE_SCROLL);
       
        startScrolling();
    }
 
    /**
     * Stops scrolling
     */
    public void stopScrolling() {
        scroller.forceFinished(true);
    }
   
    /**
     * Handles Touch event
     * @param event the motion event
     * @return
     */
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                lastTouchedY = event.getY();
                scroller.forceFinished(true);
                clearMessages();
                break;
   
            case MotionEvent.ACTION_MOVE:
                // perform scrolling
                int distanceY = (int)(event.getY() - lastTouchedY);
                if (distanceY != 0) {
                    startScrolling();
                    listener.onScroll(distanceY);
                    lastTouchedY = event.getY();
                }
                break;
        }
       
        if (!gestureDetector.onTouchEvent(event) && event.getAction() == MotionEvent.ACTION_UP) {
            justify();
        }

        return true;
    }
   
    // gesture listener
    private SimpleOnGestureListener gestureListener = new SimpleOnGestureListener() {
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            // Do scrolling in onTouchEvent() since onScroll() are not call immediately
            //  when user touch and move the wheel
            return true;
        }
       
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            lastScrollY = 0;
            final int maxY = 0x7FFFFFFF;
            final int minY = -maxY;
            scroller.fling(0, lastScrollY, 0, (int) -velocityY, 0, 0, minY, maxY);
            setNextMessage(MESSAGE_SCROLL);
            return true;
        }
    };

    // Messages
    private final int MESSAGE_SCROLL = 0;
    private final int MESSAGE_JUSTIFY = 1;
   
    /**
     * Set next message to queue. Clears queue before.
     *
     * @param message the message to set
     */
    private void setNextMessage(int message) {
        clearMessages();
        animationHandler.sendEmptyMessage(message);
    }

    /**
     * Clears messages from queue
     */
    private void clearMessages() {
        animationHandler.removeMessages(MESSAGE_SCROLL);
        animationHandler.removeMessages(MESSAGE_JUSTIFY);
    }
   
    // animation handler
    private Handler animationHandler = new Handler() {
        public void handleMessage(Message msg) {
            scroller.computeScrollOffset();
            int currY = scroller.getCurrY();
            int delta = lastScrollY - currY;
            lastScrollY = currY;
            if (delta != 0) {
                listener.onScroll(delta);
            }
           
            // scrolling is not finished when it comes to final Y
            // so, finish it manually
            if (Math.abs(currY - scroller.getFinalY()) < MIN_DELTA_FOR_SCROLLING) {
                currY = scroller.getFinalY();
                scroller.forceFinished(true);
            }
            if (!scroller.isFinished()) {
                animationHandler.sendEmptyMessage(msg.what);
            } else if (msg.what == MESSAGE_SCROLL) {
                justify();
            } else {
                finishScrolling();
            }
        }
    };
   
    /**
     * Justifies wheel
     */
    private void justify() {
        listener.onJustify();
        setNextMessage(MESSAGE_JUSTIFY);
    }

    /**
     * Starts scrolling
     */
    private void startScrolling() {
        if (!isScrollingPerformed) {
            isScrollingPerformed = true;
            listener.onStarted();
        }
    }

    /**
     * Finishes scrolling
     */
    void finishScrolling() {
        if (isScrollingPerformed) {
            listener.onFinished();
            isScrollingPerformed = false;
        }
    }
}



WheelRecycle.java:
-----------------

/*
 *  Android Wheel Control.
 *  https://code.google.com/p/android-wheel/
 *
 *  Copyright 2011 Yuri Kanivets
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package kankan.wheel;

import java.util.LinkedList;
import java.util.List;

import android.view.View;
import android.widget.LinearLayout;

/**
 * Recycle stores wheel items to reuse.
 */
public class WheelRecycle {
        // Cached items
        private List<View> items;
       
        // Cached empty items
        private List<View> emptyItems;
       
        // Wheel view
        private WheelView wheel;
       
        /**
         * Constructor
         * @param wheel the wheel view
         */
        public WheelRecycle(WheelView wheel) {
                this.wheel = wheel;
        }

        /**
         * Recycles items from specified layout.
         * There are saved only items not included to specified range.
         * All the cached items are removed from original layout.
         *
         * @param layout the layout containing items to be cached
         * @param firstItem the number of first item in layout
         * @param range the range of current wheel items
         * @return the new value of first item number
         */
        public int recycleItems(LinearLayout layout, int firstItem, ItemsRange range) {
                int index = firstItem;
                for (int i = 0; i < layout.getChildCount();) {
                        if (!range.contains(index)) {
                                recycleView(layout.getChildAt(i), index);
                                layout.removeViewAt(i);
                                if (i == 0) { // first item
                                        firstItem++;
                                }
                        } else {
                                i++; // go to next item
                        }
                        index++;
                }
                return firstItem;
        }
       
        /**
         * Gets item view
         * @return the cached view
         */
        public View getItem() {
                return getCachedView(items);
        }

        /**
         * Gets empty item view
         * @return the cached empty view
         */
        public View getEmptyItem() {
                return getCachedView(emptyItems);
        }
       
        /**
         * Clears all views
         */
        public void clearAll() {
                if (items != null) {
                        items.clear();
                }
                if (emptyItems != null) {
                        emptyItems.clear();
                }
        }

        /**
         * Adds view to specified cache. Creates a cache list if it is null.
         * @param view the view to be cached
         * @param cache the cache list
         * @return the cache list
         */
        private List<View> addView(View view, List<View> cache) {
                if (cache == null) {
                        cache = new LinkedList<View>();
                }
               
                cache.add(view);
                return cache;
        }

        /**
         * Adds view to cache. Determines view type (item view or empty one) by index.
         * @param view the view to be cached
         * @param index the index of view
         */
        private void recycleView(View view, int index) {
                int count = wheel.getViewAdapter().getItemsCount();

                if ((index < 0 || index >= count) && !wheel.isCyclic()) {
                        // empty view
                        emptyItems = addView(view, emptyItems);
                } else {
                        while (index < 0) {
                                index = count + index;
                        }
                        index %= count;
                        items = addView(view, items);
                }
        }
       
        /**
         * Gets view from specified cache.
         * @param cache the cache
         * @return the first view from cache.
         */
        private View getCachedView(List<View> cache) {
                if (cache != null && cache.size() > 0) {
                        View view = cache.get(0);
                        cache.remove(0);
                        return view;
                }
                return null;
        }

}


OnWheelScrollListener.java:
--------------------------

/*
 *  Copyright 2010 Yuri Kanivets
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package kankan.wheel;

/**
 * Wheel scrolled listener interface.
 */
public interface OnWheelScrollListener {
        /**
         * Callback method to be invoked when scrolling started.
         * @param wheel the wheel view whose state has changed.
         */
        void onScrollingStarted(WheelView wheel);
       
        /**
         * Callback method to be invoked when scrolling ended.
         * @param wheel the wheel view whose state has changed.
         */
        void onScrollingFinished(WheelView wheel);
}



OnWheelClickedListener.java:
---------------------------


/*
 *  Copyright 2011 Yuri Kanivets
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package kankan.wheel;

/**
 * Wheel clicked listener interface.
 * <p>The onItemClicked() method is called whenever a wheel item is clicked
 * <li> New Wheel position is set
 * <li> Wheel view is scrolled
 */
public interface OnWheelClickedListener {
    /**
     * Callback method to be invoked when current item clicked
     * @param wheel the wheel view
     * @param itemIndex the index of clicked item
     */
    void onItemClicked(WheelView wheel, int itemIndex);
}


OnWheelChangedListener.java:
---------------------------

/*
 *  Copyright 2011 Yuri Kanivets
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package kankan.wheel;

/**
 * Wheel changed listener interface.
 * <p>The onChanged() method is called whenever current wheel positions is changed:
 * <li> New Wheel position is set
 * <li> Wheel view is scrolled
 */
public interface OnWheelChangedListener {
        /**
         * Callback method to be invoked when current item changed
         * @param wheel the wheel view whose state has changed
         * @param oldValue the old value of current item
         * @param newValue the new value of current item
         */
        void onChanged(WheelView wheel, int oldValue, int newValue);
}



NumericWheelAdapter.java:
------------------------

/*
 *  Copyright 2011 Yuri Kanivets
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package kankan.wheel;

import android.content.Context;

/**
 * Numeric Wheel adapter.
 */
public class NumericWheelAdapter extends AbstractWheelTextAdapter {
   
    /** The default min value */
    public static final int DEFAULT_MAX_VALUE = 9;

    /** The default max value */
    private static final int DEFAULT_MIN_VALUE = 0;
   
    // Values
    private int minValue;
    private int maxValue;
   
    // format
    private String format;
   
    /**
     * Constructor
     * @param context the current context
     */
    public NumericWheelAdapter(Context context) {
        this(context, DEFAULT_MIN_VALUE, DEFAULT_MAX_VALUE);
    }

    /**
     * Constructor
     * @param context the current context
     * @param minValue the wheel min value
     * @param maxValue the wheel max value
     */
    public NumericWheelAdapter(Context context, int minValue, int maxValue) {
        this(context, minValue, maxValue, null);
    }

    /**
     * Constructor
     * @param context the current context
     * @param minValue the wheel min value
     * @param maxValue the wheel max value
     * @param format the format string
     */
    public NumericWheelAdapter(Context context, int minValue, int maxValue, String format) {
        super(context);
       
        this.minValue = minValue;
        this.maxValue = maxValue;
        this.format = format;
    }

    @Override
    public CharSequence getItemText(int index) {
        if (index >= 0 && index < getItemsCount()) {
            int value = minValue + index;
            return format != null ? String.format(format, value) : Integer.toString(value);
        }
        return null;
    }

    @Override
    public int getItemsCount() {
        return maxValue - minValue + 1;
    }  
}



ItemsRange.java:
---------------

/*
 *  Android Wheel Control.
 *  https://code.google.com/p/android-wheel/
 *
 *  Copyright 2011 Yuri Kanivets
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package kankan.wheel;

/**
 * Range for visible items.
 */
public class ItemsRange {
        // First item number
        private int first;
       
        // Items count
        private int count;

        /**
         * Default constructor. Creates an empty range
         */
    public ItemsRange() {
        this(0, 0);
    }
   
        /**
         * Constructor
         * @param first the number of first item
         * @param count the count of items
         */
        public ItemsRange(int first, int count) {
                this.first = first;
                this.count = count;
        }
       
        /**
         * Gets number of  first item
         * @return the number of the first item
         */
        public int getFirst() {
                return first;
        }
       
        /**
         * Gets number of last item
         * @return the number of last item
         */
        public int getLast() {
                return getFirst() + getCount() - 1;
        }
       
        /**
         * Get items count
         * @return the count of items
         */
        public int getCount() {
                return count;
        }
       
        /**
         * Tests whether item is contained by range
         * @param index the item number
         * @return true if item is contained
         */
        public boolean contains(int index) {
                return index >= getFirst() && index <= getLast();
        }
}



AbstractWheelTextAdapter.java:
-----------------------------

/*
 *  Copyright 2011 Yuri Kanivets
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package kankan.wheel;

import android.content.Context;
import android.graphics.Typeface;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

/**
 * Abstract wheel adapter provides common functionality for adapters.
 */
public abstract class AbstractWheelTextAdapter extends AbstractWheelAdapter {
   
    /** Text view resource. Used as a default view for adapter. */
    public static final int TEXT_VIEW_ITEM_RESOURCE = -1;
   
    /** No resource constant. */
    protected static final int NO_RESOURCE = 0;
   
    /** Default text color */
    public static final int DEFAULT_TEXT_COLOR = 0xFF101010;
   
    /** Default text color */
    public static final int LABEL_COLOR = 0xFF700070;
   
    /** Default text size */
    public static final int DEFAULT_TEXT_SIZE = 24;
   
    // Text settings
    private int textColor = DEFAULT_TEXT_COLOR;
    private int textSize = DEFAULT_TEXT_SIZE;
   
    // Current context
    protected Context context;
    // Layout inflater
    protected LayoutInflater inflater;
   
    // Items resources
    protected int itemResourceId;
    protected int itemTextResourceId;
   
    // Empty items resources
    protected int emptyItemResourceId;
       
    /**
     * Constructor
     * @param context the current context
     */
    protected AbstractWheelTextAdapter(Context context) {
        this(context, TEXT_VIEW_ITEM_RESOURCE);
    }

    /**
     * Constructor
     * @param context the current context
     * @param itemResource the resource ID for a layout file containing a TextView to use when instantiating items views
     */
    protected AbstractWheelTextAdapter(Context context, int itemResource) {
        this(context, itemResource, NO_RESOURCE);
    }
   
    /**
     * Constructor
     * @param context the current context
     * @param itemResource the resource ID for a layout file containing a TextView to use when instantiating items views
     * @param itemTextResource the resource ID for a text view in the item layout
     */
    protected AbstractWheelTextAdapter(Context context, int itemResource, int itemTextResource) {
        this.context = context;
        itemResourceId = itemResource;
        itemTextResourceId = itemTextResource;
       
        inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }
   
    /**
     * Gets text color
     * @return the text color
     */
    public int getTextColor() {
        return textColor;
    }
   
    /**
     * Sets text color
     * @param textColor the text color to set
     */
    public void setTextColor(int textColor) {
        this.textColor = textColor;
    }
   
    /**
     * Gets text size
     * @return the text size
     */
    public int getTextSize() {
        return textSize;
    }
   
    /**
     * Sets text size
     * @param textSize the text size to set
     */
    public void setTextSize(int textSize) {
        this.textSize = textSize;
    }
   
    /**
     * Gets resource Id for items views
     * @return the item resource Id
     */
    public int getItemResource() {
        return itemResourceId;
    }
   
    /**
     * Sets resource Id for items views
     * @param itemResourceId the resource Id to set
     */
    public void setItemResource(int itemResourceId) {
        this.itemResourceId = itemResourceId;
    }
   
    /**
     * Gets resource Id for text view in item layout
     * @return the item text resource Id
     */
    public int getItemTextResource() {
        return itemTextResourceId;
    }
   
    /**
     * Sets resource Id for text view in item layout
     * @param itemTextResourceId the item text resource Id to set
     */
    public void setItemTextResource(int itemTextResourceId) {
        this.itemTextResourceId = itemTextResourceId;
    }

    /**
     * Gets resource Id for empty items views
     * @return the empty item resource Id
     */
    public int getEmptyItemResource() {
        return emptyItemResourceId;
    }

    /**
     * Sets resource Id for empty items views
     * @param emptyItemResourceId the empty item resource Id to set
     */
    public void setEmptyItemResource(int emptyItemResourceId) {
        this.emptyItemResourceId = emptyItemResourceId;
    }
   
   
    /**
     * Returns text for specified item
     * @param index the item index
     * @return the text of specified items
     */
    protected abstract CharSequence getItemText(int index);

    @Override
    public View getItem(int index, View convertView, ViewGroup parent) {
        if (index >= 0 && index < getItemsCount()) {
            if (convertView == null) {
                convertView = getView(itemResourceId, parent);
            }
            TextView textView = getTextView(convertView, itemTextResourceId);
            if (textView != null) {
                CharSequence text = getItemText(index);
                if (text == null) {
                    text = "";
                }
                textView.setText(text);
   
                if (itemResourceId == TEXT_VIEW_ITEM_RESOURCE) {
                    configureTextView(textView);
                }
            }
            return convertView;
        }
        return null;
    }

    @Override
    public View getEmptyItem(View convertView, ViewGroup parent) {
        if (convertView == null) {
            convertView = getView(emptyItemResourceId, parent);
        }
        if (emptyItemResourceId == TEXT_VIEW_ITEM_RESOURCE && convertView instanceof TextView) {
            configureTextView((TextView)convertView);
        }
           
        return convertView;
        }

    /**
     * Configures text view. Is called for the TEXT_VIEW_ITEM_RESOURCE views.
     * @param view the text view to be configured
     */
    protected void configureTextView(TextView view) {
        view.setTextColor(textColor);
        view.setGravity(Gravity.CENTER);
        view.setTextSize(textSize);
        view.setLines(1);
        view.setTypeface(Typeface.SANS_SERIF, Typeface.BOLD);
    }
   
    /**
     * Loads a text view from view
     * @param view the text view or layout containing it
     * @param textResource the text resource Id in layout
     * @return the loaded text view
     */
    private TextView getTextView(View view, int textResource) {
        TextView text = null;
        try {
            if (textResource == NO_RESOURCE && view instanceof TextView) {
                text = (TextView) view;
            } else if (textResource != NO_RESOURCE) {
                text = (TextView) view.findViewById(textResource);
            }
        } catch (ClassCastException e) {
            Log.e("AbstractWheelAdapter", "You must supply a resource ID for a TextView");
            throw new IllegalStateException(
                    "AbstractWheelAdapter requires the resource ID to be a TextView", e);
        }
       
        return text;
    }
   
    /**
     * Loads view from resources
     * @param resource the resource Id
     * @return the loaded view or null if resource is not set
     */
    private View getView(int resource, ViewGroup parent) {
        switch (resource) {
        case NO_RESOURCE:
            return null;
        case TEXT_VIEW_ITEM_RESOURCE:
            return new TextView(context);
        default:
            return inflater.inflate(resource, parent, false);  
        }
    }
}



AbstractWheelAdapter.java:
--------------------------

/*
 *  Copyright 2011 Yuri Kanivets
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package kankan.wheel;

import java.util.LinkedList;
import java.util.List;

import android.database.DataSetObserver;
import android.view.View;
import android.view.ViewGroup;

/**
 * Abstract Wheel adapter.
 */
public abstract class AbstractWheelAdapter implements WheelViewAdapter {
    // Observers
    private List<DataSetObserver> datasetObservers;
   
    @Override
    public View getEmptyItem(View convertView, ViewGroup parent) {
        return null;
    }

    @Override
    public void registerDataSetObserver(DataSetObserver observer) {
        if (datasetObservers == null) {
            datasetObservers = new LinkedList<DataSetObserver>();
        }
        datasetObservers.add(observer);
    }

    @Override
    public void unregisterDataSetObserver(DataSetObserver observer) {
        if (datasetObservers != null) {
            datasetObservers.remove(observer);
        }
    }
   
    /**
     * Notifies observers about data changing
     */
    protected void notifyDataChangedEvent() {
        if (datasetObservers != null) {
            for (DataSetObserver observer : datasetObservers) {
                observer.onChanged();
            }
        }
    }
   
    /**
     * Notifies observers about invalidating data
     */
    protected void notifyDataInvalidatedEvent() {
        if (datasetObservers != null) {
            for (DataSetObserver observer : datasetObservers) {
                observer.onInvalidated();
            }
        }
    }
}