Remove GreenDroid

pull/46/head
Alex Baker 12 years ago
parent 6f66f4f3cc
commit 0f8cf75228

@ -59,11 +59,14 @@ android.applicationVariants.all { variant ->
dependencies {
compile 'com.android.support:support-v4:18.0.0'
compile 'com.actionbarsherlock:actionbarsherlock:4.4.0@aar'
compile 'net.simonvt.menudrawer:menudrawer:3.0.4@aar'
compile project(":android-aac-enc")
compile project(":greendroid")
compile project(":api")
compile fileTree(dir: "libs", includes: ["*.jar"])
compile 'net.simonvt.menudrawer:menudrawer:3.0.4@aar'
compile group: 'com.google.guava', name: 'guava', version: '11.0.1', transitive: false
compile group: 'com.google.code.gson', name: 'gson', version: '1.7.1', transitive: false
compile group: 'org.codehaus.jackson', name: 'jackson-core-asl', version: '1.6.7', transitive: false

@ -12,7 +12,6 @@ split.density=false
# Project target.
target=android-18
apk-configurations=
android.library.reference.1=../android-aac-enc
android.library.reference.2=../api
android.library.reference.3=../greendroid
android.library.reference.1=../api
android.library.reference.2=../android-aac-enc

@ -88,7 +88,6 @@
android:icon="@drawable/icon"
android:label="@string/app_name"
android:theme="@style/Theme"
android:name="greendroid.app.GDApplication"
android:hardwareAccelerated="false"
android:manageSpaceActivity="com.todoroo.astrid.core.OldTaskPreferences">

@ -80,7 +80,6 @@ import com.todoroo.astrid.data.TaskAttachment;
import com.todoroo.astrid.data.User;
import com.todoroo.astrid.files.FilesAction;
import com.todoroo.astrid.files.FilesControlSet;
import com.todoroo.astrid.helper.AsyncImageView;
import com.todoroo.astrid.helper.TaskAdapterAddOnManager;
import com.todoroo.astrid.notes.NotesAction;
import com.todoroo.astrid.notes.NotesDecorationExposer;
@ -90,7 +89,6 @@ import com.todoroo.astrid.tags.TaskToTagMetadata;
import com.todoroo.astrid.timers.TimerDecorationExposer;
import com.todoroo.astrid.ui.CheckableImageView;
import com.todoroo.astrid.utility.Constants;
import com.todoroo.astrid.utility.ResourceDrawableCache;
/**
* Adapter for displaying a user's tasks as a list
@ -358,8 +356,6 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
viewHolder.view = view;
viewHolder.rowBody = (ViewGroup)view.findViewById(R.id.rowBody);
viewHolder.nameView = (TextView)view.findViewById(R.id.title);
viewHolder.picture = (AsyncImageView)view.findViewById(R.id.picture);
viewHolder.pictureBorder = (ImageView)view.findViewById(R.id.pictureBorder);
viewHolder.completeBox = (CheckableImageView)view.findViewById(R.id.completeBox);
viewHolder.dueDate = (TextView)view.findViewById(R.id.dueDate);
viewHolder.tagsView = (TextView)view.findViewById(R.id.tagsDisplay);
@ -447,8 +443,6 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
public ViewGroup rowBody;
public TextView nameView;
public CheckableImageView completeBox;
public AsyncImageView picture;
public ImageView pictureBorder;
public TextView dueDate;
public TextView tagsView;
public TextView details1, details2;
@ -621,16 +615,6 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
viewHolder.completeBox.setOnTouchListener(otl);
viewHolder.completeBox.setOnClickListener(completeBoxListener);
if (viewHolder.picture != null) {
viewHolder.picture.setOnTouchListener(otl);
viewHolder.picture.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
viewHolder.completeBox.performClick();
}
});
}
if (viewHolder.taskActionContainer != null) {
viewHolder.taskActionContainer.setOnClickListener(new OnClickListener() {
@Override
@ -1135,39 +1119,6 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
}
}
paint.setTextSize(detailTextSize);
// image view
final AsyncImageView pictureView = viewHolder.picture; {
if (pictureView != null) {
if(Task.USER_ID_SELF.equals(task.getValue(Task.USER_ID))) {
pictureView.setVisibility(View.GONE);
if (viewHolder.pictureBorder != null) {
viewHolder.pictureBorder.setVisibility(View.GONE);
}
} else {
pictureView.setVisibility(View.VISIBLE);
if (viewHolder.pictureBorder != null) {
viewHolder.pictureBorder.setVisibility(View.VISIBLE);
}
pictureView.setUrl(null);
if (Task.USER_ID_UNASSIGNED.equals(task.getValue(Task.USER_ID))) {
pictureView.setDefaultImageDrawable(ResourceDrawableCache.getImageDrawableFromId(resources, R.drawable.icn_anyone_transparent));
} else {
pictureView.setDefaultImageDrawable(ResourceDrawableCache.getImageDrawableFromId(resources, R.drawable.icn_default_person_image));
if (!TextUtils.isEmpty(viewHolder.imageUrl)) {
pictureView.setUrl(viewHolder.imageUrl);
} else if (!TextUtils.isEmpty(task.getValue(Task.USER))) {
try {
JSONObject user = new JSONObject(task.getValue(Task.USER));
pictureView.setUrl(user.optString("picture")); //$NON-NLS-1$
} catch (JSONException e) {
//
}
}
}
}
}
}
}
setupCompleteBox(viewHolder);
@ -1177,7 +1128,6 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
private void setupCompleteBox(ViewHolder viewHolder) {
// complete box
final Task task = viewHolder.task;
final AsyncImageView pictureView = viewHolder.picture;
final CheckableImageView checkBoxView = viewHolder.completeBox; {
boolean completed = task.isCompleted();
checkBoxView.setChecked(completed);
@ -1199,23 +1149,7 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
return;
}
if (checkBoxView.isChecked()) {
if (pictureView != null) {
pictureView.setVisibility(View.GONE);
}
if (viewHolder.pictureBorder != null) {
viewHolder.pictureBorder.setVisibility(View.GONE);
}
}
if (pictureView != null && pictureView.getVisibility() == View.VISIBLE) {
checkBoxView.setVisibility(View.INVISIBLE);
if (viewHolder.pictureBorder != null) {
viewHolder.pictureBorder.setBackgroundDrawable(IMPORTANCE_DRAWABLES_LARGE[value]);
}
} else {
checkBoxView.setVisibility(View.VISIBLE);
}
checkBoxView.setVisibility(View.VISIBLE);
}
}

@ -294,16 +294,6 @@ public class UpdateAdapter extends CursorAdapter {
}
private void setupUserActivityRow(View view, UserActivity activity, User user) {
final AsyncImageView pictureView = (AsyncImageView)view.findViewById(R.id.picture); {
if (user.containsNonNullValue(USER_PICTURE)) {
String pictureUrl = user.getPictureUrl(USER_PICTURE, RemoteModel.PICTURE_THUMB);
pictureView.setUrl(pictureUrl);
} else {
pictureView.setUrl(null);
}
pictureView.setVisibility(View.VISIBLE);
}
final AsyncImageView commentPictureView = (AsyncImageView)view.findViewById(R.id.comment_picture); {
String pictureThumb = activity.getPictureUrl(UserActivity.PICTURE, RemoteModel.PICTURE_MEDIUM);
String pictureFull = activity.getPictureUrl(UserActivity.PICTURE, RemoteModel.PICTURE_LARGE);
@ -333,16 +323,6 @@ public class UpdateAdapter extends CursorAdapter {
}
private void setupHistoryRow(View view, History history, User user) {
final AsyncImageView pictureView = (AsyncImageView)view.findViewById(R.id.picture); {
if (user.containsNonNullValue(USER_PICTURE)) {
String pictureUrl = user.getPictureUrl(USER_PICTURE, RemoteModel.PICTURE_THUMB);
pictureView.setUrl(pictureUrl);
} else {
pictureView.setUrl(null);
}
pictureView.setVisibility(View.VISIBLE);
}
final AsyncImageView commentPictureView = (AsyncImageView)view.findViewById(R.id.comment_picture);
commentPictureView.setVisibility(View.GONE);
@ -376,7 +356,7 @@ public class UpdateAdapter extends CursorAdapter {
if (pictureThumb != null && imageCache.contains(pictureThumb) && updateBitmap == null) {
try {
commentPictureView.setDefaultImageBitmap(imageCache.get(pictureThumb));
commentPictureView.setImageBitmap(imageCache.get(pictureThumb));
} catch (IOException e) {
e.printStackTrace();
}
@ -390,7 +370,7 @@ public class UpdateAdapter extends CursorAdapter {
AlertDialog image = new AlertDialog.Builder(fragment.getActivity()).create();
AsyncImageView imageView = new AsyncImageView(fragment.getActivity());
imageView.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
imageView.setDefaultImageResource(android.R.drawable.ic_menu_gallery);
imageView.setImageResource(android.R.drawable.ic_menu_gallery);
if (updateBitmap != null) {
imageView.setImageBitmap(updateBitmap);
} else {
@ -418,80 +398,7 @@ public class UpdateAdapter extends CursorAdapter {
public static Spanned getUpdateComment(final AstridActivity context, UserActivity activity, User user, String linkColor, String fromView) {
String message = activity.getValue(UserActivity.MESSAGE);
if (!Preferences.getBoolean(R.string.p_show_caption_comments, false)) {
return Html.fromHtml(message);
}
String userDisplay;
if (activity.getValue(UserActivity.USER_UUID).equals(Task.USER_ID_SELF)) {
userDisplay = context.getString(R.string.update_string_user_self);
} else if (user == null) {
userDisplay = context.getString(R.string.ENA_no_user);
} else {
userDisplay = user.getDisplayName(USER_NAME, USER_FIRST_NAME, USER_LAST_NAME);
}
if (TextUtils.isEmpty(userDisplay)) {
userDisplay = context.getString(R.string.ENA_no_user);
}
String targetName = activity.getValue(UserActivity.TARGET_NAME);
String action = activity.getValue(UserActivity.ACTION);
int commentResource = 0;
if (UserActivity.ACTION_TASK_COMMENT.equals(action)) {
if (fromView.equals(FROM_TASK_VIEW) || TextUtils.isEmpty(targetName)) {
commentResource = R.string.update_string_default_comment;
} else {
commentResource = R.string.update_string_task_comment;
}
} else if (UserActivity.ACTION_TAG_COMMENT.equals(action)) {
if (fromView.equals(FROM_TAG_VIEW) || TextUtils.isEmpty(targetName)) {
commentResource = R.string.update_string_default_comment;
} else {
commentResource = R.string.update_string_tag_comment;
}
}
if (commentResource == 0) {
return Html.fromHtml(String.format("%s %s", userDisplay, message)); //$NON-NLS-1$
}
String original = context.getString(commentResource, userDisplay, targetName, message);
int taskLinkIndex = original.indexOf(TARGET_LINK_PREFIX);
if (taskLinkIndex < 0) {
return Html.fromHtml(original);
}
String[] components = original.split(" "); //$NON-NLS-1$
SpannableStringBuilder builder = new SpannableStringBuilder();
StringBuilder htmlStringBuilder = new StringBuilder();
for (String comp : components) {
Matcher m = TARGET_LINK_PATTERN.matcher(comp);
if (m.find()) {
builder.append(Html.fromHtml(htmlStringBuilder.toString()));
htmlStringBuilder.setLength(0);
String linkType = m.group(1);
CharSequence link = getLinkSpan(context, activity, targetName, linkColor, linkType);
if (link != null) {
builder.append(link);
if (!m.hitEnd()) {
builder.append(comp.substring(m.end()));
}
builder.append(' ');
}
} else {
htmlStringBuilder.append(comp);
htmlStringBuilder.append(' ');
}
}
if (htmlStringBuilder.length() > 0) {
builder.append(Html.fromHtml(htmlStringBuilder.toString()));
}
return builder;
return Html.fromHtml(message);
}
public static String getHistoryComment(final AstridActivity context, History history, User user, String linkColor, String fromView) {

@ -5,27 +5,21 @@
*/
package com.todoroo.astrid.helper;
import java.io.IOException;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.os.Looper;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.widget.ImageView;
import com.todoroo.andlib.service.ContextManager;
import java.io.IOException;
import edu.mit.mobile.android.imagecache.ImageCache;
/**
* Subclass of greendroid.widget.AsyncImageView, so that we can cache the image
* locally when user is offline
*
* IMPORTANT: cannot load a cached image by setting the url in an xml file.
* ImageDiskCache object is created after object is loaded from xml
*/
public class AsyncImageView extends greendroid.widget.AsyncImageView {
public class AsyncImageView extends ImageView {
private final ImageCache imageDiskCache;
private Bitmap cacheImage;
@ -42,7 +36,7 @@ public class AsyncImageView extends greendroid.widget.AsyncImageView {
super(context, set, defStyle);
imageDiskCache = getImageCache();
}
@Override
public void setUrl(String url) {
if (cacheImage != null && cacheURL.equals(url) && !TextUtils.isEmpty(url)) {
setImageBitmap(cacheImage);
@ -57,26 +51,6 @@ public class AsyncImageView extends greendroid.widget.AsyncImageView {
//
}
}
super.setUrl(url);
}
public Bitmap getImageBitmap() {
setDrawingCacheEnabled(true);
// this is the important code :)
// Without it the view will have a dimension of 0,0 and the bitmap will be null
measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
layout(0, 0, getMeasuredWidth(), getMeasuredHeight());
buildDrawingCache(true);
Bitmap drawingCache = getDrawingCache();
if (drawingCache == null) {
return null;
}
Bitmap b = Bitmap.createBitmap(getDrawingCache());
setDrawingCacheEnabled(false); // clear drawing cache
return b;
}
private static volatile ImageCache imageCacheInstance = null;
@ -98,5 +72,4 @@ public class AsyncImageView extends greendroid.widget.AsyncImageView {
}
return imageCacheInstance;
}
}

@ -60,7 +60,6 @@ import com.todoroo.astrid.service.MetadataService;
import com.todoroo.astrid.service.StartupService;
import com.todoroo.astrid.service.TaskService;
import com.todoroo.astrid.timers.TimerActionControlSet.TimerActionListener;
import com.todoroo.astrid.utility.ResourceDrawableCache;
import org.json.JSONObject;
import org.tasks.R;
@ -369,29 +368,14 @@ public class EditNoteActivity extends LinearLayout implements TimerActionListene
public View getUpdateNotes(NoteOrUpdate note, ViewGroup parent) {
View convertView;
if (Preferences.getBoolean(R.string.p_show_caption_comments, false)) {
convertView = ((Activity)getContext()).getLayoutInflater().inflate(
View convertView = ((Activity)getContext()).getLayoutInflater().inflate(
R.layout.update_adapter_row, parent, false);
}
else {
convertView = ((Activity)getContext()).getLayoutInflater().inflate(
R.layout.update_adapter_row_no_caption, parent, false);
}
bindView(convertView, note);
return convertView;
}
/** Helper method to set the contents and visibility of each field */
public synchronized void bindView(View view, NoteOrUpdate item) {
// picture
if (Preferences.getBoolean(R.string.p_show_caption_comments, false)) {
final AsyncImageView pictureView = (AsyncImageView)view.findViewById(R.id.picture);
pictureView.setDefaultImageDrawable(ResourceDrawableCache.getImageDrawableFromId(resources, R.drawable.icn_default_person_image));
pictureView.setUrl(item.picture);
}
// name
final TextView nameView = (TextView)view.findViewById(R.id.title); {
nameView.setText(item.title);

@ -1,80 +0,0 @@
package com.todoroo.astrid.utility;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import org.tasks.R;
import com.todoroo.andlib.service.ContextManager;
/**
* This class caches common images based on resource ID to avoid
* the performance hit from constantly loading them from disk
* @author Sam
*
*/
public class ResourceDrawableCache {
private static Drawable ICN_DEFAULT_PERSON_IMAGE = null;
private static Drawable ICN_ANYONE = null;
private static Drawable ICN_ANYONE_TRANSPARENT = null;
private static Drawable ICN_ADD_CONTACT = null;
private static Drawable DEFAULT_LIST_0 = null;
private static Drawable DEFAULT_LIST_1 = null;
private static Drawable DEFAULT_LIST_2 = null;
private static Drawable DEFAULT_LIST_3 = null;
public static Drawable getImageDrawableFromId(Resources r, int resId) {
if (r == null) {
r = ContextManager.getResources();
}
switch(resId) {
case R.drawable.icn_default_person_image:
if (ICN_DEFAULT_PERSON_IMAGE == null) {
ICN_DEFAULT_PERSON_IMAGE = r.getDrawable(resId);
}
return ICN_DEFAULT_PERSON_IMAGE;
case R.drawable.icn_anyone:
if (ICN_ANYONE == null) {
ICN_ANYONE = r.getDrawable(resId);
}
return ICN_ANYONE;
case R.drawable.icn_anyone_transparent:
if (ICN_ANYONE_TRANSPARENT == null) {
ICN_ANYONE_TRANSPARENT = r.getDrawable(resId);
}
return ICN_ANYONE_TRANSPARENT;
case R.drawable.icn_add_contact:
if (ICN_ADD_CONTACT == null) {
ICN_ADD_CONTACT = r.getDrawable(resId);
}
return ICN_ADD_CONTACT;
case R.drawable.default_list_0:
if (DEFAULT_LIST_0 == null) {
DEFAULT_LIST_0 = r.getDrawable(resId);
}
return DEFAULT_LIST_0;
case R.drawable.default_list_1:
if (DEFAULT_LIST_1 == null) {
DEFAULT_LIST_1 = r.getDrawable(resId);
}
return DEFAULT_LIST_1;
case R.drawable.default_list_2:
if (DEFAULT_LIST_2 == null) {
DEFAULT_LIST_2 = r.getDrawable(resId);
}
return DEFAULT_LIST_2;
case R.drawable.default_list_3:
if (DEFAULT_LIST_3 == null) {
DEFAULT_LIST_3 = r.getDrawable(resId);
}
return DEFAULT_LIST_3;
default:
return r.getDrawable(resId);
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 508 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 678 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 571 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

@ -20,27 +20,6 @@
android:layout_marginBottom="5dip"
android:minHeight="45dip">
<ImageView
android:id="@+id/pictureBorder"
android:layout_width="39dip"
android:layout_height="39dip"
android:layout_marginLeft="8dip"
android:layout_centerVertical="true"
android:background="@drawable/icn_default_person_image"
android:scaleType="center"
android:visibility="gone" >
</ImageView>
<com.todoroo.astrid.helper.AsyncImageView
android:id="@+id/picture"
android:layout_width="39dip"
android:layout_height="39dip"
android:padding="2dip"
android:layout_marginLeft="8dip"
android:layout_centerVertical="true"
astrid:defaultSrc="@drawable/icn_default_person_image"
android:scaleType="fitCenter"
android:visibility="gone" />
<com.todoroo.astrid.ui.CheckableImageView
android:id="@+id/completeBox"
android:layout_width="45dip"

@ -20,27 +20,6 @@
android:layout_marginBottom="5dip"
android:minHeight="40dip">
<ImageView
android:id="@+id/pictureBorder"
android:layout_width="35dip"
android:layout_height="35dip"
android:layout_marginLeft="8dip"
android:layout_centerVertical="true"
android:background="@drawable/icn_default_person_image"
android:scaleType="center"
android:visibility="gone" >
</ImageView>
<com.todoroo.astrid.helper.AsyncImageView
android:id="@+id/picture"
android:layout_width="35dip"
android:layout_height="35dip"
android:padding="2dip"
android:layout_marginLeft="8dip"
android:layout_centerVertical="true"
astrid:defaultSrc="@drawable/icn_default_person_image"
android:scaleType="fitCenter"
android:visibility="gone" />
<com.todoroo.astrid.ui.CheckableImageView
android:id="@+id/completeBox"
android:layout_width="45dip"

@ -20,25 +20,14 @@
android:paddingLeft="6dip"
android:paddingRight="6dip">
<!-- picture -->
<com.todoroo.astrid.helper.AsyncImageView android:id="@+id/picture"
android:layout_width="40dip"
android:layout_height="40dip"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_marginTop="5dip"
android:layout_marginLeft="3dip"
astrid:defaultSrc="@drawable/icn_default_person_image"
android:scaleType="fitCenter" />
<!-- title -->
<TextView android:id="@+id/title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:paddingLeft="54dip"
android:paddingRight="5dip"
android:paddingLeft="5dip"
android:paddingRight="3dip"
style="@style/TextAppearance.TAd_ItemTitle"
android:textSize="16sp"/>
@ -49,7 +38,7 @@
android:layout_height="wrap_content"
android:layout_below="@id/title"
android:layout_alignLeft="@id/title"
android:layout_marginLeft="54dip"
android:layout_marginLeft="5dip"
android:paddingTop="1dip"
style="@style/TextAppearance.TAd_ItemDueDate"
android:textStyle="normal"
@ -58,19 +47,6 @@
android:textSize="12sp"
android:singleLine="true"/>
<!-- picture -->
<com.todoroo.astrid.helper.AsyncImageView android:id="@+id/comment_picture"
android:layout_width="100dip"
android:layout_height="100dip"
android:layout_below="@id/date"
android:paddingTop="5dip"
astrid:defaultSrc="@drawable/icn_default_person_image"
android:scaleType="fitStart"
android:layout_marginLeft="50dip"
android:visibility="gone" />
</RelativeLayout>
<!-- picture -->
@ -79,10 +55,9 @@
android:layout_width="50dip"
android:layout_height="50dip"
android:layout_alignParentBottom="true"
android:layout_marginLeft="50dip"
android:layout_marginLeft="5dip"
android:layout_marginBottom="4dip"
android:visibility="gone"
astrid:defaultSrc="@android:drawable/ic_menu_gallery"
android:scaleType="fitCenter"/>
</LinearLayout>

@ -1,77 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
** Copyright (c) 2012 Todoroo Inc
**
** See the file "LICENSE" for the full license governing this code.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:astrid="http://schemas.android.com/apk/res/org.tasks"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:minHeight="55dip"
android:orientation="vertical">
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@android:drawable/list_selector_background"
android:paddingTop="5dip"
android:paddingBottom="5dip"
android:paddingLeft="6dip"
android:paddingRight="6dip">
<!-- title -->
<TextView android:id="@+id/title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:paddingLeft="5dip"
android:paddingRight="3dip"
style="@style/TextAppearance.TAd_ItemTitle"
android:textSize="16sp"/>
<!-- activity date -->
<TextView android:id="@+id/date"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@id/title"
android:layout_alignLeft="@id/title"
android:layout_marginLeft="5dip"
android:paddingTop="1dip"
style="@style/TextAppearance.TAd_ItemDueDate"
android:textStyle="normal"
android:gravity="left"
android:ellipsize="end"
android:textSize="12sp"
android:singleLine="true"/>
<!-- picture -->
<com.todoroo.astrid.helper.AsyncImageView android:id="@+id/comment_picture"
android:layout_width="100dip"
android:layout_height="100dip"
android:layout_below="@id/date"
android:paddingTop="5dip"
astrid:defaultSrc="@drawable/icn_default_person_image"
android:scaleType="fitStart"
android:layout_marginLeft="50dip"
android:visibility="gone" />
</RelativeLayout>
<!-- picture -->
<com.todoroo.astrid.helper.AsyncImageView
android:id="@+id/comment_picture"
android:layout_width="50dip"
android:layout_height="50dip"
android:layout_alignParentBottom="true"
android:layout_marginLeft="5dip"
android:layout_marginBottom="4dip"
android:visibility="gone"
astrid:defaultSrc="@android:drawable/ic_menu_gallery"
android:scaleType="fitCenter"/>
</LinearLayout>

@ -67,9 +67,6 @@
<!-- show comments in task edit -->
<string name="p_show_task_edit_comments">p_show_task_edit_comments</string>
<!-- show caption of comments in task edit -->
<string name="p_show_caption_comments">p_show_caption_comments</string>
<!-- show save and cancel buttons in task edit -->
<string name="p_save_and_cancel">p_save_and_cancel</string>

@ -7,9 +7,6 @@
Please do not translate this part of the string. -->
<!-- These are still in use -->
<string name="update_string_default_comment">%1$s commented: %3$s</string>
<string name="update_string_task_comment">%1$s on $link_task: %3$s</string>
<string name="update_string_tag_comment">%1$s on %2$s: %3$s</string>
<string name="update_string_user_self">You</string>
<string name="history_yourself">yourself</string>

@ -438,5 +438,9 @@
<item name="android:textSize">14dip</item>
<item name="android:textColor">@android:color/black</item>
</style>
<style name="TextAppearance.Medium">
<item name="android:textSize">18sp</item>
</style>
</resources>

@ -1,29 +0,0 @@
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.5.+'
}
}
apply plugin: 'android-library'
repositories {
mavenCentral()
}
android {
compileSdkVersion 18
buildToolsVersion "18.1"
defaultConfig {
minSdkVersion 7
targetSdkVersion 18
}
}
dependencies {
compile 'com.android.support:support-v4:18.0.0'
compile 'com.actionbarsherlock:actionbarsherlock:4.4.0@aar'
}

@ -1,15 +0,0 @@
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system use,
# "ant.properties", and override values to adapt the script to your
# project structure.
android.library=true
# Indicates whether an apk should be generated for each density.
split.density=false
# Project target.
target=android-18

@ -1,25 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
** Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
**
** 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.
*/
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.cyrilmottier.android.greendroid"
android:versionCode="1"
android:versionName="1.0">
<application/>
</manifest>

@ -1,144 +0,0 @@
/*
* Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
*
* 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 greendroid.app;
import greendroid.widget.GDActionBar;
import greendroid.widget.ActionBarItem;
import android.app.Activity;
import android.app.Application;
import android.view.View;
import android.widget.FrameLayout;
/**
* Defines all methods related to Activities embedding an {@link GDActionBar}
*
* @author Cyril Mottier
*/
public interface ActionBarActivity {
/**
* The optional title of the launched ActionBarActivity
*
* @see Activity#setTitle(CharSequence)
* @see Activity#setTitle(int)
*/
static final String GD_ACTION_BAR_TITLE = "greendroid.app.ActionBarActivity.GD_ACTION_BAR_TITLE";
/**
* An integer that can be used to force the ActionBar to a particular
* visibility. This is especially useful when using GDActivity inside a
* GDTabActivity.
*
* @see View#VISIBLE
* @see View#INVISIBLE
* @see View#GONE
*/
static final String GD_ACTION_BAR_VISIBILITY = "greendroid.app.ActionBarActivity.GD_ACTION_BAR_VISIBILITY";
/**
* Clients may use this method to listen to {@link ActionBarItem}s clicks.
*
* @param item The {@link ActionBarItem} that has been clicked
* @param position The position of the clicked item. This number is equal or
* greater to zero. 0 is the leftmost item.
* @return true if the method has handled the click on the
* {@link ActionBarItem} at position <em>position</em>. Otherwise it
* returns false.
*/
boolean onHandleActionBarItemClick(ActionBarItem item, int position);
/**
* Returns the content view. Please note the content view is not the entire
* view but a {@link FrameLayout} that contains everything but the
* {@link GDActionBar}.
*
* @return The content view
*/
FrameLayout getContentView();
/**
* Returns the {@link GDActionBar}. Listening to {@link GDActionBar} events
* should be done via the
* {@link ActionBarActivity#onHandleActionBarItemClick(ActionBarItem, int)}
* method. Most of the time, this method don't need to be used directly.
*
* @see {@link ActionBarActivity#onHandleActionBarItemClick(ActionBarItem, int)}
* @see {@link ActionBarActivity#addActionBarItem(ActionBarItem)}
* @see {@link ActionBarActivity#addActionBarItem(greendroid.widget.ActionBarItem.Type)}
* @return The {@link GDActionBar} currently displayed on screen
*/
GDActionBar getGDActionBar();
/**
* A simple utility method that casts the {@link Application} returned by
* {@link #getApplication()} into a {@link GDApplication}
*
* @return The current {@link GDApplication}
*/
GDApplication getGDApplication();
/**
* Add a new item to the {@link GDActionBar}.
*
* @param item The item to add to the {@link GDActionBar}
*/
ActionBarItem addActionBarItem(ActionBarItem item);
/**
* Add a new item to the {@link GDActionBar}.
*
* @param item The item to add to the {@link GDActionBar}
* @param itemId Unique item ID. Use {@link GDActionBar#NONE} if you do not
* need a unique ID.
*/
ActionBarItem addActionBarItem(ActionBarItem item, int itemId);
/**
* Adds a new item of type <em>type</em> to the {@link GDActionBar}.
*
* @param actionBarItemType The item to add to the {@link GDActionBar}
*/
ActionBarItem addActionBarItem(ActionBarItem.Type actionBarItemType);
/**
* Adds a new item of type <em>type</em> to the {@link GDActionBar}.
*
* @param actionBarItemType The item to add to the {@link GDActionBar}
* @param itemId Unique item ID. Use {@link GDActionBar#NONE} if you do not
* need a unique ID.
*/
ActionBarItem addActionBarItem(ActionBarItem.Type actionBarItemType, int itemId);
/**
* Returns the identifier of the layout that needs to be created for this
* {@link ActionBarActivity}
*
* @return The layout identifier of the layout to create
*/
int createLayout();
/**
* Called at the beginning of the {@link Activity#onContentChanged()}
* method. This may be used to initialize all references on elements.
*/
void onPreContentChanged();
/**
* Called at the end of the {@link Activity#onContentChanged()} method. This
* may be use to initialize the content of the layout (titles, etc.)
*/
void onPostContentChanged();
}

@ -1,303 +0,0 @@
/*
* Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
*
* 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 greendroid.app;
import com.cyrilmottier.android.greendroid.R;
import greendroid.util.Config;
import greendroid.widget.GDActionBar;
import greendroid.widget.ActionBarHost;
import greendroid.widget.ActionBarItem;
import greendroid.widget.GDActionBar.OnActionBarListener;
import greendroid.widget.GDActionBar.Type;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.widget.FrameLayout;
/**
* <p>
* An {@link GDActivity} is a regular Activity that always hosts an
* {@link GDActionBar}. It is extremely simple to use as you have nothing
* particular to do. Indeed, the ActionBar is automatically added to your own
* layout when using the {@link #getContentView()} method. You can also use one
* of the setActionBarContentView utility methods. As a result, a basic
* {@link GDActivity} will often be initialized using the following snippet of
* code:
* </p>
*
* <pre>
* protected void onCreate(Bundle savedInstanceState) {
* super.onCreate(savedInstanceState);
*
* setActionBarContentView(R.layout.main);
* }
* </pre>
* <p>
* An ActionBar is a widget that may contains actions items and a title. You can
* also set the title putting an extra string with the key
* {@link GD_ACTION_BAR_TITLE} in your Intent:
* </p>
*
* <pre>
* Intent intent = new Intent(this, MyGDActivity.class);
* intent.putExtra(ActionBarActivity.GD_ACTION_BAR_TITLE, &quot;Next screen title&quot;);
* startActivity(intent);
* </pre>
* <p>
* Note: An {@link GDActivity} automatically handle the type of the ActionBar
* (Dashboard or Normal) depending on the value returned by the
* getHomeActivityClass of your {@link GDApplication}. However you can force the
* type of the action bar in your constructor.
* </p>
*
* <pre>
* public MyGDActivity() {
* super(ActionBar.Type.Dashboard);
* }
* </pre>
* <p>
* All Activities that inherits from an {@link GDActivity} are notified when an
* action button is tapped in the onHandleActionBarItemClick(ActionBarItem, int)
* method. By default this method does nothing but return false.
* </p>
*
* @see {@link GDApplication#getHomeActivityClass()}
* @see {@link ActionBarActivity#GD_ACTION_BAR_TITLE}
* @see {@link GDActivity#setActionBarContentView(int)}
* @see {@link GDActivity#setActionBarContentView(View)}
* @see {@link GDActivity#setActionBarContentView(View, LayoutParams)}
* @author Cyril Mottier
*/
public class GDActivity extends Activity implements ActionBarActivity {
private static final String LOG_TAG = GDActivity.class.getSimpleName();
private boolean mDefaultConstructorUsed = false;
private Type mActionBarType;
private ActionBarHost mActionBarHost;
public GDActivity() {
this(Type.Normal);
mDefaultConstructorUsed = true;
}
public GDActivity(GDActionBar.Type actionBarType) {
super();
mActionBarType = actionBarType;
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
ensureLayout();
super.onRestoreInstanceState(savedInstanceState);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (mDefaultConstructorUsed) {
// HACK cyril: This should have been done is the default
// constructor. Unfortunately, the getApplication() method returns
// null there. Hence, this has to be done here.
if (getClass().equals(getGDApplication().getHomeActivityClass())) {
mActionBarType = Type.Dashboard;
}
}
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
ensureLayout();
}
public GDActionBar.Type getActionBarType() {
return mActionBarType;
}
public int createLayout() {
switch (mActionBarType) {
case Dashboard:
return R.layout.gd_content_dashboard;
case Empty:
return R.layout.gd_content_empty;
case Normal:
default:
return R.layout.gd_content_normal;
}
}
protected void ensureLayout() {
if (!verifyLayout()) {
setContentView(createLayout());
}
}
protected boolean verifyLayout() {
return mActionBarHost != null;
}
public GDApplication getGDApplication() {
return (GDApplication) getApplication();
}
@Override
public void onContentChanged() {
super.onContentChanged();
onPreContentChanged();
onPostContentChanged();
}
public void onPreContentChanged() {
mActionBarHost = (ActionBarHost) findViewById(R.id.gd_action_bar_host);
if (mActionBarHost == null) {
throw new RuntimeException(
"Your content must have an ActionBarHost whose id attribute is R.id.gd_action_bar_host");
}
mActionBarHost.getActionBar().setOnActionBarListener(mActionBarListener);
}
public void onPostContentChanged() {
boolean titleSet = false;
final Intent intent = getIntent();
if (intent != null) {
String title = intent.getStringExtra(ActionBarActivity.GD_ACTION_BAR_TITLE);
if (title != null) {
titleSet = true;
setTitle(title);
}
}
if (!titleSet) {
// No title has been set via the Intent. Let's look in the
// ActivityInfo
try {
final ActivityInfo activityInfo = getPackageManager().getActivityInfo(getComponentName(), 0);
if (activityInfo.labelRes != 0) {
setTitle(activityInfo.labelRes);
}
} catch (NameNotFoundException e) {
// Do nothing
}
}
final int visibility = intent.getIntExtra(ActionBarActivity.GD_ACTION_BAR_VISIBILITY, View.VISIBLE);
getGDActionBar().setVisibility(visibility);
}
@Override
public void setTitle(CharSequence title) {
getGDActionBar().setTitle(title);
}
@Override
public void setTitle(int titleId) {
setTitle(getString(titleId));
}
public GDActionBar getGDActionBar() {
ensureLayout();
return mActionBarHost.getActionBar();
}
public ActionBarItem addActionBarItem(ActionBarItem item) {
return getGDActionBar().addItem(item);
}
public ActionBarItem addActionBarItem(ActionBarItem item, int itemId) {
return getGDActionBar().addItem(item, itemId);
}
public ActionBarItem addActionBarItem(ActionBarItem.Type actionBarItemType) {
return getGDActionBar().addItem(actionBarItemType);
}
public ActionBarItem addActionBarItem(ActionBarItem.Type actionBarItemType, int itemId) {
return getGDActionBar().addItem(actionBarItemType, itemId);
}
public FrameLayout getContentView() {
ensureLayout();
return mActionBarHost.getContentView();
}
public void setActionBarContentView(int resID) {
LayoutInflater.from(this).inflate(resID, getContentView());
}
public void setActionBarContentView(View view, LayoutParams params) {
getContentView().addView(view, params);
}
public void setActionBarContentView(View view) {
getContentView().addView(view);
}
public boolean onHandleActionBarItemClick(ActionBarItem item, int position) {
return false;
}
private OnActionBarListener mActionBarListener = new OnActionBarListener() {
public void onActionBarItemClicked(int position) {
if (position == OnActionBarListener.HOME_ITEM) {
final GDApplication app = getGDApplication();
switch (mActionBarType) {
case Normal:
final Class<?> klass = app.getHomeActivityClass();
if (klass != null && !klass.equals(GDActivity.this.getClass())) {
if (Config.GD_INFO_LOGS_ENABLED) {
Log.i(LOG_TAG, "Going back to the home activity");
}
Intent homeIntent = new Intent(GDActivity.this, klass);
homeIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(homeIntent);
}
break;
case Dashboard:
final Intent appIntent = app.getMainApplicationIntent();
if (appIntent != null) {
if (Config.GD_INFO_LOGS_ENABLED) {
Log.i(LOG_TAG, "Launching the main application Intent");
}
startActivity(appIntent);
}
break;
}
} else {
if (!onHandleActionBarItemClick(getGDActionBar().getItem(position), position)) {
if (Config.GD_WARNING_LOGS_ENABLED) {
Log.w(LOG_TAG, "Click on item at position " + position + " dropped down to the floor");
}
}
}
}
};
}

@ -1,152 +0,0 @@
/*
* Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
*
* 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 greendroid.app;
import greendroid.image.ImageCache;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
import android.app.Activity;
import android.app.Application;
import android.content.Intent;
/**
* Defines various methods that should be overridden in order to style your
* application.
*
* @author Cyril Mottier
*/
public class GDApplication extends Application {
/**
* Used for receiving low memory system notification. You should definitely
* use it in order to clear caches and not important data everytime the
* system need memory.
*
* @author Cyril Mottier
* @see GDApplication#registerOnLowMemoryListener(OnLowMemoryListener)
* @see GDApplication#unregisterOnLowMemoryListener(OnLowMemoryListener)
*/
public static interface OnLowMemoryListener {
public void onLowMemoryReceived();
}
private static final int CORE_POOL_SIZE = 5;
private static final ThreadFactory sThreadFactory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1);
public Thread newThread(Runnable r) {
return new Thread(r, "GreenDroid thread #" + mCount.getAndIncrement());
}
};
private ExecutorService mExecutorService;
private ImageCache mImageCache;
private ArrayList<WeakReference<OnLowMemoryListener>> mLowMemoryListeners;
public GDApplication() {
mLowMemoryListeners = new ArrayList<WeakReference<OnLowMemoryListener>>();
}
public ExecutorService getExecutor() {
if (mExecutorService == null) {
mExecutorService = Executors.newFixedThreadPool(CORE_POOL_SIZE, sThreadFactory);
}
return mExecutorService;
}
public ImageCache getImageCache() {
if (mImageCache == null) {
mImageCache = new ImageCache(this);
}
return mImageCache;
}
/**
* Returns the class of the home {@link Activity}. The home {@link Activity}
* is the main entrance point of your application. This is usually where the
* dashboard/general menu is displayed.
*
* @return The Class of the home {@link Activity}
*/
public Class<?> getHomeActivityClass() {
return null;
}
/**
* Each application may have an "application intent" which will be used when
* the user clicked on the application button.
*
* @return The main application {@link Intent} (may be null if you don't
* want to use the main application {@link Intent} feature)
*/
public Intent getMainApplicationIntent() {
return null;
}
/**
* Adds a new listener to the list
*
* @param listener The listener to unregister
* @see {@link OnLowMemoryListener}
*/
public void registerOnLowMemoryListener(OnLowMemoryListener listener) {
if (listener != null) {
mLowMemoryListeners.add(new WeakReference<OnLowMemoryListener>(listener));
}
}
/**
* Removes a previously registered listener
*
* @param listener The listener to unregister
* @see {@link OnLowMemoryListener}
*/
public void unregisterOnLowMemoryListener(OnLowMemoryListener listener) {
if (listener != null) {
int i = 0;
while (i < mLowMemoryListeners.size()) {
final OnLowMemoryListener l = mLowMemoryListeners.get(i).get();
if (l == null || l == listener) {
mLowMemoryListeners.remove(i);
} else {
i++;
}
}
}
}
@Override
public void onLowMemory() {
super.onLowMemory();
int i = 0;
while (i < mLowMemoryListeners.size()) {
final OnLowMemoryListener listener = mLowMemoryListeners.get(i).get();
if (listener == null) {
mLowMemoryListeners.remove(i);
} else {
listener.onLowMemoryReceived();
i++;
}
}
}
}

@ -1,180 +0,0 @@
/*
* Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
*
* 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 greendroid.app;
import greendroid.util.Config;
import greendroid.widget.GDActionBar;
import android.app.ListActivity;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListAdapter;
import android.widget.ListView;
import com.cyrilmottier.android.greendroid.R;
/**
* An equivalent to {@link ListActivity} that manages a ListView.
*
* @see {@link ListActivity}
* @author Cyril Mottier
*/
public class GDListActivity extends GDActivity {
private static final String LOG_TAG = GDListActivity.class.getSimpleName();
private ListAdapter mAdapter;
private ListView mList;
private View mEmptyView;
private Handler mHandler = new Handler();
private boolean mFinishedStart = false;
private Runnable mRequestFocus = new Runnable() {
public void run() {
mList.focusableViewAvailable(mList);
}
};
public GDListActivity() {
super();
}
public GDListActivity(GDActionBar.Type actionBarType) {
super(actionBarType);
}
/**
* This method will be called when an item in the list is selected.
* Subclasses should override. Subclasses can call
* getListView().getItemAtPosition(position) if they need to access the data
* associated with the selected item.
*
* @param l The ListView where the click happened
* @param v The view that was clicked within the ListView
* @param position The position of the view in the list
* @param id The row id of the item that was clicked
*/
protected void onListItemClick(ListView l, View v, int position, long id) {
}
/**
* Provide the cursor for the list view.
*/
public void setListAdapter(ListAdapter adapter) {
synchronized (this) {
ensureLayout();
mAdapter = adapter;
mList.setAdapter(adapter);
}
}
/**
* Set the currently selected list item to the specified position with the
* adapter's data
*
* @param position
*/
public void setSelection(int position) {
mList.setSelection(position);
}
/**
* Get the position of the currently selected list item.
*/
public int getSelectedItemPosition() {
return mList.getSelectedItemPosition();
}
/**
* Get the cursor row ID of the currently selected list item.
*/
public long getSelectedItemId() {
return mList.getSelectedItemId();
}
/**
* Get the activity's list view widget.
*/
public ListView getListView() {
ensureLayout();
return mList;
}
/**
* Get the ListAdapter associated with this activity's ListView.
*/
public ListAdapter getListAdapter() {
return mAdapter;
}
@Override
public int createLayout() {
if (Config.GD_INFO_LOGS_ENABLED) {
Log.d(LOG_TAG, "No layout specified : creating the default layout");
}
switch (getActionBarType()) {
case Dashboard:
return R.layout.gd_list_content_dashboard;
case Empty:
return R.layout.gd_list_content_empty;
case Normal:
default:
return R.layout.gd_list_content_normal;
}
}
@Override
protected boolean verifyLayout() {
return super.verifyLayout() && mList != null;
}
@Override
public void onPreContentChanged() {
super.onPreContentChanged();
mEmptyView = findViewById(android.R.id.empty);
mList = (ListView) findViewById(android.R.id.list);
if (mList == null) {
throw new RuntimeException("Your content must have a ListView whose id attribute is "
+ "'android.R.id.list'");
}
}
@Override
public void onPostContentChanged() {
super.onPostContentChanged();
if (mEmptyView != null) {
mList.setEmptyView(mEmptyView);
}
mList.setOnItemClickListener(mOnClickListener);
if (mFinishedStart) {
setListAdapter(mAdapter);
}
mHandler.post(mRequestFocus);
mFinishedStart = true;
}
private AdapterView.OnItemClickListener mOnClickListener = new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
onListItemClick((ListView) parent, v, position, id);
}
};
}

@ -1,201 +0,0 @@
/*
* Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
*
* 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 greendroid.app;
import greendroid.util.Config;
import greendroid.widget.GDActionBar;
import greendroid.widget.GDActionBar.OnActionBarListener;
import greendroid.widget.ActionBarHost;
import greendroid.widget.ActionBarItem;
import android.app.TabActivity;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.TabHost;
import android.widget.TextView;
import com.cyrilmottier.android.greendroid.R;
/**
* An equivalent to a TabActivity that manages fancy tabs and an ActionBar
*
* @author Cyril Mottier
*/
public class GDTabActivity extends TabActivity implements ActionBarActivity {
private static final String LOG_TAG = GDTabActivity.class.getSimpleName();
private ActionBarHost mActionBarHost;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(createLayout());
}
public int createLayout() {
return R.layout.gd_tab_content;
}
public GDApplication getGDApplication() {
return (GDApplication) getApplication();
}
@Override
public void onContentChanged() {
super.onContentChanged();
onPreContentChanged();
onPostContentChanged();
}
public void onPreContentChanged() {
mActionBarHost = (ActionBarHost) findViewById(R.id.gd_action_bar_host);
if (mActionBarHost == null) {
throw new RuntimeException(
"Your content must have an ActionBarHost whose id attribute is R.id.gd_action_bar_host");
}
mActionBarHost.getActionBar().setOnActionBarListener(mActionBarListener);
}
public void onPostContentChanged() {
boolean titleSet = false;
final Intent intent = getIntent();
if (intent != null) {
String title = intent.getStringExtra(ActionBarActivity.GD_ACTION_BAR_TITLE);
if (title != null) {
titleSet = true;
setTitle(title);
}
}
if (!titleSet) {
// No title has been set via the Intent. Let's look in the
// ActivityInfo
try {
final ActivityInfo activityInfo = getPackageManager().getActivityInfo(getComponentName(), 0);
if (activityInfo.labelRes != 0) {
setTitle(activityInfo.labelRes);
}
} catch (NameNotFoundException e) {
// Do nothing
}
}
final int visibility = intent.getIntExtra(ActionBarActivity.GD_ACTION_BAR_VISIBILITY, View.VISIBLE);
getGDActionBar().setVisibility(visibility);
}
// @Override
// protected void onTitleChanged(CharSequence title, int color) {
// setTitle(title);
// }
@Override
public void setTitle(CharSequence title) {
getGDActionBar().setTitle(title);
}
@Override
public void setTitle(int titleId) {
setTitle(getString(titleId));
}
public GDActionBar getGDActionBar() {
return mActionBarHost.getActionBar();
}
public ActionBarItem addActionBarItem(ActionBarItem item) {
return getGDActionBar().addItem(item);
}
public ActionBarItem addActionBarItem(ActionBarItem item, int itemId) {
return getGDActionBar().addItem(item, itemId);
}
public ActionBarItem addActionBarItem(ActionBarItem.Type actionBarItemType) {
return getGDActionBar().addItem(actionBarItemType);
}
public ActionBarItem addActionBarItem(ActionBarItem.Type actionBarItemType, int itemId) {
return getGDActionBar().addItem(actionBarItemType, itemId);
}
public FrameLayout getContentView() {
return mActionBarHost.getContentView();
}
public boolean onHandleActionBarItemClick(ActionBarItem item, int position) {
return false;
}
private OnActionBarListener mActionBarListener = new OnActionBarListener() {
public void onActionBarItemClicked(int position) {
if (position == OnActionBarListener.HOME_ITEM) {
final Class<?> klass = getGDApplication().getHomeActivityClass();
if (klass != null && !klass.equals(GDTabActivity.class.getClass())) {
if (Config.GD_INFO_LOGS_ENABLED) {
Log.i(LOG_TAG, "Going back to the home activity");
}
Intent homeIntent = new Intent(GDTabActivity.this, klass);
homeIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(homeIntent);
}
} else {
if (!onHandleActionBarItemClick(getGDActionBar().getItem(position), position)) {
if (Config.GD_WARNING_LOGS_ENABLED) {
Log.w(LOG_TAG, "Click on item at position " + position + " dropped down to the floor");
}
}
}
}
};
/*
* GDTabActivity methods
*/
public void addTab(String tag, int labelId, Intent intent) {
addTab(tag, getString(labelId), intent);
}
public void addTab(String tag, CharSequence label, Intent intent) {
final TabHost host = getTabHost();
View indicator = createTabIndicator(label);
if (indicator == null) {
final TextView textIndicator = (TextView) getLayoutInflater().inflate(R.layout.gd_tab_indicator,
getTabWidget(), false);
textIndicator.setText(label);
indicator = textIndicator;
}
host.addTab(host.newTabSpec(tag).setIndicator(indicator).setContent(intent));
}
protected View createTabIndicator(CharSequence label) {
return null;
}
}

@ -1,72 +0,0 @@
/*
* Copyright (C) 2011 Cyril Mottier (http://www.cyrilmottier.com)
*
* 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 greendroid.graphics.drawable;
import greendroid.widget.GDActionBar;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.LightingColorFilter;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.StateListDrawable;
import android.util.StateSet;
/**
* A specialized {@link Drawable} that is dedicated to {@link ActionBarItem}s.
* It automatically adapts its color depending on its current state (black when
* pressed or focused and white otherwise). As a result, the
* {@link AutoColorDrawable} is a replacement {@link StateListDrawable} that
* should be used in {@link GDActionBar}s.
*
* @author Cyril Mottier
*/
public class ActionBarDrawable extends BitmapDrawable {
private ColorFilter mNormalCf;
private ColorFilter mAltCf;
public ActionBarDrawable(Resources res, int resId) {
this(res, res.getDrawable(resId), Color.WHITE, Color.BLACK);
}
public ActionBarDrawable(Resources res, Drawable d) {
this(res, d, Color.WHITE, Color.BLACK);
}
public ActionBarDrawable(Resources res, int resId, int normalColor, int altColor) {
this(res, res.getDrawable(resId), normalColor, altColor);
}
public ActionBarDrawable(Resources res, Drawable d, int normalColor, int altColor) {
super(res, (d instanceof BitmapDrawable) ? ((BitmapDrawable) d).getBitmap() : null);
mNormalCf = new LightingColorFilter(Color.BLACK, normalColor);
mAltCf = new LightingColorFilter(Color.BLACK, altColor);
}
@Override
public boolean isStateful() {
return true;
}
@Override
protected boolean onStateChange(int[] stateSet) {
final boolean useAlt = StateSet.stateSetMatches(DrawableStateSet.ENABLED_PRESSED_STATE_SET, stateSet)
|| StateSet.stateSetMatches(DrawableStateSet.ENABLED_FOCUSED_STATE_SET, stateSet);
setColorFilter(useAlt ? mAltCf : mNormalCf);
return true;
}
}

@ -1,30 +0,0 @@
/*
* Copyright (C) 2011 Cyril Mottier (http://www.cyrilmottier.com)
*
* 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 greendroid.graphics.drawable;
public class DrawableStateSet {
public static final int[] EMPTY_STATE_SET = {};
public static final int[] ENABLED_PRESSED_STATE_SET = {
android.R.attr.state_enabled, android.R.attr.state_pressed
};
public static final int[] ENABLED_FOCUSED_STATE_SET = {
android.R.attr.state_enabled, android.R.attr.state_focused
};
}

@ -1,65 +0,0 @@
/*
* Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
*
* 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 greendroid.image;
import greendroid.app.GDApplication.OnLowMemoryListener;
import greendroid.util.GDUtils;
import java.lang.ref.SoftReference;
import java.util.HashMap;
import android.content.Context;
import android.graphics.Bitmap;
public class ImageCache implements OnLowMemoryListener {
private final HashMap<String, SoftReference<Bitmap>> mSoftCache;
public ImageCache(Context context) {
mSoftCache = new HashMap<String, SoftReference<Bitmap>>();
GDUtils.getGDApplication(context).registerOnLowMemoryListener(this);
}
public static ImageCache from(Context context) {
return GDUtils.getImageCache(context);
}
public Bitmap get(String url) {
final SoftReference<Bitmap> ref = mSoftCache.get(url);
if (ref == null) {
return null;
}
final Bitmap bitmap = ref.get();
if (bitmap == null) {
mSoftCache.remove(url);
}
return bitmap;
}
public void put(String url, Bitmap bitmap) {
mSoftCache.put(url, new SoftReference<Bitmap>(bitmap));
}
public void flush() {
mSoftCache.clear();
}
public void onLowMemoryReceived() {
flush();
}
}

@ -1,201 +0,0 @@
/*
* Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
*
* 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 greendroid.image;
import greendroid.util.Config;
import greendroid.util.GDUtils;
import java.net.URL;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.Message;
import android.os.Process;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
/**
* An ImageLoader asynchronously loads image from a given url. Client may be
* notified from the current image loading state using the
* {@link ImageLoaderCallback}.
* <p>
* <em><strong>Note: </strong>You normally don't need to use the {@link ImageLoader}
* class directly in your application. You'll generally prefer using an
* {@link ImageRequest} that takes care of the entire loading process.</em>
* </p>
*
* @author Cyril Mottier
*/
public class ImageLoader {
private static final String LOG_TAG = ImageLoader.class.getSimpleName();
public static interface ImageLoaderCallback {
void onImageLoadingStarted(ImageLoader loader);
void onImageLoadingEnded(ImageLoader loader, Bitmap bitmap);
void onImageLoadingFailed(ImageLoader loader, Throwable exception);
}
private static final int ON_START = 0x100;
private static final int ON_FAIL = 0x101;
private static final int ON_END = 0x102;
private static ImageCache sImageCache;
private static ExecutorService sExecutor;
private static BitmapFactory.Options sDefaultOptions;
public ImageLoader(Context context) {
if (sImageCache == null) {
sImageCache = GDUtils.getImageCache(context);
}
if (sExecutor == null) {
sExecutor = GDUtils.getExecutor(context);
}
if (sDefaultOptions == null) {
sDefaultOptions = new BitmapFactory.Options();
sDefaultOptions.inDither = true;
sDefaultOptions.inScaled = true;
sDefaultOptions.inDensity = DisplayMetrics.DENSITY_MEDIUM;
sDefaultOptions.inTargetDensity = context.getResources().getDisplayMetrics().densityDpi;
}
}
public Future<?> loadImage(String url, ImageLoaderCallback callback) {
return loadImage(url, callback, null);
}
public Future<?> loadImage(String url, ImageLoaderCallback callback, ImageProcessor bitmapProcessor) {
return loadImage(url, callback, bitmapProcessor, null);
}
public Future<?> loadImage(String url, ImageLoaderCallback callback, ImageProcessor bitmapProcessor, BitmapFactory.Options options) {
return sExecutor.submit(new ImageFetcher(url, callback, bitmapProcessor, options));
}
private class ImageFetcher implements Runnable {
private String mUrl;
private ImageHandler mHandler;
private ImageProcessor mBitmapProcessor;
private BitmapFactory.Options mOptions;
public ImageFetcher(String url, ImageLoaderCallback callback, ImageProcessor bitmapProcessor, BitmapFactory.Options options) {
mUrl = url;
mHandler = new ImageHandler(url, callback);
mBitmapProcessor = bitmapProcessor;
mOptions = options;
}
public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
final Handler h = mHandler;
Bitmap bitmap = null;
Throwable throwable = null;
h.sendMessage(Message.obtain(h, ON_START));
try {
if (TextUtils.isEmpty(mUrl)) {
throw new Exception("The given URL cannot be null or empty");
}
// TODO Cyril: Use a AndroidHttpClient?
bitmap = BitmapFactory.decodeStream(new URL(mUrl).openStream(), null, (mOptions == null) ? sDefaultOptions : mOptions);
if (mBitmapProcessor != null && bitmap != null) {
final Bitmap processedBitmap = mBitmapProcessor.processImage(bitmap);
if (processedBitmap != null) {
bitmap = processedBitmap;
}
}
} catch (Exception e) {
// An error occured while retrieving the image
if (Config.GD_ERROR_LOGS_ENABLED) {
Log.e(LOG_TAG, "Error while fetching image", e);
}
throwable = e;
}
if (bitmap == null) {
if (throwable == null) {
// Skia returned a null bitmap ... that's usually because
// the given url wasn't pointing to a valid image
throwable = new Exception("Skia image decoding failed");
}
h.sendMessage(Message.obtain(h, ON_FAIL, throwable));
} else {
h.sendMessage(Message.obtain(h, ON_END, bitmap));
}
}
}
private class ImageHandler extends Handler {
private String mUrl;
private ImageLoaderCallback mCallback;
private ImageHandler(String url, ImageLoaderCallback callback) {
mUrl = url;
mCallback = callback;
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case ON_START:
if (mCallback != null) {
mCallback.onImageLoadingStarted(ImageLoader.this);
}
break;
case ON_FAIL:
if (mCallback != null) {
mCallback.onImageLoadingFailed(ImageLoader.this, (Throwable) msg.obj);
}
break;
case ON_END:
final Bitmap bitmap = (Bitmap) msg.obj;
sImageCache.put(mUrl, bitmap);
if (mCallback != null) {
mCallback.onImageLoadingEnded(ImageLoader.this, bitmap);
}
break;
default:
super.handleMessage(msg);
break;
}
};
}
}

@ -1,40 +0,0 @@
/*
* Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
*
* 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 greendroid.image;
import android.graphics.Bitmap;
/**
* An interface specifying a way to process an image prior storing it in the
* application-wide cache. A great way to use this interface is to prepare a
* Bitmap (resizing, adding rounded corners, changing the tint color, etc.) for
* faster drawing.
*
* @author Cyril Mottier
*/
public interface ImageProcessor {
/**
* Called whenever the bitmap need to be processed. The returned may have
* been modified or completely different.
*
* @param bitmap
* The Bitmap to process
* @return A Bitmap that has been modified
*/
Bitmap processImage(Bitmap bitmap);
}

@ -1,130 +0,0 @@
/*
* Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
*
* 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 greendroid.image;
import greendroid.image.ImageLoader.ImageLoaderCallback;
import java.util.concurrent.Future;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
/**
* An {@link ImageRequest} may be used to request an image from the network. The
* process of requesting for an image is done in three steps:
* <ul>
* <li>Instantiate a new {@link ImageRequest}</li>
* <li>Call {@link #load(Context)} to start loading the image</li>
* <li>Listen to loading state changes using a {@link ImageRequestCallback}</li>
* </ul>
*
* @author Cyril Mottier
*/
public class ImageRequest {
/**
* @author Cyril Mottier
*/
public static interface ImageRequestCallback {
void onImageRequestStarted(ImageRequest request);
void onImageRequestFailed(ImageRequest request, Throwable throwable);
void onImageRequestEnded(ImageRequest request, Bitmap image);
void onImageRequestCancelled(ImageRequest request);
}
private static ImageLoader sImageLoader;
private Future<?> mFuture;
private String mUrl;
private ImageRequestCallback mCallback;
private ImageProcessor mBitmapProcessor;
private BitmapFactory.Options mOptions;
public ImageRequest(String url, ImageRequestCallback callback) {
this(url, callback, null);
}
public ImageRequest(String url, ImageRequestCallback callback, ImageProcessor bitmapProcessor) {
this(url, callback, bitmapProcessor, null);
}
public ImageRequest(String url, ImageRequestCallback callback, ImageProcessor bitmapProcessor, BitmapFactory.Options options) {
mUrl = url;
mCallback = callback;
mBitmapProcessor = bitmapProcessor;
mOptions = options;
}
public void setImageRequestCallback(ImageRequestCallback callback) {
mCallback = callback;
}
public String getUrl() {
return mUrl;
}
public void load(Context context) {
if (mFuture == null) {
if (sImageLoader == null) {
sImageLoader = new ImageLoader(context);
}
mFuture = sImageLoader.loadImage(mUrl, new InnerCallback(), mBitmapProcessor, mOptions);
}
}
public void cancel() {
if (!isCancelled()) {
// Here we do not want to force the task to be interrupted. Indeed,
// it may be useful to keep the result in a cache for a further use
mFuture.cancel(false);
if (mCallback != null) {
mCallback.onImageRequestCancelled(this);
}
}
}
public final boolean isCancelled() {
return mFuture.isCancelled();
}
private class InnerCallback implements ImageLoaderCallback {
public void onImageLoadingStarted(ImageLoader loader) {
if (mCallback != null) {
mCallback.onImageRequestStarted(ImageRequest.this);
}
}
public void onImageLoadingEnded(ImageLoader loader, Bitmap bitmap) {
if (mCallback != null && !isCancelled()) {
mCallback.onImageRequestEnded(ImageRequest.this, bitmap);
}
mFuture = null;
}
public void onImageLoadingFailed(ImageLoader loader, Throwable exception) {
if (mCallback != null && !isCancelled()) {
mCallback.onImageRequestFailed(ImageRequest.this, exception);
}
mFuture = null;
}
}
}

@ -1,40 +0,0 @@
/*
* Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
*
* 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 greendroid.util;
@SuppressWarnings("all")
public class Config {
private Config() {
}
private static final int GD_LOG_LEVEL_INFO = 3;
private static final int GD_LOG_LEVEL_WARNING = 2;
private static final int GD_LOG_LEVEL_ERROR = 1;
private static final int GD_LOG_LEVEL_NONE = 0;
/**
* Set this flag to {@link Config#GD_LOG_LEVEL_NONE} when releasing your
* application in order to remove all logs generated by GreenDroid.
*/
private static final int GD_LOG_LEVEL = GD_LOG_LEVEL_NONE;
public static final boolean GD_INFO_LOGS_ENABLED = (GD_LOG_LEVEL == GD_LOG_LEVEL_INFO);
public static final boolean GD_WARNING_LOGS_ENABLED = GD_INFO_LOGS_ENABLED
|| (GD_LOG_LEVEL == GD_LOG_LEVEL_WARNING);
public static final boolean GD_ERROR_LOGS_ENABLED = GD_WARNING_LOGS_ENABLED || (GD_LOG_LEVEL == GD_LOG_LEVEL_ERROR);
}

@ -1,65 +0,0 @@
/*
* Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
*
* 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 greendroid.util;
import greendroid.app.GDApplication;
import greendroid.image.ImageCache;
import java.util.concurrent.ExecutorService;
import android.content.Context;
/**
* Class that provides several utility methods related to GreenDroid.
*
* @author Cyril Mottier
*/
public class GDUtils {
private GDUtils() {
}
/**
* Return the current {@link GDApplication}
*
* @param context The calling context
* @return The {@link GDApplication} the given context is linked to.
*/
public static GDApplication getGDApplication(Context context) {
return (GDApplication) context.getApplicationContext();
}
/**
* Return the {@link GDApplication} image cache
*
* @param context The calling context
* @return The image cache of the current {@link GDApplication}
*/
public static ImageCache getImageCache(Context context) {
return getGDApplication(context).getImageCache();
}
/**
* Return the {@link GDApplication} executors pool.
*
* @param context The calling context
* @return The executors pool of the current {@link GDApplication}
*/
public static ExecutorService getExecutor(Context context) {
return getGDApplication(context).getExecutor();
}
}

@ -1,38 +0,0 @@
package greendroid.util;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class Md5Util {
private static MessageDigest sMd5MessageDigest;
private static StringBuilder sStringBuilder;
static {
try {
sMd5MessageDigest = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
// TODO cyril: I'm quite sure about my "MD5" algorithm
// but this is not a correct way to handle an exception ...
}
sStringBuilder = new StringBuilder();
}
private Md5Util() {
}
public static String md5(String s) {
sMd5MessageDigest.reset();
sMd5MessageDigest.update(s.getBytes());
byte digest[] = sMd5MessageDigest.digest();
sStringBuilder.setLength(0);
for (int i=0; i<digest.length; i++) {
sStringBuilder.append(Integer.toHexString(0xFF & digest[i]));
}
return sStringBuilder.toString();
}
}

@ -1,35 +0,0 @@
package greendroid.util;
/**
* Utility class containing several useful constants related to time.
*
* @author Cyril Mottier
*/
public class Time {
/**
* The number of milliseconds in a second.
*/
public static final int GD_SECOND = 1000;
/**
* The number of milliseconds in a minute.
*/
public static final int GD_MINUTE = GD_SECOND * 60;
/**
* The number of milliseconds in an hour.
*/
public static final int GD_HOUR = GD_MINUTE * 60;
/**
* The number of milliseconds in a day.
*/
public static final int GD_DAY = GD_HOUR * 24;
/**
* The number of milliseconds in a week.
*/
public static final int GD_WEEK = GD_DAY * 7;
}

@ -1,62 +0,0 @@
/*
* Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
*
* 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 greendroid.widget;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import com.cyrilmottier.android.greendroid.R;
public class ActionBarHost extends LinearLayout {
private GDActionBar mActionBar;
private FrameLayout mContentView;
public ActionBarHost(Context context) {
this(context, null);
}
public ActionBarHost(Context context, AttributeSet attrs) {
super(context, attrs);
setOrientation(LinearLayout.VERTICAL);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mActionBar = (GDActionBar) findViewById(R.id.gd_action_bar);
if (mActionBar == null || !(mActionBar instanceof GDActionBar)) {
throw new IllegalArgumentException("No ActionBar with the id R.id.gd_action_bar found in the layout.");
}
mContentView = (FrameLayout) findViewById(R.id.gd_action_bar_content_view);
if (mContentView == null || !(mContentView instanceof FrameLayout)) {
throw new IllegalArgumentException("No FrameLayout with the id R.id.gd_action_bar_content_view found in the layout.");
}
}
public GDActionBar getActionBar() {
return mActionBar;
}
public FrameLayout getContentView() {
return mContentView;
}
}

@ -1,297 +0,0 @@
/*
* Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
*
* 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 greendroid.widget;
import greendroid.graphics.drawable.ActionBarDrawable;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.view.View;
import com.cyrilmottier.android.greendroid.R;
/**
* Base class representing an {@link ActionBarItem} used in {@link GDActionBar}s.
* The base implementation exposes a single Drawable as well as a content
* description.
*
* @author Cyril Mottier
*/
public abstract class ActionBarItem {
public enum Type {
GoHome, // A house
Search, // A magnifying glass
Talk, // A speech bubble
Compose, // A sheet of paper with a pen
Export, // A dot with an arrow
Share, // A dot with two arrows
Refresh, // Two curved arrows
TakePhoto, // A camera
// PickPhoto, // Two pictures with an arrow
Locate, // The traditional GMaps pin
Edit, // A pencil
Add, // A plus sign
Star, // A star
SortBySize, // Some bars
LocateMyself, // A surrounded dot
Compass,
Help,
Info,
Settings,
List,
Trashcan,
Eye,
AllFriends,
Group,
Gallery,
Slideshow,
Mail
}
protected Drawable mDrawable;
protected CharSequence mContentDescription;
protected View mItemView;
protected Context mContext;
protected GDActionBar mActionBar;
private int mItemId;
void setActionBar(GDActionBar actionBar) {
mContext = actionBar.getContext();
mActionBar = actionBar;
}
public Drawable getDrawable() {
return mDrawable;
}
public ActionBarItem setDrawable(int drawableId) {
return setDrawable(mContext.getResources().getDrawable(drawableId));
}
public ActionBarItem setDrawable(Drawable drawable) {
if (drawable != mDrawable) {
mDrawable = drawable;
if (mItemView != null) {
onDrawableChanged();
}
}
return this;
}
public CharSequence getContentDescription() {
return mContentDescription;
}
public ActionBarItem setContentDescription(int contentDescriptionId) {
return setContentDescription(mContext.getString(contentDescriptionId));
}
public ActionBarItem setContentDescription(CharSequence contentDescription) {
if (contentDescription != mContentDescription) {
mContentDescription = contentDescription;
if (mItemView != null) {
onContentDescriptionChanged();
}
}
return this;
}
public View getItemView() {
if (mItemView == null) {
mItemView = createItemView();
prepareItemView();
}
return mItemView;
}
protected abstract View createItemView();
protected void prepareItemView() {
}
protected void onDrawableChanged() {
}
protected void onContentDescriptionChanged() {
}
protected void onItemClicked() {
}
void setItemId(int itemId) {
mItemId = itemId;
}
public int getItemId() {
return mItemId;
}
static ActionBarItem createWithType(GDActionBar actionBar, ActionBarItem.Type type) {
int drawableId = 0;
int descriptionId = 0;
switch (type) {
case GoHome:
drawableId = R.drawable.gd_action_bar_home;
descriptionId = R.string.gd_go_home;
break;
case Search:
drawableId = R.drawable.gd_action_bar_search;
descriptionId = R.string.gd_search;
break;
case Talk:
drawableId = R.drawable.gd_action_bar_talk;
descriptionId = R.string.gd_talk;
break;
case Compose:
drawableId = R.drawable.gd_action_bar_compose;
descriptionId = R.string.gd_compose;
break;
case Export:
drawableId = R.drawable.gd_action_bar_export;
descriptionId = R.string.gd_export;
break;
case Share:
drawableId = R.drawable.gd_action_bar_share;
descriptionId = R.string.gd_share;
break;
case Refresh:
return actionBar.newActionBarItem(LoaderActionBarItem.class)
.setDrawable(new ActionBarDrawable(actionBar.getResources(), R.drawable.gd_action_bar_refresh))
.setContentDescription(R.string.gd_refresh);
case TakePhoto:
drawableId = R.drawable.gd_action_bar_take_photo;
descriptionId = R.string.gd_take_photo;
break;
//
// case PickPhoto:
// drawableId = R.drawable.gd_action_bar_pick_photo;
// descriptionId = R.string.gd_pick_photo;
// break;
case Locate:
drawableId = R.drawable.gd_action_bar_locate;
descriptionId = R.string.gd_locate;
break;
case Edit:
drawableId = R.drawable.gd_action_bar_edit;
descriptionId = R.string.gd_edit;
break;
case Add:
drawableId = R.drawable.gd_action_bar_add;
descriptionId = R.string.gd_add;
break;
case Star:
drawableId = R.drawable.gd_action_bar_star;
descriptionId = R.string.gd_star;
break;
case SortBySize:
drawableId = R.drawable.gd_action_bar_sort_by_size;
descriptionId = R.string.gd_sort_by_size;
break;
case LocateMyself:
drawableId = R.drawable.gd_action_bar_locate_myself;
descriptionId = R.string.gd_locate_myself;
break;
case Compass:
drawableId = R.drawable.gd_action_bar_compass;
descriptionId = R.string.gd_compass;
break;
case Help:
drawableId = R.drawable.gd_action_bar_help;
descriptionId = R.string.gd_help;
break;
case Info:
drawableId = R.drawable.gd_action_bar_info;
descriptionId = R.string.gd_info;
break;
case Settings:
drawableId = R.drawable.gd_action_bar_settings;
descriptionId = R.string.gd_settings;
break;
case List:
drawableId = R.drawable.gd_action_bar_list;
descriptionId = R.string.gd_list;
break;
case Trashcan:
drawableId = R.drawable.gd_action_bar_trashcan;
descriptionId = R.string.gd_trashcan;
break;
case Eye:
drawableId = R.drawable.gd_action_bar_eye;
descriptionId = R.string.gd_eye;
break;
case AllFriends:
drawableId = R.drawable.gd_action_bar_all_friends;
descriptionId = R.string.gd_all_friends;
break;
case Group:
drawableId = R.drawable.gd_action_bar_group;
descriptionId = R.string.gd_group;
break;
case Gallery:
drawableId = R.drawable.gd_action_bar_gallery;
descriptionId = R.string.gd_gallery;
break;
case Slideshow:
drawableId = R.drawable.gd_action_bar_slideshow;
descriptionId = R.string.gd_slideshow;
break;
case Mail:
drawableId = R.drawable.gd_action_bar_mail;
descriptionId = R.string.gd_mail;
break;
default:
// Do nothing but return null
return null;
}
final Drawable d = new ActionBarDrawable(actionBar.getResources(), drawableId);
return actionBar.newActionBarItem(NormalActionBarItem.class).setDrawable(d)
.setContentDescription(descriptionId);
}
}

@ -1,466 +0,0 @@
/*
* Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
*
* 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 greendroid.widget;
import greendroid.image.ImageProcessor;
import greendroid.image.ImageRequest;
import greendroid.image.ImageRequest.ImageRequestCallback;
import greendroid.util.Config;
import greendroid.util.GDUtils;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.ImageView;
import android.widget.ListView;
import com.cyrilmottier.android.greendroid.R;
/**
* <p>
* A {@link AsyncImageView} is a network-aware {@link ImageView}. It may display
* images from the web according to a URL. {@link AsyncImageView} takes care of
* loading asynchronously images on the Internet. It also caches images in an
* application-wide cache to prevent loading images several times.
* </p>
* <p>
* Clients may listen the {@link OnImageViewLoadListener} to be notified of the
* current image loading state.
* </p>
* <p>
* {@link AsyncImageView} may be extremely useful in {@link ListView}'s row. To
* prevent your {@link AsyncImageView} from downloading while scrolling or
* flinging it is a good idea to pause it using {@link #setPaused(boolean)}
* method. Once the scrolling/flinging is over, <em>un-pause</em> your
* {@link AsyncImageView}s using <code>setPaused(false)</code>
* </p>
*
* @author Cyril Mottier
*/
public class AsyncImageView extends ImageView implements ImageRequestCallback {
private static final String LOG_TAG = AsyncImageView.class.getSimpleName();
/**
* Clients may listen to {@link AsyncImageView} changes using a
* {@link OnImageViewLoadListener}.
*
* @author Cyril Mottier
*/
public static interface OnImageViewLoadListener {
/**
* Called when the image started to load
*
* @param imageView
* The AsyncImageView that started loading
*/
void onLoadingStarted(AsyncImageView imageView);
/**
* Called when the image ended to load that is when the image has been
* downloaded and is ready to be displayed on screen
*
* @param imageView
* The AsyncImageView that ended loading
*/
void onLoadingEnded(AsyncImageView imageView, Bitmap image);
/**
* Called when the image loading failed
*
* @param imageView
* The AsyncImageView that failed to load
*/
void onLoadingFailed(AsyncImageView imageView, Throwable throwable);
}
private static final int IMAGE_SOURCE_UNKNOWN = -1;
private static final int IMAGE_SOURCE_RESOURCE = 0;
private static final int IMAGE_SOURCE_DRAWABLE = 1;
private static final int IMAGE_SOURCE_BITMAP = 2;
private int mImageSource;
private Bitmap mDefaultBitmap;
private Drawable mDefaultDrawable;
private int mDefaultResId;
private String mUrl;
private ImageRequest mRequest;
private boolean mPaused;
private Bitmap mBitmap;
private OnImageViewLoadListener mOnImageViewLoadListener;
private ImageProcessor mImageProcessor;
private BitmapFactory.Options mOptions;
public AsyncImageView(Context context) {
this(context, null);
}
public AsyncImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public AsyncImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initializeDefaultValues();
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.AsyncImageView);
setUrl(a.getString(R.styleable.AsyncImageView_url));
Drawable d = a.getDrawable(R.styleable.AsyncImageView_defaultSrc);
if (d != null) {
setDefaultImageDrawable(d);
}
final int inDensity = a.getInt(R.styleable.AsyncImageView_inDensity, -1);
if (inDensity != -1) {
setInDensity(inDensity);
}
a.recycle();
}
private void initializeDefaultValues() {
mImageSource = IMAGE_SOURCE_UNKNOWN;
mPaused = false;
}
/**
* Return true if this AsyncImageView is currently loading an image.
*
* @return true if this AsyncImageView is currently loading an image.
* Otherwise it returns false.
*/
public boolean isLoading() {
return mRequest != null;
}
/**
* Return true if the displayed image has been correctly loaded.
*
* @return true if this AsyncImageView succeed to load the image at the
* given url.
*/
public boolean isLoaded() {
return mRequest == null && mBitmap != null;
}
/**
* Pause this AsyncImageView preventing it from downloading the image. The
* download process will start back once setPaused(false) is called.
*
* @param paused
*/
public void setPaused(boolean paused) {
if (mPaused != paused) {
mPaused = paused;
if (!paused) {
reload();
}
}
}
/**
* Helper to {@link #setBitmapFactoryOptions(Options)} that simply
* sets the inDensity for loaded image.
*
* @param inDensity
* @see AsyncImageView#setBitmapFactoryOptions(Options)
*/
public void setInDensity(int inDensity) {
if (mOptions == null) {
mOptions = new BitmapFactory.Options();
mOptions.inDither = true;
mOptions.inScaled = true;
mOptions.inTargetDensity = getContext().getResources().getDisplayMetrics().densityDpi;
}
mOptions.inDensity = inDensity;
}
/**
* Assign a {@link Options} object to this {@link AsyncImageView}. Those
* options are used internally by the {@link AsyncImageView} when decoding
* the image. This may be used to prevent the default behavior that loads
* all images as mdpi density.
*
* @param options
*/
public void setOptions(BitmapFactory.Options options) {
mOptions = options;
}
/**
* Reload the image pointed by the given URL
*/
public void reload() {
reload(false);
}
/**
* Reload the image pointed by the given URL. You may want to force
* reloading by setting the force parameter to true.
*
* @param force
* if true the AsyncImageView won't look into the
* application-wide cache.
*/
public void reload(boolean force) {
if (mRequest == null && mUrl != null) {
// Prior downloading the image ... let's look in a cache !
// TODO cyril: This is a synchronous call ... make it asynchronous
mBitmap = null;
if (!force) {
mBitmap = GDUtils.getImageCache(getContext()).get(mUrl);
}
if (mBitmap != null) {
setImageBitmap(mBitmap);
return;
}
if (Config.GD_INFO_LOGS_ENABLED) {
Log.i(LOG_TAG,
"Cache miss. Starting to load the image at the given URL");
}
setDefaultImage();
mRequest = new ImageRequest(mUrl, this, mImageProcessor, mOptions);
mRequest.load(getContext());
}
}
/**
* Force the loading to be stopped.
*/
public void stopLoading() {
if (mRequest != null) {
mRequest.cancel();
mRequest = null;
}
}
/**
* Register a callback to be invoked when an event occured for this
* AsyncImageView.
*
* @param listener
* The listener that will be notified
*/
public void setOnImageViewLoadListener(OnImageViewLoadListener listener) {
mOnImageViewLoadListener = listener;
}
/**
* Set the url of the image that will be used as the content of this
* AsyncImageView. The given may be null in order to display the default
* image. Please note the url may be a local url. For instance, you can
* asynchronously load images from the disk memory is the url scheme is
* <code>file://</code>
*
* @param url
* The url of the image to set. Pass null to force the
* AsyncImageView to display the default image
*/
public void setUrl(String url) {
// Check the url has changed
if (mBitmap != null && url != null && url.equals(mUrl)) {
return;
}
stopLoading();
mUrl = url;
// Setting the url to an empty string force the displayed image to the
// default image
if (TextUtils.isEmpty(mUrl)) {
mBitmap = null;
setDefaultImage();
} else {
if (!mPaused) {
reload();
} else {
// We're paused: let's look in a synchronous and efficient cache
// prior using the default image.
mBitmap = GDUtils.getImageCache(getContext()).get(mUrl);
if (mBitmap != null) {
setImageBitmap(mBitmap);
return;
} else {
setDefaultImage();
}
}
}
}
/**
* Set the default bitmap as the content of this AsyncImageView
*
* @param bitmap
* The bitmap to set
*/
public void setDefaultImageBitmap(Bitmap bitmap) {
mImageSource = IMAGE_SOURCE_BITMAP;
mDefaultBitmap = bitmap;
setDefaultImage();
}
/**
* Set the default drawable as the content of this AsyncImageView
*
* @param drawable
* The drawable to set
*/
public void setDefaultImageDrawable(Drawable drawable) {
mImageSource = IMAGE_SOURCE_DRAWABLE;
mDefaultDrawable = drawable;
setDefaultImage();
}
/**
* Set the default resource as the content of this AsyncImageView
*
* @param resId
* The resource identifier to set
*/
public void setDefaultImageResource(int resId) {
mImageSource = IMAGE_SOURCE_RESOURCE;
mDefaultResId = resId;
setDefaultImage();
}
/**
* Set an image processor to this AsyncImageView. An ImageProcessor may be
* used in order to work on the retrieved Bitmap prior displaying it on
* screen.
*
* @param imageProcessor
* The {@link ImageProcessor} to set
* @see ImageProcessor
*/
public void setImageProcessor(ImageProcessor imageProcessor) {
mImageProcessor = imageProcessor;
}
private void setDefaultImage() {
if (mBitmap == null) {
switch (mImageSource) {
case IMAGE_SOURCE_BITMAP:
setImageBitmap(mDefaultBitmap);
break;
case IMAGE_SOURCE_DRAWABLE:
setImageDrawable(mDefaultDrawable);
break;
case IMAGE_SOURCE_RESOURCE:
setImageResource(mDefaultResId);
break;
default:
setImageDrawable(null);
break;
}
}
}
static class SavedState extends BaseSavedState {
String url;
SavedState(Parcelable superState) {
super(superState);
}
private SavedState(Parcel in) {
super(in);
url = in.readString();
}
@Override
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);
out.writeString(url);
}
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.url = mUrl;
return ss;
}
@Override
public void onRestoreInstanceState(Parcelable state) {
SavedState ss = (SavedState) state;
super.onRestoreInstanceState(ss.getSuperState());
setUrl(ss.url);
}
public void onImageRequestStarted(ImageRequest request) {
if (mOnImageViewLoadListener != null) {
mOnImageViewLoadListener.onLoadingStarted(this);
}
}
public void onImageRequestFailed(ImageRequest request, Throwable throwable) {
mRequest = null;
if (mOnImageViewLoadListener != null) {
mOnImageViewLoadListener.onLoadingFailed(this, throwable);
}
}
public void onImageRequestEnded(ImageRequest request, Bitmap image) {
mBitmap = image;
setImageBitmap(image);
if (mOnImageViewLoadListener != null) {
mOnImageViewLoadListener.onLoadingEnded(this, image);
}
mRequest = null;
}
public void onImageRequestCancelled(ImageRequest request) {
mRequest = null;
if (mOnImageViewLoadListener != null) {
mOnImageViewLoadListener.onLoadingFailed(this, null);
}
}
}

@ -1,309 +0,0 @@
/*
* Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
*
* 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 greendroid.widget;
import greendroid.graphics.drawable.ActionBarDrawable;
import java.util.LinkedList;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.cyrilmottier.android.greendroid.R;
public class GDActionBar extends LinearLayout {
public static final int NONE = 0;
private static final int MAX_ITEMS_COUNT = 3;
public enum Type {
Normal, Dashboard, Empty
}
public interface OnActionBarListener {
int HOME_ITEM = -1;
/**
* Clients may listen to this method in order to be notified the user
* has clicked on an item.
*
* @param position The position of the item in the action bar. -1 means
* the user pressed the "Home" button. 0 means the user
* clicked the first action bar item (the leftmost item) and
* so on.
*/
void onActionBarItemClicked(int position);
}
private TextView mTitleView;
private ImageButton mHomeButton;
private boolean mMerging = false;
private CharSequence mTitle;
private GDActionBar.Type mType;
private OnActionBarListener mOnActionBarListener;
private LinkedList<ActionBarItem> mItems;
private Drawable mDividerDrawable;
private Drawable mHomeDrawable;
private int mDividerWidth;
public GDActionBar(Context context) {
this(context, null);
}
public GDActionBar(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.gdActionBarStyle);
}
public GDActionBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs);
initActionBar();
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ActionBar, defStyle, 0);
mTitle = a.getString(R.styleable.ActionBar_gdtitle);
mDividerDrawable = a.getDrawable(R.styleable.ActionBar_dividerDrawable);
mDividerWidth = a.getDimensionPixelSize(R.styleable.ActionBar_dividerWidth, -1);
mHomeDrawable = a.getDrawable(R.styleable.ActionBar_homeDrawable);
if (mHomeDrawable == null) {
mHomeDrawable = new ActionBarDrawable(getResources(), R.drawable.gd_action_bar_home);
}
int layoutID;
int type = a.getInteger(R.styleable.ActionBar_type, -1);
switch (type) {
case 2:
mType = Type.Empty;
layoutID = R.layout.gd_action_bar_empty;
break;
case 1:
mType = Type.Dashboard;
layoutID = R.layout.gd_action_bar_dashboard;
break;
case 0:
default:
mType = Type.Normal;
layoutID = R.layout.gd_action_bar_normal;
break;
}
// HACK Cyril: Without this, the onFinishInflate is called twice !?!
// This issue is due to a bug when Android inflates a layout with a
// parent - which is compulsory with a <merge /> tag. I've reported this
// bug to Romain Guy who fixed it (patch will probably be available in
// the Gingerbread release).
mMerging = true;
LayoutInflater.from(context).inflate(layoutID, this);
mMerging = false;
a.recycle();
}
private void initActionBar() {
mItems = new LinkedList<ActionBarItem>();
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
if (!mMerging) {
switch (mType) {
case Dashboard:
mHomeButton = (ImageButton) findViewById(R.id.gd_action_bar_home_item);
mHomeButton.setOnClickListener(mClickHandler);
break;
case Empty:
mTitleView = (TextView) findViewById(R.id.gd_action_bar_title);
setTitle(mTitle);
break;
case Normal:
default:
mHomeButton = (ImageButton) findViewById(R.id.gd_action_bar_home_item);
mHomeButton.setOnClickListener(mClickHandler);
mHomeButton.setImageDrawable(mHomeDrawable);
mHomeButton.setContentDescription(getContext().getString(R.string.gd_go_home));
mTitleView = (TextView) findViewById(R.id.gd_action_bar_title);
setTitle(mTitle);
break;
}
}
}
public void setOnActionBarListener(OnActionBarListener listener) {
mOnActionBarListener = listener;
}
public void setTitle(CharSequence title) {
mTitle = title;
if (mTitleView != null) {
mTitleView.setText(title);
}
}
public ActionBarItem addItem(ActionBarItem.Type actionBarItemType) {
return addItem(ActionBarItem.createWithType(this, actionBarItemType), NONE);
}
public ActionBarItem addItem(ActionBarItem.Type actionBarItemType, int itemId) {
return addItem(ActionBarItem.createWithType(this, actionBarItemType), itemId);
}
public ActionBarItem addItem(ActionBarItem item) {
return addItem(item, NONE);
}
public ActionBarItem addItem(ActionBarItem item, int itemId) {
if (mItems.size() >= MAX_ITEMS_COUNT) {
/*
* An ActionBar must contain as few items as possible. So let's keep
* a limit :)
*/
return null;
}
if (item != null) {
item.setItemId(itemId);
if (mDividerDrawable != null) {
ImageView divider = new ImageView(getContext());
int dividerWidth = (mDividerWidth > 0) ? mDividerWidth : mDividerDrawable.getIntrinsicWidth();
final LinearLayout.LayoutParams lp = new LayoutParams(dividerWidth, LayoutParams.FILL_PARENT);
divider.setLayoutParams(lp);
divider.setBackgroundDrawable(mDividerDrawable);
addView(divider);
}
final View itemView = item.getItemView();
itemView.findViewById(R.id.gd_action_bar_item).setOnClickListener(mClickHandler);
final int size = (int) getResources().getDimension(R.dimen.gd_action_bar_height);
addView(itemView, new LayoutParams(size, LayoutParams.FILL_PARENT));
mItems.add(item);
}
return item;
}
public ActionBarItem getItem(int position) {
if (position < 0 || position >= mItems.size()) {
return null;
}
return mItems.get(position);
}
public void removeItem(ActionBarItem item) {
removeItem(mItems.indexOf(item));
}
public void removeItem(int position) {
if (position < 0 || position >= mItems.size()) {
return;
}
final int viewIndex = indexOfChild(mItems.get(position).getItemView());
final int increment = (mDividerDrawable != null) ? 1 : 0;
removeViews(viewIndex - increment, 1 + increment);
mItems.remove(position);
}
public void setType(Type type) {
if (type != mType) {
removeAllViews();
int layoutId = 0;
switch (type) {
case Empty:
layoutId = R.layout.gd_action_bar_empty;
break;
case Dashboard:
layoutId = R.layout.gd_action_bar_dashboard;
break;
case Normal:
layoutId = R.layout.gd_action_bar_normal;
break;
}
mType = type;
LayoutInflater.from(getContext()).inflate(layoutId, this);
// Reset all items
LinkedList<ActionBarItem> itemsCopy = new LinkedList<ActionBarItem>(mItems);
mItems.clear();
for (ActionBarItem item : itemsCopy) {
addItem(item);
}
}
}
public ActionBarItem newActionBarItem(Class<? extends ActionBarItem> klass) {
try {
ActionBarItem item = klass.newInstance();
item.setActionBar(this);
return item;
} catch (Exception e) {
throw new IllegalArgumentException("The given klass must have a default constructor");
}
}
private OnClickListener mClickHandler = new OnClickListener() {
public void onClick(View v) {
if (mOnActionBarListener != null) {
if (v == mHomeButton) {
mOnActionBarListener.onActionBarItemClicked(OnActionBarListener.HOME_ITEM);
return;
}
final int itemCount = mItems.size();
for (int i = 0; i < itemCount; i++) {
final ActionBarItem item = mItems.get(i);
final View itemButton = item.getItemView().findViewById(R.id.gd_action_bar_item);
if (v == itemButton) {
item.onItemClicked();
mOnActionBarListener.onActionBarItemClicked(i);
break;
}
}
}
}
};
}

@ -1,453 +0,0 @@
/*
* Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
*
* 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 greendroid.widget;
import greendroid.widget.item.DescriptionItem;
import greendroid.widget.item.DrawableItem;
import greendroid.widget.item.Item;
import greendroid.widget.item.LongTextItem;
import greendroid.widget.item.ProgressItem;
import greendroid.widget.item.SeparatorItem;
import greendroid.widget.item.SubtextItem;
import greendroid.widget.item.SubtitleItem;
import greendroid.widget.item.TextItem;
import greendroid.widget.item.ThumbnailItem;
import greendroid.widget.itemview.ItemView;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import android.content.Context;
import android.content.res.Resources;
import android.util.AttributeSet;
import android.util.Xml;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;
import android.widget.ListAdapter;
import android.widget.ListView;
/**
* <p>
* A {@link ListAdapter} that acts like an {@link ArrayAdapter}. It manages a
* ListView that is backed by an array of {@link Item}s. This is more advanced
* than a simple {@link ArrayAdapter} because it handles different types of
* cells internally. Adding, removing items from the internal array is also
* possible.
* </p>
* <p>
* The {@link ListView} can be notified manually using
* {@link notifyDataSetChanged} or automatically using the notifyOnChange flag.
* </p>
* <p>
* Finally, an ItemAdapter can be created via XML code using the createFromXml
* method. This is a very powerful feature when you want to display static data
* or if you want to prepopulate your ItemAdapter.
* </p>
*
* @author Cyril Mottier
*/
public class ItemAdapter extends BaseAdapter {
private static final int DEFAULT_MAX_VIEW_TYPE_COUNT = 10;
private static class TypeInfo {
int count;
int type;
}
private List<Item> mItems;
private HashMap<Class<? extends Item>, TypeInfo> mTypes;
private Context mContext;
private boolean mNotifyOnChange;
private int mMaxViewTypeCount;
/**
* Constructs an empty ItemAdapter.
*
* @param context The context associated with this array adapter.
*/
public ItemAdapter(Context context) {
this(context, new ArrayList<Item>());
}
/**
* Constructs an ItemAdapter using the specified items.
* <p>
* <em>Note</em> : Using this constructor implies the internal array will be
* immutable. As a result, adding or removing items will result in an
* exception.
* </p>
*
* @param context The context associated with this array adapter.
* @param items The array of Items use as underlying data for this
* ItemAdapter
*/
public ItemAdapter(Context context, Item[] items) {
this(context, Arrays.asList(items), DEFAULT_MAX_VIEW_TYPE_COUNT);
}
/**
* Constructs an ItemAdapter using the specified items.
* <p>
*
* @param context The context associated with this array adapter.
* @param items The list of Items used as data for this ItemAdapter
*/
public ItemAdapter(Context context, List<Item> items) {
this(context, items, DEFAULT_MAX_VIEW_TYPE_COUNT);
}
/**
* Constructs an ItemAdapter using the specified items.
* <p>
* <em>Note</em> : Using this constructor implies the internal array will be
* immutable. As a result, adding or removing items will result in an
* exception.
* </p>
* <p>
* <em><strong>Note:</strong> A ListAdapter doesn't handle variable view type
* count (even after a notifyDataSetChanged). An ItemAdapter handles several
* types of cell are therefore use a trick to overcome the previous problem.
* This trick is to fool the ListView several types exist. If you already
* know the number of item types you can have, simply set it using this method</em>
* </p>
*
* @param context The context associated with this array adapter.
* @param items The array of Items use as underlying data for this
* ItemAdapter
* @param maxViewTypeCount The maximum number of view type that may be
* generated by this ItemAdapter
*/
public ItemAdapter(Context context, Item[] items, int maxViewTypeCount) {
this(context, Arrays.asList(items), maxViewTypeCount);
}
/**
* Constructs an ItemAdapter using the specified items.
* <p>
* <em><strong>Note:</strong> A ListAdapter doesn't handle variable view type
* count (even after a notifyDataSetChanged). An ItemAdapter handles several
* types of cell are therefore use a trick to overcome the previous problem.
* This trick is to fool the ListView several types exist. If you already
* know the number of item types you can have, simply set it using this method</em>
* </p>
*
* @param context The context associated with this array adapter.
* @param items The list of Items used as data for this ItemAdapter
* @param maxViewTypeCount The maximum number of view type that may be
* generated by this ItemAdapter
*/
public ItemAdapter(Context context, List<Item> items, int maxViewTypeCount) {
mContext = context;
mItems = items;
mTypes = new HashMap<Class<? extends Item>, TypeInfo>();
mMaxViewTypeCount = Integer.MAX_VALUE;
for (Item item : mItems) {
addItem(item);
}
mMaxViewTypeCount = Math.max(1, Math.max(mTypes.size(), maxViewTypeCount));
}
private void addItem(Item item) {
final Class<? extends Item> klass = item.getClass();
TypeInfo info = mTypes.get(klass);
if (info == null) {
final int type = mTypes.size();
if (type >= mMaxViewTypeCount) {
throw new RuntimeException("This ItemAdapter may handle only " + mMaxViewTypeCount
+ " different view types.");
}
final TypeInfo newInfo = new TypeInfo();
newInfo.count = 1;
newInfo.type = type;
mTypes.put(klass, newInfo);
} else {
info.count++;
}
}
private void removeItem(Item item) {
final Class<? extends Item> klass = item.getClass();
TypeInfo info = mTypes.get(klass);
if (info != null) {
info.count--;
if (info.count == 0) {
// TODO cyril: Creating a pool to keep all TypeInfo instances
// could be a great idea in the future.
mTypes.remove(klass);
}
}
}
/**
* Returns the context associated with this array adapter. The context is
* used to create views from the resource passed to the constructor.
*
* @return The Context associated to this ItemAdapter
*/
public Context getContext() {
return mContext;
}
/**
* Returns the current number of different views types used in this
* ItemAdapter. Having a <em>getCurrentViewTypeCount</em> equal to
* <em>getViewTypeCount</em> means you won't be able to add a new type of
* view in this adapter (The Adapter class doesn't allow variable view type
* count).
*
* @return The current number of different view types
*/
public int getActualViewTypeCount() {
return mTypes.size();
}
/**
* Adds the specified object at the end of the array.
*
* @param object The object to add at the end of the array.
*/
public void add(Item item) {
mItems.add(item);
addItem(item);
if (mNotifyOnChange) {
notifyDataSetChanged();
}
}
/**
* Inserts the specified object at the specified index in the array.
*
* @param item The object to insert into the array.
* @param index The index at which the object must be inserted.
*/
public void insert(Item item, int index) {
mItems.add(index, item);
addItem(item);
if (mNotifyOnChange) {
notifyDataSetChanged();
}
}
/**
* Removes the specified object from the array.
*
* @param object The object to remove.
*/
public void remove(Item item) {
if (mItems.remove(item)) {
removeItem(item);
if (mNotifyOnChange) {
notifyDataSetChanged();
}
}
}
/**
* Remove all elements from the list.
*/
public void clear() {
mItems.clear();
mTypes.clear();
if (mNotifyOnChange) {
notifyDataSetChanged();
}
}
/**
* Sorts the content of this adapter using the specified comparator.
*
* @param comparator The comparator used to sort the objects contained in
* this adapter.
*/
public void sort(Comparator<? super Item> comparator) {
Collections.sort(mItems, comparator);
if (mNotifyOnChange) {
notifyDataSetChanged();
}
}
/**
* Control whether methods that change the list ({@link #add},
* {@link #insert}, {@link #remove}, {@link #clear}) automatically call
* {@link #notifyDataSetChanged}. If set to false, caller must manually call
* notifyDataSetChanged() to have the changes reflected in the attached
* view. The default is true, and calling notifyDataSetChanged() resets the
* flag to true.
*
* @param notifyOnChange if true, modifications to the list will
* automatically call {@link #notifyDataSetChanged}
*/
public void setNotifyOnChange(boolean notifyOnChange) {
mNotifyOnChange = notifyOnChange;
}
/**
* Creates an ItemAdapter from a given resource ID
*
* @param context The Context in which the ItemAdapter will be used in
* @param xmlId The resource ID of an XML file that describes a set of
* {@link Item}
* @return a new ItemAdapter constructed with the content of the file
* pointed by <em>xmlId</em>
* @throws XmlPullParserException
* @throws IOException
*/
public static ItemAdapter createFromXml(Context context, int xmlId) throws XmlPullParserException, IOException {
return createFromXml(context, context.getResources().getXml(xmlId));
}
/**
* Creates an ItemAdapter from a given XML document. Called on a parser
* positioned at a tag in an XML document, tries to create an ItemAdapter
* from that tag.
*
* @param context The Context in which the ItemAdapter will be used in
* @param xmlId The resource ID of an XML file that describes a set of
* {@link Item}
* @return a new ItemAdapter constructed with the content of the file
* pointed by <em>xmlId</em>
* @throws XmlPullParserException
* @throws IOException
*/
public static ItemAdapter createFromXml(Context context, XmlPullParser parser) throws XmlPullParserException,
IOException {
AttributeSet attrs = Xml.asAttributeSet(parser);
int type;
while ((type = parser.next()) != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT) {
// Empty loop
}
if (type != XmlPullParser.START_TAG) {
throw new XmlPullParserException("No start tag found");
}
if (!parser.getName().equals("item-array")) {
throw new XmlPullParserException("Unknown start tag. Should be 'item-array'");
}
final List<Item> items = new ArrayList<Item>();
final int innerDepth = parser.getDepth() + 1;
final Resources r = context.getResources();
int depth;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) {
if (type != XmlPullParser.START_TAG) {
continue;
}
if (depth > innerDepth) {
continue;
}
String name = parser.getName();
Item item;
if (name.equals("text-item")) {
item = new TextItem();
} else if (name.equals("longtext-item")) {
item = new LongTextItem();
} else if (name.equals("description-item")) {
item = new DescriptionItem();
} else if (name.equals("separator-item")) {
item = new SeparatorItem();
} else if (name.equals("progress-item")) {
item = new ProgressItem();
} else if (name.equals("drawable-item")) {
item = new DrawableItem();
} else if (name.equals("subtitle-item")) {
item = new SubtitleItem();
} else if (name.equals("subtext-item")) {
item = new SubtextItem();
} else if (name.equals("thumbnail-item")) {
item = new ThumbnailItem();
} else {
// TODO cyril: Remove that so that we can extend from
// ItemAdapter and creates our own items via XML?
throw new XmlPullParserException(parser.getPositionDescription() + ": invalid item tag " + name);
}
// TODO cyril: Here we should call a method that children may
// override to be able to create our own Items
if (item != null) {
item.inflate(r, parser, attrs);
items.add(item);
}
}
return new ItemAdapter(context, items);
}
public int getCount() {
return mItems.size();
}
public Object getItem(int position) {
return mItems.get(position);
}
public long getItemId(int position) {
return position;
}
@Override
public int getItemViewType(int position) {
return mTypes.get(getItem(position).getClass()).type;
}
@Override
public boolean isEnabled(int position) {
return ((Item) getItem(position)).enabled;
}
@Override
public int getViewTypeCount() {
return mMaxViewTypeCount;
}
public View getView(int position, View convertView, ViewGroup parent) {
final Item item = (Item) getItem(position);
ItemView cell = (ItemView) convertView;
if (cell == null) {
cell = item.newView(mContext, null);
cell.prepareItemView();
}
cell.setObject(item);
return (View) cell;
}
}

@ -1,74 +0,0 @@
/*
* Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
*
* 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 greendroid.widget;
import android.view.LayoutInflater;
import android.view.View;
import com.cyrilmottier.android.greendroid.R;
/**
* An extension of a {@link NormalActionBarItem} that supports a loading states.
* When in loading state, a {@link LoaderActionBarItem} display an indeterminate
* circular {@link ProgressBar}. This item is very handful with application
* fetching data from the network or performing long background tasks.
*
* @author Cyril Mottier
*/
public class LoaderActionBarItem extends NormalActionBarItem {
private boolean mLoading;
private View mButton;
private View mProgressBar;
public LoaderActionBarItem() {
mLoading = false;
}
@Override
protected View createItemView() {
return LayoutInflater.from(mContext).inflate(R.layout.gd_action_bar_item_loader, mActionBar, false);
}
@Override
protected void prepareItemView() {
super.prepareItemView();
mButton = mItemView.findViewById(R.id.gd_action_bar_item);
mProgressBar = mItemView.findViewById(R.id.gd_action_bar_item_progress_bar);
}
@Override
protected void onItemClicked() {
super.onItemClicked();
setLoading(true);
}
/**
* Sets the loading state of this {@link LoaderActionBarItem}.
*
* @param loading The new loading state. If true, an indeterminate
* {@link ProgressBar} is displayed. When false (default value)
* the {@link ActionBarItem} behaves exactly like a regular
* {@link NormalActionBarItem}.
*/
public void setLoading(boolean loading) {
if (loading != mLoading) {
mProgressBar.setVisibility(loading ? View.VISIBLE : View.GONE);
mButton.setVisibility(loading ? View.GONE : View.VISIBLE);
mLoading = loading;
}
}
}

@ -1,59 +0,0 @@
/*
* Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
*
* 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 greendroid.widget;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageButton;
import com.cyrilmottier.android.greendroid.R;
/**
* Default implementation of an {@link ActionBarItem}. A
* {@link NormalActionBarItem} is a simple {@link ActionBarItem} containing a
* single icon.
*
* @author Cyril Mottier
*/
public class NormalActionBarItem extends ActionBarItem {
@Override
protected View createItemView() {
return LayoutInflater.from(mContext).inflate(R.layout.gd_action_bar_item_base, mActionBar, false);
}
@Override
protected void prepareItemView() {
super.prepareItemView();
final ImageButton imageButton = (ImageButton) mItemView.findViewById(R.id.gd_action_bar_item);
imageButton.setImageDrawable(mDrawable);
imageButton.setContentDescription(mContentDescription);
}
@Override
protected void onContentDescriptionChanged() {
super.onContentDescriptionChanged();
mItemView.findViewById(R.id.gd_action_bar_item).setContentDescription(mContentDescription);
}
@Override
protected void onDrawableChanged() {
super.onDrawableChanged();
ImageButton imageButton = (ImageButton) mItemView.findViewById(R.id.gd_action_bar_item);
imageButton.setImageDrawable(mDrawable);
}
}

@ -1,58 +0,0 @@
/*
* Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
*
* 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 greendroid.widget;
import java.lang.ref.WeakReference;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.view.View;
/**
* A QuickAction implements an item in a {@link QuickActionWidget}. A
* QuickAction represents a single action and may contain a text and an icon.
*
* @author Benjamin Fellous
* @author Cyril Mottier
*/
public class QuickAction {
public Drawable mDrawable;
public CharSequence mTitle;
/* package */WeakReference<View> mView;
public QuickAction(Drawable d, CharSequence title) {
mDrawable = d;
mTitle = title;
}
public QuickAction(Context ctx, int drawableId, CharSequence title) {
mDrawable = ctx.getResources().getDrawable(drawableId);
mTitle = title;
}
public QuickAction(Context ctx, Drawable d, int titleId) {
mDrawable = d;
mTitle = ctx.getResources().getString(titleId);
}
public QuickAction(Context ctx, int drawableId, int titleId) {
mDrawable = ctx.getResources().getDrawable(drawableId);
mTitle = ctx.getResources().getString(titleId);
}
}

@ -1,150 +0,0 @@
/*
* Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
*
* 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 greendroid.widget;
import java.lang.ref.WeakReference;
import java.util.List;
import android.content.Context;
import android.graphics.Rect;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.MeasureSpec;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.widget.FrameLayout;
import android.widget.HorizontalScrollView;
import android.widget.ListView;
import android.widget.TextView;
import com.cyrilmottier.android.greendroid.R;
/**
* A QuickActionBar displays a set of {@link QuickAction} on a single row. In
* case too many items are added to the QuickActionBar, the user can
* horizontally scroll QuickActions. Using a QuickActionBar is a great
* replacement for the long click UI pattern. For instance,
* {@link QuickActionBar} adds secondary actions to an item of a
* {@link ListView}.
*
* @author Benjamin Fellous
* @author Cyril Mottier
*/
public class QuickActionBar extends QuickActionWidget {
private HorizontalScrollView mScrollView;
private Animation mRackAnimation;
private ViewGroup mRack;
private ViewGroup mQuickActionItems;
private List<QuickAction> mQuickActions;
public QuickActionBar(Context context) {
super(context);
mRackAnimation = AnimationUtils.loadAnimation(context, R.anim.gd_rack);
mRackAnimation.setInterpolator(new Interpolator() {
public float getInterpolation(float t) {
final float inner = (t * 1.55f) - 1.1f;
return 1.2f - inner * inner;
}
});
setContentView(R.layout.gd_quick_action_bar);
final View v = getContentView();
mRack = (ViewGroup) v.findViewById(R.id.gdi_rack);
mQuickActionItems = (ViewGroup) v.findViewById(R.id.gdi_quick_action_items);
mScrollView = (HorizontalScrollView) v.findViewById(R.id.gdi_scroll);
}
@Override
public void show(View anchor) {
super.show(anchor);
mScrollView.scrollTo(0, 0);
}
@Override
protected void onMeasureAndLayout(Rect anchorRect, View contentView) {
contentView.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
contentView.measure(MeasureSpec.makeMeasureSpec(getScreenWidth(), MeasureSpec.EXACTLY),
ViewGroup.LayoutParams.WRAP_CONTENT);
int rootHeight = contentView.getMeasuredHeight();
int offsetY = getArrowOffsetY();
int dyTop = anchorRect.top;
int dyBottom = getScreenHeight() - anchorRect.bottom;
boolean onTop = (dyTop > dyBottom);
int popupY = (onTop) ? anchorRect.top - rootHeight + offsetY : anchorRect.bottom - offsetY;
setWidgetSpecs(popupY, onTop);
}
@Override
protected void populateQuickActions(List<QuickAction> quickActions) {
mQuickActions = quickActions;
final LayoutInflater inflater = LayoutInflater.from(getContext());
for (QuickAction action : quickActions) {
TextView view = (TextView) inflater.inflate(R.layout.gd_quick_action_bar_item, mQuickActionItems, false);
view.setText(action.mTitle);
view.setCompoundDrawablesWithIntrinsicBounds(null, action.mDrawable, null, null);
view.setOnClickListener(mClickHandlerInternal);
mQuickActionItems.addView(view);
action.mView = new WeakReference<View>(view);
}
}
@Override
protected void onClearQuickActions() {
super.onClearQuickActions();
mQuickActionItems.removeAllViews();
}
private OnClickListener mClickHandlerInternal = new OnClickListener() {
public void onClick(View view) {
final OnQuickActionClickListener listener = getOnQuickActionClickListener();
if (listener != null) {
final int itemCount = mQuickActions.size();
for (int i = 0; i < itemCount; i++) {
if (view == mQuickActions.get(i).mView.get()) {
listener.onQuickActionClicked(QuickActionBar.this, i);
break;
}
}
}
if (getDismissOnClick()) {
dismiss();
}
}
};
}

@ -1,122 +0,0 @@
/*
* Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
*
* 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 greendroid.widget;
import java.util.List;
import android.content.Context;
import android.graphics.Rect;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.MeasureSpec;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.GridView;
import android.widget.TextView;
import com.cyrilmottier.android.greendroid.R;
/**
* A {@link QuickActionGrid} is an implementation of a {@link QuickActionWidget}
* that displays {@link QuickAction}s in a grid manner. This is usually used to create
* a shortcut to jump between different type of information on screen.
*
* @author Benjamin Fellous
* @author Cyril Mottier
*/
public class QuickActionGrid extends QuickActionWidget {
private GridView mGridView;
public QuickActionGrid(Context context) {
super(context);
setContentView(R.layout.gd_quick_action_grid);
final View v = getContentView();
mGridView = (GridView) v.findViewById(R.id.gdi_grid);
}
@Override
protected void populateQuickActions(final List<QuickAction> quickActions) {
mGridView.setAdapter(new BaseAdapter() {
public View getView(int position, View view, ViewGroup parent) {
TextView textView = (TextView) view;
if (view == null) {
final LayoutInflater inflater = LayoutInflater.from(getContext());
textView = (TextView) inflater.inflate(R.layout.gd_quick_action_grid_item, mGridView, false);
}
QuickAction quickAction = quickActions.get(position);
textView.setText(quickAction.mTitle);
textView.setCompoundDrawablesWithIntrinsicBounds(null, quickAction.mDrawable, null, null);
return textView;
}
public long getItemId(int position) {
return position;
}
public Object getItem(int position) {
return null;
}
public int getCount() {
return quickActions.size();
}
});
mGridView.setOnItemClickListener(mInternalItemClickListener);
}
@Override
protected void onMeasureAndLayout(Rect anchorRect, View contentView) {
contentView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
contentView.measure(MeasureSpec.makeMeasureSpec(getScreenWidth(), MeasureSpec.EXACTLY),
LayoutParams.WRAP_CONTENT);
int rootHeight = contentView.getMeasuredHeight();
int offsetY = getArrowOffsetY();
int dyTop = anchorRect.top;
int dyBottom = getScreenHeight() - anchorRect.bottom;
boolean onTop = (dyTop > dyBottom);
int popupY = (onTop) ? anchorRect.top - rootHeight + offsetY : anchorRect.bottom - offsetY;
setWidgetSpecs(popupY, onTop);
}
private OnItemClickListener mInternalItemClickListener = new OnItemClickListener() {
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
getOnQuickActionClickListener().onQuickActionClicked(QuickActionGrid.this, position);
if (getDismissOnClick()) {
dismiss();
}
}
};
}

@ -1,326 +0,0 @@
/*
* Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
*
* 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 greendroid.widget;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.PopupWindow;
import com.cyrilmottier.android.greendroid.R;
/**
* Abstraction of a {@link QuickAction} wrapper. A QuickActionWidget is
* displayed on top of the user interface (it overlaps all UI elements but the
* notification bar). Clients may listen to user actions using a
* {@link OnQuickActionClickListener} .
*
* @author Benjamin Fellous
* @author Cyril Mottier
*/
public abstract class QuickActionWidget extends PopupWindow {
private static final int MEASURE_AND_LAYOUT_DONE = 1 << 1;
private final int[] mLocation = new int[2];
protected final Rect mRect = new Rect();
private int mPrivateFlags;
private Context mContext;
private boolean mDismissOnClick;
private int mArrowOffsetY;
private int mPopupY;
private boolean mIsOnTop;
private int mScreenHeight;
private int mScreenWidth;
private boolean mIsDirty;
private OnQuickActionClickListener mOnQuickActionClickListener;
private ArrayList<QuickAction> mQuickActions = new ArrayList<QuickAction>();
/**
* Interface that may be used to listen to clicks on quick actions.
*
* @author Benjamin Fellous
* @author Cyril Mottier
*/
public static interface OnQuickActionClickListener {
/**
* Clients may implement this method to be notified of a click on a
* particular quick action.
*
* @param position Position of the quick action that have been clicked.
*/
void onQuickActionClicked(QuickActionWidget widget, int position);
}
/**
* Creates a new QuickActionWidget for the given context.
*
* @param context The context in which the QuickActionWidget is running in
*/
public QuickActionWidget(Context context) {
super(context);
mContext = context;
initializeDefault();
setFocusable(true);
setTouchable(true);
setOutsideTouchable(true);
setWidth(WindowManager.LayoutParams.WRAP_CONTENT);
setHeight(WindowManager.LayoutParams.WRAP_CONTENT);
final WindowManager windowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
mScreenWidth = windowManager.getDefaultDisplay().getWidth();
mScreenHeight = windowManager.getDefaultDisplay().getHeight();
}
/**
* Equivalent to {@link PopupWindow#setContentView(View)} but with a layout
* identifier.
*
* @param layoutId The layout identifier of the view to use.
*/
public void setContentView(int layoutId) {
setContentView(LayoutInflater.from(mContext).inflate(layoutId, null));
}
private void initializeDefault() {
mDismissOnClick = true;
mArrowOffsetY = mContext.getResources().getDimensionPixelSize(R.dimen.gd_arrow_offset);
}
/**
* Returns the arrow offset for the Y axis.
*
* @see {@link #setArrowOffsetY(int)}
* @return The arrow offset.
*/
public int getArrowOffsetY() {
return mArrowOffsetY;
}
/**
* Sets the arrow offset to a new value. Setting an arrow offset may be
* particular useful to warn which view the QuickActionWidget is related to.
* By setting a positive offset, the arrow will overlap the view given by
* {@link #show(View)}. The default value is 5dp.
*
* @param offsetY The offset for the Y axis
*/
public void setArrowOffsetY(int offsetY) {
mArrowOffsetY = offsetY;
}
/**
* Returns the width of the screen.
*
* @return The width of the screen
*/
protected int getScreenWidth() {
return mScreenWidth;
}
/**
* Returns the height of the screen.
*
* @return The height of the screen
*/
protected int getScreenHeight() {
return mScreenHeight;
}
/**
* By default, a {@link QuickActionWidget} is dismissed once the user
* clicked on a {@link QuickAction}. This behavior can be changed using this
* method.
*
* @param dismissOnClick True if you want the {@link QuickActionWidget} to
* be dismissed on click else false.
*/
public void setDismissOnClick(boolean dismissOnClick) {
mDismissOnClick = dismissOnClick;
}
public boolean getDismissOnClick() {
return mDismissOnClick;
}
/**
* @param listener
*/
public void setOnQuickActionClickListener(OnQuickActionClickListener listener) {
mOnQuickActionClickListener = listener;
}
/**
* Add a new QuickAction to this {@link QuickActionWidget}. Adding a new
* {@link QuickAction} while the {@link QuickActionWidget} is currently
* being shown does nothing. The new {@link QuickAction} will be displayed
* on the next call to {@link #show(View)}.
*
* @param action The new {@link QuickAction} to add
*/
public void addQuickAction(QuickAction action) {
if (action != null) {
mQuickActions.add(action);
mIsDirty = true;
}
}
/**
* Removes all {@link QuickAction} from this {@link QuickActionWidget}.
*/
public void clearAllQuickActions() {
if (!mQuickActions.isEmpty()) {
mQuickActions.clear();
mIsDirty = true;
}
}
/**
* Call that method to display the {@link QuickActionWidget} anchored to the
* given view.
*
* @param anchor The view the {@link QuickActionWidget} will be anchored to.
*/
public void show(View anchor) {
final View contentView = getContentView();
if (contentView == null) {
throw new IllegalStateException("You need to set the content view using the setContentView method");
}
// Replaces the background of the popup with a cleared background
setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
final int[] loc = mLocation;
anchor.getLocationOnScreen(loc);
mRect.set(loc[0], loc[1], loc[0] + anchor.getWidth(), loc[1] + anchor.getHeight());
if (mIsDirty) {
clearQuickActions();
populateQuickActions(mQuickActions);
}
onMeasureAndLayout(mRect, contentView);
if ((mPrivateFlags & MEASURE_AND_LAYOUT_DONE) != MEASURE_AND_LAYOUT_DONE) {
throw new IllegalStateException("onMeasureAndLayout() did not set the widget specification by calling"
+ " setWidgetSpecs()");
}
showArrow();
prepareAnimationStyle();
try {
showAtLocation(anchor, Gravity.NO_GRAVITY, getShowAtX(), mPopupY);
} catch (Exception e) {
Log.w("quick-action-show", e);
}
}
protected int getShowAtX() {
return 0;
}
protected void clearQuickActions() {
if (!mQuickActions.isEmpty()) {
onClearQuickActions();
}
}
protected void onClearQuickActions() {
}
protected abstract void populateQuickActions(List<QuickAction> quickActions);
protected abstract void onMeasureAndLayout(Rect anchorRect, View contentView);
protected void setWidgetSpecs(int popupY, boolean isOnTop) {
mPopupY = popupY;
mIsOnTop = isOnTop;
mPrivateFlags |= MEASURE_AND_LAYOUT_DONE;
}
private void showArrow() {
final View contentView = getContentView();
final int arrowId = mIsOnTop ? R.id.gdi_arrow_down : R.id.gdi_arrow_up;
final View arrow = contentView.findViewById(arrowId);
final View arrowUp = contentView.findViewById(R.id.gdi_arrow_up);
final View arrowDown = contentView.findViewById(R.id.gdi_arrow_down);
if (arrowId == R.id.gdi_arrow_up) {
arrowUp.setVisibility(View.VISIBLE);
arrowDown.setVisibility(View.INVISIBLE);
} else if (arrowId == R.id.gdi_arrow_down) {
arrowUp.setVisibility(View.INVISIBLE);
arrowDown.setVisibility(View.VISIBLE);
}
ViewGroup.MarginLayoutParams param = (ViewGroup.MarginLayoutParams) arrow.getLayoutParams();
param.leftMargin = getArrowLeftMargin(arrow);
}
protected int getArrowLeftMargin(View arrow) {
return mRect.centerX() - (arrow.getMeasuredWidth()) / 2;
}
private void prepareAnimationStyle() {
final int screenWidth = mScreenWidth;
final boolean onTop = mIsOnTop;
final int arrowPointX = mRect.centerX();
if (arrowPointX <= screenWidth / 4) {
setAnimationStyle(onTop ? R.style.GreenDroid_Animation_PopUp_Left
: R.style.GreenDroid_Animation_PopDown_Left);
} else if (arrowPointX >= 3 * screenWidth / 4) {
setAnimationStyle(onTop ? R.style.GreenDroid_Animation_PopUp_Right
: R.style.GreenDroid_Animation_PopDown_Right);
} else {
setAnimationStyle(onTop ? R.style.GreenDroid_Animation_PopUp_Center
: R.style.GreenDroid_Animation_PopDown_Center);
}
}
protected Context getContext() {
return mContext;
}
protected OnQuickActionClickListener getOnQuickActionClickListener() {
return mOnQuickActionClickListener;
}
}

@ -1,83 +0,0 @@
/*
* Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
*
* 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 greendroid.widget;
import android.database.DataSetObservable;
import android.database.DataSetObserver;
import android.view.View;
import android.view.ViewGroup;
/**
* A SegmentedAdapter is a data source of a SegmentedHost/SegmentedHost.
*
* @author Cyril Mottier
*/
public abstract class SegmentedAdapter {
private final DataSetObservable mDataSetObservable = new DataSetObservable();
/**
* How many segments have to be displayed
*
* @return The number of segment displayed by the underlying SegmentedBar
*/
public abstract int getCount();
/**
* Get the View associated to the segment at position <em>position</em>
*
* @param position The position of the item in the SegmentedAdapter
* @param parent The parent that this view will eventually be attached to
* @return A View corresponding to the segment at the given position
*/
public abstract View getView(int position, ViewGroup parent);
/**
* Get the title for the segment at position <em>position</em>
*
* @param position The position of the segment in the SegmentedBar
* @return A title for the segment at the given position.
*/
public abstract String getSegmentTitle(int position);
/**
* Register an observer that is called when changes happen to the data used
* by this adapter.
*
* @param observer The object that gets notified when the data set changes.
*/
public void registerDataSetObserver(DataSetObserver observer) {
mDataSetObservable.registerObserver(observer);
}
/**
* Unregister an observer that has previously been registered with this
* adapter via {@link #unregisterDataSetObserver(DataSetObserver)}
*
* @param observer The object to unregister
*/
public void unregisterDataSetObserver(DataSetObserver observer) {
mDataSetObservable.unregisterObserver(observer);
}
/**
* Notifies the attached View that the underlying data has changed and
* should refresh itself.
*/
public void notifyDataSetChanged() {
mDataSetObservable.notifyChanged();
}
}

@ -1,282 +0,0 @@
/*
* Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
*
* 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 greendroid.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnFocusChangeListener;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.ImageView;
import android.widget.LinearLayout;
import com.cyrilmottier.android.greendroid.R;
/**
* A SegmentedBar displays a set of Buttons. Only one segment in a SegmentedBar
* can be selected at a time. A SegmentedBar is very close to a TabWidget in
* term of functionalities.
*
* @author Cyril Mottier
*/
public class SegmentedBar extends LinearLayout implements OnFocusChangeListener {
/**
* Clients may use this listener to be notified of any changes that occurs
* on the SegmentBar
*
* @author Cyril Mottier
*/
public static interface OnSegmentChangeListener {
/**
* Notification that the current segment has changed.
*
* @param index The index of the new selected segment.
* @param clicked Whether the segment has been selected via a user
* click.
*/
public void onSegmentChange(int index, boolean clicked);
}
private OnSegmentChangeListener mOnSegmentChangeListener;
private int mCheckedSegment;
private Drawable mDividerDrawable;
private int mDividerWidth;
public SegmentedBar(Context context) {
this(context, null);
}
public SegmentedBar(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.gdSegmentedBarStyle);
}
public SegmentedBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs);
initSegmentedBar();
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SegmentedBar, defStyle, 0);
mDividerDrawable = a.getDrawable(R.styleable.SegmentedBar_dividerDrawable);
mDividerWidth = a.getDimensionPixelSize(R.styleable.SegmentedBar_dividerWidth, 0);
a.recycle();
}
private void initSegmentedBar() {
mCheckedSegment = 0;
setOrientation(LinearLayout.HORIZONTAL);
// Register ourselves so that we can handle focus on internal segments
setFocusable(true);
setOnFocusChangeListener(this);
}
/**
* Sets the drawable that is used as divider between each segment.
*
* @param dividerDrawable The drawable to used as a divider. Note : using a
* ColorDrawable will not work properly as the intrinsic width of
* a ColorDrawable is -1.
*/
public void setDividerDrawable(Drawable dividerDrawable) {
mDividerDrawable = dividerDrawable;
}
/**
* Sets the drawable that is used as divider between each segment.
*
* @param resId The identifier of the Drawable to use.
*/
public void setDividerDrawable(int resId) {
mDividerDrawable = getContext().getResources().getDrawable(resId);
}
/**
* Sets the width of the divider that will be used as segment divider. If
* the dividerWidth has not been set, the intrinsic width of the divider
* drawable is used.
*
* @param width Width of the divider
*/
public void setDividerWidth(int width) {
mDividerWidth = width;
}
/**
* Returns the current number of segment in this SegmentBar
*
* @return The number of segments in this SegmentBar
*/
public int getSegmentCount() {
int segmentCount = getChildCount();
// If we have divider we'll have an odd number of child
if (mDividerDrawable != null) {
segmentCount = (segmentCount + 1) / 2;
}
return segmentCount;
}
/**
* Use this method to register an OnSegmentChangeListener and listen to
* changes that occur on this SegmentBar
*
* @param listener The listener to use
*/
public void setOnSegmentChangeListener(OnSegmentChangeListener listener) {
mOnSegmentChangeListener = listener;
}
/**
* Sets the current segment to the index <em>index</em>
*
* @param index The index of the segment to set. Client will be notified
* using this method of the segment change.
*/
public void setCurrentSegment(int index) {
if (index < 0 || index >= getSegmentCount()) {
return;
}
((CheckBox) getChildSegmentAt(mCheckedSegment)).setChecked(false);
mCheckedSegment = index;
((CheckBox) getChildSegmentAt(mCheckedSegment)).setChecked(true);
}
/**
* Returns the view representing the segment at the index <em>index</em>
*
* @param index The index of the segment to retrieve
* @return The view that represents the segment at index <em>index</em>
*/
public View getChildSegmentAt(int index) {
/*
* If we are using dividers, then instead of segments at 0, 1, 2, ... we
* have segments at 0, 2, 4, ...
*/
if (mDividerDrawable != null) {
index *= 2;
}
return getChildAt(index);
}
/**
* Adds a segment to the SegmentBar. This method automatically adds a
* divider if needed.
*
* @param title The title of the segment to add.
*/
public void addSegment(String title) {
final Context context = getContext();
final LayoutInflater inflater = LayoutInflater.from(context);
/*
* First of all, we have to check whether or not we need to add a
* divider. A divider is added when there is at least one segment
*/
if (mDividerDrawable != null && getSegmentCount() > 0) {
ImageView divider = new ImageView(context);
final int width = (mDividerWidth > 0) ? mDividerWidth : mDividerDrawable.getIntrinsicWidth();
final LinearLayout.LayoutParams lp = new LayoutParams(width, LayoutParams.FILL_PARENT);
lp.setMargins(0, 0, 0, 0);
divider.setLayoutParams(lp);
divider.setBackgroundDrawable(mDividerDrawable);
addView(divider);
}
CheckBox segment = (CheckBox) inflater.inflate(R.layout.gd_segment, this, false);
segment.setText(title);
segment.setClickable(true);
segment.setFocusable(true);
segment.setOnFocusChangeListener(this);
segment.setOnCheckedChangeListener(new SegmentCheckedListener(getSegmentCount()));
segment.setOnClickListener(new SegmentClickedListener(getSegmentCount()));
addView(segment);
}
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus) {
return;
}
if (v == this) {
final View segment = getChildSegmentAt(mCheckedSegment);
if (segment != null) {
segment.requestFocus();
}
}
else {
final int segmentCounts = getSegmentCount();
for (int i = 0; i < segmentCounts; i++) {
if (getChildSegmentAt(i) == v) {
setCurrentSegment(i);
notifyListener(i, false);
break;
}
}
}
}
private class SegmentClickedListener implements OnClickListener {
private final int mSegmentIndex;
private SegmentClickedListener(int segmentIndex) {
mSegmentIndex = segmentIndex;
}
public void onClick(View v) {
final CheckBox segment = (CheckBox) getChildSegmentAt(mCheckedSegment);
if (mSegmentIndex == mCheckedSegment && !segment.isChecked()) {
segment.setChecked(true);
} else {
notifyListener(mSegmentIndex, true);
}
}
}
private class SegmentCheckedListener implements OnCheckedChangeListener {
private final int mSegmentIndex;
private SegmentCheckedListener(int segmentIndex) {
mSegmentIndex = segmentIndex;
}
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
setCurrentSegment(mSegmentIndex);
}
}
}
private void notifyListener(int index, boolean clicked) {
if (mOnSegmentChangeListener != null) {
mOnSegmentChangeListener.onSegmentChange(index, clicked);
}
}
}

@ -1,181 +0,0 @@
/*
* Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
*
* 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 greendroid.widget;
import greendroid.util.Config;
import greendroid.widget.SegmentedBar.OnSegmentChangeListener;
import android.content.Context;
import android.content.res.TypedArray;
import android.database.DataSetObserver;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import com.cyrilmottier.android.greendroid.R;
/**
* A SegmentedHost is a wrapper view that handle a SegmentedBar and a
* FrameLayout that hold the content. Data (titles, and content Views) are
* provided to the SegmentedHost via a {@link SegmentedAdapter}.
*
* @author Cyril Mottier
*/
public class SegmentedHost extends LinearLayout {
private final static String LOG_TAG = SegmentedHost.class.getSimpleName();
private int mSegmentedBarId;
private SegmentedBar mSegmentedBar;
private int mSegmentedHostId;
private FrameLayout mContentView;
private int mSelectedSegment;
private SegmentedAdapter mAdapter;
private View[] mViews;
private DataSetObserver mSegmentObserver = new DataSetObserver() {
public void onChanged() {
setupSegmentedHost(mSelectedSegment);
}
public void onInvalidated() {
// Do nothing - method never called
}
};
public SegmentedHost(Context context) {
this(context, null);
}
public SegmentedHost(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.gdSegmentedHostStyle);
}
public SegmentedHost(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs);
initSegmentedView();
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SegmentedHost, defStyle, 0);
mSegmentedBarId = a.getResourceId(R.styleable.SegmentedHost_segmentedBar, -1);
if (mSegmentedBarId <= 0) {
throw new IllegalArgumentException("The segmentedBar attribute is required and must refer "
+ "to a valid child.");
}
mSegmentedHostId = a.getResourceId(R.styleable.SegmentedHost_segmentedContentView, -1);
if (mSegmentedHostId <= 0) {
throw new IllegalArgumentException("The segmentedHost attribute is required and must refer "
+ "to a valid child.");
}
}
private void initSegmentedView() {
setOrientation(LinearLayout.VERTICAL);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mSegmentedBar = (SegmentedBar) findViewById(mSegmentedBarId);
if (mSegmentedBar == null) {
throw new IllegalArgumentException("The segmentedBar attribute must refer to an existing child.");
}
mSegmentedBar.setOnSegmentChangeListener(new SegmentSwitcher());
mContentView = (FrameLayout) findViewById(mSegmentedHostId);
if (mContentView == null) {
throw new IllegalArgumentException("The segmentedHost attribute must refer to an existing child.");
} else if (!(mContentView instanceof FrameLayout)) {
throw new RuntimeException("The segmentedHost attribute must refer to a FrameLayout");
}
}
public SegmentedBar getSegmentedBar() {
return mSegmentedBar;
}
public FrameLayout getContentView() {
return mContentView;
}
public void setAdapter(SegmentedAdapter adapter) {
if (mAdapter != null) {
mAdapter.unregisterDataSetObserver(mSegmentObserver);
}
mAdapter = adapter;
if (adapter != null) {
mAdapter.registerDataSetObserver(mSegmentObserver);
}
setupSegmentedHost(0);
}
private void setupSegmentedHost(int selectedSegment) {
if (Config.GD_INFO_LOGS_ENABLED) {
Log.i(LOG_TAG, "Preparing the SegmentedHost with the segment " + selectedSegment);
}
mSegmentedBar.removeAllViews();
mContentView.removeAllViews();
mViews = null;
if (mAdapter != null) {
// Add all segments to the Segmentedbar
final int count = mAdapter.getCount();
for (int i = 0; i < count; i++) {
mSegmentedBar.addSegment(mAdapter.getSegmentTitle(i));
}
if (selectedSegment < 0) {
selectedSegment = 0;
} else if (selectedSegment > count) {
selectedSegment = count;
}
if (count > 0) {
// Prepare the SegmentBar
mViews = new View[count];
mSegmentedBar.setCurrentSegment(selectedSegment);
// And displays the first view
setContentView(selectedSegment);
}
}
}
private class SegmentSwitcher implements OnSegmentChangeListener {
public void onSegmentChange(int index, boolean clicked) {
setContentView(index);
}
}
private void setContentView(int index) {
mSelectedSegment = index;
mContentView.removeAllViews();
if (mViews[index] == null) {
mViews[index] = mAdapter.getView(index, SegmentedHost.this);
}
mContentView.addView(mViews[index]);
}
}

@ -1,54 +0,0 @@
/*
* Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
*
* 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 greendroid.widget.item;
import greendroid.widget.itemview.ItemView;
import android.content.Context;
import android.view.ViewGroup;
import com.cyrilmottier.android.greendroid.R;
/**
* A description item displays a text on several lines. The default
* implementation makes it disabled.
*
* @author Cyril Mottier
*/
public class DescriptionItem extends TextItem {
/**
* @hide
*/
public DescriptionItem() {
this(null);
}
/**
* Creates a new DescriptionItem with the given description.
*
* @param description The description for the current item.
*/
public DescriptionItem(String description) {
super(description);
enabled = false;
}
@Override
public ItemView newView(Context context, ViewGroup parent) {
return createCellFromXml(context, R.layout.gd_description_item_view, parent);
}
}

@ -1,91 +0,0 @@
/*
* Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
*
* 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 greendroid.widget.item;
import greendroid.widget.itemview.ItemView;
import java.io.IOException;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.ViewGroup;
import com.cyrilmottier.android.greendroid.R;
/**
* A DrawableItem displays a single Drawable on the left of the item cell and a
* description text on the right. A DrawableItem takes care of adapting itself
* depending on the presence of its Drawable.
*
* @author Cyril Mottier
*/
public class DrawableItem extends TextItem {
/**
* The resource identifier for the drawable.
*/
public int drawableId;
/**
* @hide
*/
public DrawableItem() {
this(null);
}
/**
* Constructs a new DrawableItem that has no Drawable and displays the given
* text. Used as it, a DrawableItem is very similar to a TextItem
*
* @param text The text of this DrawableItem
*/
public DrawableItem(String text) {
this(text, 0);
}
/**
* Constructs a new DrawableItem that has no Drawable and displays the given
* text. Used as it, a DrawableItem is very similar to a TextItem
*
* @param text The text of this DrawableItem
* @param drawableId The resource identifier of the Drawable
*/
public DrawableItem(String text, int drawableId) {
super(text);
this.drawableId = drawableId;
}
@Override
public ItemView newView(Context context, ViewGroup parent) {
return createCellFromXml(context, R.layout.gd_drawable_item_view, parent);
}
@Override
public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs) throws XmlPullParserException,
IOException {
super.inflate(r, parser, attrs);
TypedArray a = r.obtainAttributes(attrs, R.styleable.DrawableItem);
drawableId = a.getResourceId(R.styleable.DrawableItem_drawable, 0);
a.recycle();
}
}

@ -1,134 +0,0 @@
/*
* Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
*
* 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 greendroid.widget.item;
import greendroid.widget.itemview.ItemView;
import java.io.IOException;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.widget.ListView;
import com.cyrilmottier.android.greendroid.R;
/**
* Base class for all items used in GreenDroid. An item represents a wrapper of
* data. Each item contains at least all the information needed to display a
* single row in a {@link ListView}.
*
* @author Cyril Mottier
*/
public abstract class Item {
private SparseArray<Object> mTags;
private Object mTag;
/**
* Set to true when this item is enabled?
*/
public boolean enabled;
/**
* Constructs a new item.
*/
public Item() {
// By default, an item is enabled
enabled = true;
}
/**
* Returns the tag associated to that item.
*
* @return The tag associated to this item.
*/
public Object getTag() {
return mTag;
}
/**
* Sets the tag associated with this item. A tag is often used to store
* extra information.
*
* @param tag The tag associated to this item
*/
public void setTag(Object tag) {
mTag = tag;
}
/**
* Returns the tag associated with this item and the specified key.
*
* @param key The key of the tag to retrieve
* @return The tag associated to the key <em>key</em> or null if no tags are
* associated to that key
*/
public Object getTag(int key) {
return (mTags == null) ? null : mTags.get(key);
}
/**
* Sets a tag associated with this item and a key. A tag is often used to
* store extra information.
*
* @param key The key for the specified tag
* @param tag A tag that will be associated to that item
*/
public void setTag(int key, Object tag) {
if (mTags == null) {
mTags = new SparseArray<Object>();
}
mTags.put(key, tag);
}
/**
* Returns a view that is associated to the current item. The returned view
* is normally capable of being a good recipient for all item's information.
*
* @param context The context in which the {@link ItemView} will be used
* @param parent The parent view of that new view. It is usually the parent
* ListView
* @return A new allocated view for the current Item
*/
public abstract ItemView newView(Context context, ViewGroup parent);
/**
* Helper method to inflate a layout using a given Context and a layoutID.
*
* @param context The current context
* @param layoutID The identifier of the layout to inflate
* @return A newly inflated view
*/
protected static ItemView createCellFromXml(Context context, int layoutID, ViewGroup parent) {
return (ItemView) LayoutInflater.from(context).inflate(layoutID, parent, false);
}
public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs) throws XmlPullParserException,
IOException {
TypedArray a = r.obtainAttributes(attrs, R.styleable.Item);
enabled = a.getBoolean(R.styleable.Item_enabled, enabled);
a.recycle();
}
}

@ -1,45 +0,0 @@
/*
* Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
*
* 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 greendroid.widget.item;
import greendroid.widget.itemview.ItemView;
import android.content.Context;
import android.view.ViewGroup;
import com.cyrilmottier.android.greendroid.R;
/**
* A LongTextItem is very similar to a regular {@link TextItem}. The only
* difference is it may display the text on several lines.
*
* @author Cyril Mottier
*/
public class LongTextItem extends TextItem {
public LongTextItem() {
this(null);
}
public LongTextItem(String text) {
super(text);
}
@Override
public ItemView newView(Context context, ViewGroup parent) {
return createCellFromXml(context, R.layout.gd_long_text_item_view, parent);
}
}

@ -1,93 +0,0 @@
/*
* Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
*
* 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 greendroid.widget.item;
import greendroid.widget.itemview.ItemView;
import java.io.IOException;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.ViewGroup;
import com.cyrilmottier.android.greendroid.R;
/**
* Progress indicator that displays a centered text with a circular progress bar
* when something is in progress.@
*
* @author Cyril Mottier
*/
public class ProgressItem extends TextItem {
private static final boolean DEFAULT_IS_IN_PROGRESS = false;
/**
* The state of this item. When set to true, a circular progress bar
* indicates something is going on/being computed.
*/
public boolean isInProgress;
/**
* @hide
*/
public ProgressItem() {
this(null);
}
/**
* Constructs a ProgressItem with the given text. By default, the circular
* progress bar is not visible ... which indicates nothing is currently in
* progress.
*
* @param text The text for this item
*/
public ProgressItem(String text) {
this(text, DEFAULT_IS_IN_PROGRESS);
}
/**
* Constructs a ProgressItem with the given text and state.
*
* @param text The text for this item
* @param isInProgress The state for this item
*/
public ProgressItem(String text, boolean isInProgress) {
super(text);
this.isInProgress = isInProgress;
}
@Override
public ItemView newView(Context context, ViewGroup parent) {
return createCellFromXml(context, R.layout.gd_progress_item_view, parent);
}
@Override
public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs) throws XmlPullParserException,
IOException {
super.inflate(r, parser, attrs);
TypedArray a = r.obtainAttributes(attrs, R.styleable.ProgressItem);
isInProgress = a.getBoolean(R.styleable.ProgressItem_isInProgress, DEFAULT_IS_IN_PROGRESS);
a.recycle();
}
}

@ -1,55 +0,0 @@
/*
* Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
*
* 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 greendroid.widget.item;
import greendroid.widget.itemview.ItemView;
import android.content.Context;
import android.view.ViewGroup;
import android.widget.ListView;
import com.cyrilmottier.android.greendroid.R;
/**
* Acts as a separator between important {@link ListView} sections. A separator
* display a text on a single line.
*
* @author Cyril Mottier
*/
public class SeparatorItem extends TextItem {
/**
* @hide
*/
public SeparatorItem() {
this(null);
}
/**
* Constructs a SeparatorItem made of the given text
*
* @param text The text for this SeparatorItem
*/
public SeparatorItem(String text) {
super(text);
enabled = false;
}
@Override
public ItemView newView(Context context, ViewGroup parent) {
return createCellFromXml(context, R.layout.gd_separator_item_view, parent);
}
}

@ -1,90 +0,0 @@
/*
* Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
*
* 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 greendroid.widget.item;
import greendroid.widget.itemview.ItemView;
import java.io.IOException;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.ViewGroup;
import com.cyrilmottier.android.greendroid.R;
/**
* A SubtextItem is really similar to a SubtitleItem as it displays a two lines
* of text. The only difference between those two items are the number of lines
* occupied by the content. A SubtextItem may generally used to display a
* description text. As a result, it is disabled by default
*
* @author Cyril Mottier
*/
public class SubtextItem extends TextItem {
/**
* The string that will be displayed above the title of the item (possibly
* on several lines).
*/
public String subtext;
/**
* @hide
*/
public SubtextItem() {
this(null);
}
/**
* @hide
*/
public SubtextItem(String text) {
this(text, null);
}
/**
* Constructs a new SubtextItem
*
* @param text The main text for this item
* @param subtext The subtext
*/
public SubtextItem(String text, String subtext) {
super(text);
this.subtext = subtext;
enabled = false;
}
@Override
public ItemView newView(Context context, ViewGroup parent) {
return createCellFromXml(context, R.layout.gd_subtext_item_view, parent);
}
@Override
public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs) throws XmlPullParserException,
IOException {
super.inflate(r, parser, attrs);
TypedArray a = r.obtainAttributes(attrs, R.styleable.SubtextItem);
subtext = a.getString(R.styleable.SubtextItem_subtext);
a.recycle();
}
}

@ -1,79 +0,0 @@
/*
* Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
*
* 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 greendroid.widget.item;
import greendroid.widget.itemview.ItemView;
import java.io.IOException;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.ViewGroup;
import com.cyrilmottier.android.greendroid.R;
/**
* An Item that contains two Strings : a text and a subtitle. The representation
* of this Item is a view containing two lines of text. Uf you want to be sure,
* the subtitle can occupy more than a single line, please use a
* {@link SubtextItem}
*
* @author Cyril Mottier
*/
public class SubtitleItem extends TextItem {
/**
* The subtitle of this item
*/
public String subtitle;
/**
* @hide
*/
public SubtitleItem() {
}
/**
* Constructs a new SubtitleItem with the specified text and subtitle.
*
* @param text The text for this item
* @param subtitle The item's subtitle
*/
public SubtitleItem(String text, String subtitle) {
super(text);
this.subtitle = subtitle;
}
@Override
public ItemView newView(Context context, ViewGroup parent) {
return createCellFromXml(context, R.layout.gd_subtitle_item_view, parent);
}
@Override
public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs) throws XmlPullParserException,
IOException {
super.inflate(r, parser, attrs);
TypedArray a = r.obtainAttributes(attrs, R.styleable.SubtitleItem);
subtitle = a.getString(R.styleable.SubtitleItem_gdsubtitle);
a.recycle();
}
}

@ -1,73 +0,0 @@
/*
* Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
*
* 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 greendroid.widget.item;
import greendroid.widget.itemview.ItemView;
import java.io.IOException;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.ViewGroup;
import com.cyrilmottier.android.greendroid.R;
/**
* A TextItem is a very basic item that only contains a single text. This text
* will be displayed on a single line onto the screen.
*
* @author Cyril Mottier
*/
public class TextItem extends Item {
/**
* The item's text.
*/
public String text;
public TextItem() {
}
/**
* Constructs a new TextItem with the specified text.
*
* @param text The text used to create this item.
*/
public TextItem(String text) {
this.text = text;
}
@Override
public ItemView newView(Context context, ViewGroup parent) {
return createCellFromXml(context, R.layout.gd_text_item_view, parent);
}
@Override
public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs) throws XmlPullParserException,
IOException {
super.inflate(r, parser, attrs);
TypedArray a = r.obtainAttributes(attrs, R.styleable.TextItem);
text = a.getString(R.styleable.TextItem_text);
a.recycle();
}
}

@ -1,79 +0,0 @@
/*
* Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
*
* 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 greendroid.widget.item;
import greendroid.widget.itemview.ItemView;
import java.io.IOException;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.ViewGroup;
import com.cyrilmottier.android.greendroid.R;
/**
* A ThumbnailItem item is a complex item that wraps a drawable and two strings
* : a title and a subtitle. The representation of that item is quite common to
* Android users: The drawable is on the left of the item view and on the right
* the title and the subtitle are displayed like a {@link SubtitleItem}.
*
* @author Cyril Mottier
*/
public class ThumbnailItem extends SubtitleItem {
/**
* The resource ID for the drawable.
*/
public int drawableId;
/**
* @hide
*/
public ThumbnailItem() {
}
/**
* @param text
* @param subtitle
* @param drawableId
*/
public ThumbnailItem(String text, String subtitle, int drawableId) {
super(text, subtitle);
this.drawableId = drawableId;
}
@Override
public ItemView newView(Context context, ViewGroup parent) {
return createCellFromXml(context, R.layout.gd_thumbnail_item_view, parent);
}
@Override
public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs) throws XmlPullParserException,
IOException {
super.inflate(r, parser, attrs);
TypedArray a = r.obtainAttributes(attrs, R.styleable.ThumbnailItem);
drawableId = a.getResourceId(R.styleable.ThumbnailItem_thumbnail, drawableId);
a.recycle();
}
}

@ -1,45 +0,0 @@
/*
* Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
*
* 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 greendroid.widget.itemview;
import greendroid.widget.item.Item;
import greendroid.widget.item.TextItem;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.TextView;
public class DescriptionItemView extends TextView implements ItemView {
public DescriptionItemView(Context context) {
this(context, null);
}
public DescriptionItemView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public DescriptionItemView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public void prepareItemView() {
}
public void setObject(Item item) {
setText(((TextItem) item).text);
}
}

@ -1,60 +0,0 @@
/*
* Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
*
* 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 greendroid.widget.itemview;
import greendroid.widget.item.DrawableItem;
import greendroid.widget.item.Item;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.cyrilmottier.android.greendroid.R;
public class DrawableItemView extends LinearLayout implements ItemView {
private TextView mTextView;
private ImageView mImageView;
public DrawableItemView(Context context) {
this(context, null);
}
public DrawableItemView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void prepareItemView() {
mTextView = (TextView) findViewById(R.id.gd_text);
mImageView = (ImageView) findViewById(R.id.gd_drawable);
}
public void setObject(Item object) {
final DrawableItem item = (DrawableItem) object;
mTextView.setText(item.text);
final int drawableId = item.drawableId;
if (drawableId == 0) {
mImageView.setVisibility(View.GONE);
} else {
mImageView.setVisibility(View.VISIBLE);
mImageView.setImageResource(drawableId);
}
}
}

@ -1,26 +0,0 @@
/*
* Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
*
* 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 greendroid.widget.itemview;
import greendroid.widget.item.Item;
public interface ItemView {
void prepareItemView();
void setObject(Item item);
}

@ -1,45 +0,0 @@
/*
* Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
*
* 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 greendroid.widget.itemview;
import greendroid.widget.item.Item;
import greendroid.widget.item.LongTextItem;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.TextView;
public class LongTextItemView extends TextView implements ItemView {
public LongTextItemView(Context context) {
this(context, null);
}
public LongTextItemView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public LongTextItemView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public void prepareItemView() {
}
public void setObject(Item item) {
setText(((LongTextItem) item).text);
}
}

@ -1,57 +0,0 @@
/*
* Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
*
* 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 greendroid.widget.itemview;
import greendroid.widget.item.Item;
import greendroid.widget.item.ProgressItem;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.cyrilmottier.android.greendroid.R;
public class ProgressItemView extends FrameLayout implements ItemView {
private ProgressBar mProgressBar;
private TextView mTextView;
public ProgressItemView(Context context) {
this(context, null);
}
public ProgressItemView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ProgressItemView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public void prepareItemView() {
mProgressBar = (ProgressBar) findViewById(R.id.gd_progress_bar);
mTextView = (TextView) findViewById(R.id.gd_text);
}
public void setObject(Item object) {
final ProgressItem item = (ProgressItem) object;
mProgressBar.setVisibility(item.isInProgress ? View.VISIBLE : View.GONE);
mTextView.setText(item.text);
}
}

@ -1,46 +0,0 @@
/*
* Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
*
* 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 greendroid.widget.itemview;
import greendroid.widget.item.Item;
import greendroid.widget.item.TextItem;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.TextView;
public class SeparatorItemView extends TextView implements ItemView {
public SeparatorItemView(Context context) {
this(context, null);
}
public SeparatorItemView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SeparatorItemView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public void prepareItemView() {
}
public void setObject(Item object) {
final TextItem item = (TextItem) object;
setText(item.text);
}
}

@ -1,51 +0,0 @@
/*
* Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
*
* 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 greendroid.widget.itemview;
import greendroid.widget.item.Item;
import greendroid.widget.item.SubtextItem;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.cyrilmottier.android.greendroid.R;
public class SubtextItemView extends LinearLayout implements ItemView {
private TextView mTextView;
private TextView mSubtextView;
public SubtextItemView(Context context) {
this(context, null);
}
public SubtextItemView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void prepareItemView() {
mTextView = (TextView) findViewById(R.id.gd_text);
mSubtextView = (TextView) findViewById(R.id.gd_subtext);
}
public void setObject(Item object) {
final SubtextItem item = (SubtextItem) object;
mTextView.setText(item.text);
mSubtextView.setText(item.subtext);
}
}

@ -1,51 +0,0 @@
/*
* Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
*
* 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 greendroid.widget.itemview;
import greendroid.widget.item.Item;
import greendroid.widget.item.SubtitleItem;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.cyrilmottier.android.greendroid.R;
public class SubtitleItemView extends LinearLayout implements ItemView {
private TextView mTextView;
private TextView mSubtitleView;
public SubtitleItemView(Context context) {
this(context, null);
}
public SubtitleItemView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void prepareItemView() {
mTextView = (TextView) findViewById(R.id.gd_text);
mSubtitleView = (TextView) findViewById(R.id.gd_subtitle);
}
public void setObject(Item object) {
final SubtitleItem item = (SubtitleItem) object;
mTextView.setText(item.text);
mSubtitleView.setText(item.subtitle);
}
}

@ -1,45 +0,0 @@
/*
* Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
*
* 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 greendroid.widget.itemview;
import greendroid.widget.item.Item;
import greendroid.widget.item.TextItem;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.TextView;
public class TextItemView extends TextView implements ItemView {
public TextItemView(Context context) {
this(context, null);
}
public TextItemView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public TextItemView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public void prepareItemView() {
}
public void setObject(Item object) {
setText(((TextItem) object).text);
}
}

@ -1,59 +0,0 @@
/*
* Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
*
* 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 greendroid.widget.itemview;
import greendroid.widget.item.Item;
import greendroid.widget.item.ThumbnailItem;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.cyrilmottier.android.greendroid.R;
public class ThumbnailItemView extends RelativeLayout implements ItemView {
private TextView mTextView;
private TextView mSubtitleView;
private ImageView mThumbnailView;
public ThumbnailItemView(Context context) {
this(context, null);
}
public ThumbnailItemView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ThumbnailItemView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public void prepareItemView() {
mTextView = (TextView) findViewById(R.id.gd_text);
mSubtitleView = (TextView) findViewById(R.id.gd_subtitle);
mThumbnailView = (ImageView) findViewById(R.id.gd_thumbnail);
}
public void setObject(Item object) {
final ThumbnailItem item = (ThumbnailItem) object;
mTextView.setText(item.text);
mSubtitleView.setText(item.subtitle);
mThumbnailView.setImageResource(item.drawableId);
}
}

@ -1,38 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
** Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
**
** 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.
*/
-->
<set
xmlns:android="http://schemas.android.com/apk/res/android">
<scale
android:fromXScale="0.3"
android:toXScale="1.0"
android:fromYScale="0.3"
android:toYScale="1.0"
android:pivotX="50%"
android:pivotY="100%"
android:duration="@android:integer/config_shortAnimTime" />
<alpha
android:interpolator="@android:anim/decelerate_interpolator"
android:fromAlpha="0.0"
android:toAlpha="1.0"
android:duration="@android:integer/config_shortAnimTime" />
</set>

@ -1,38 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
** Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
**
** 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.
*/
-->
<set
xmlns:android="http://schemas.android.com/apk/res/android">
<scale
android:fromXScale="0.3"
android:toXScale="1.0"
android:fromYScale="0.3"
android:toYScale="1.0"
android:pivotX="0%"
android:pivotY="50%"
android:duration="@android:integer/config_shortAnimTime" />
<alpha
android:interpolator="@android:anim/decelerate_interpolator"
android:fromAlpha="0.0"
android:toAlpha="1.0"
android:duration="@android:integer/config_shortAnimTime" />
</set>

@ -1,38 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
** Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
**
** 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.
*/
-->
<set
xmlns:android="http://schemas.android.com/apk/res/android">
<scale
android:fromXScale="0.3"
android:toXScale="1.0"
android:fromYScale="0.3"
android:toYScale="1.0"
android:pivotX="100%"
android:pivotY="50%"
android:duration="@android:integer/config_shortAnimTime" />
<alpha
android:interpolator="@android:anim/decelerate_interpolator"
android:fromAlpha="0.0"
android:toAlpha="1.0"
android:duration="@android:integer/config_shortAnimTime" />
</set>

@ -1,38 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
** Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
**
** 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.
*/
-->
<set
xmlns:android="http://schemas.android.com/apk/res/android">
<scale
android:fromXScale="0.3"
android:toXScale="1.0"
android:fromYScale="0.3"
android:toYScale="1.0"
android:pivotX="50%"
android:pivotY="0%"
android:duration="@android:integer/config_shortAnimTime" />
<alpha
android:interpolator="@android:anim/decelerate_interpolator"
android:fromAlpha="0.0"
android:toAlpha="1.0"
android:duration="@android:integer/config_shortAnimTime" />
</set>

@ -1,38 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
** Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
**
** 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.
*/
-->
<set
xmlns:android="http://schemas.android.com/apk/res/android">
<scale
android:fromXScale="0.3"
android:toXScale="1.0"
android:fromYScale="0.3"
android:toYScale="1.0"
android:pivotX="0%"
android:pivotY="0%"
android:duration="@android:integer/config_shortAnimTime" />
<alpha
android:interpolator="@android:anim/decelerate_interpolator"
android:fromAlpha="0.0"
android:toAlpha="1.0"
android:duration="@android:integer/config_shortAnimTime" />
</set>

@ -1,38 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
** Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
**
** 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.
*/
-->
<set
xmlns:android="http://schemas.android.com/apk/res/android">
<scale
android:fromXScale="0.3"
android:toXScale="1.0"
android:fromYScale="0.3"
android:toYScale="1.0"
android:pivotX="100%"
android:pivotY="0%"
android:duration="@android:integer/config_shortAnimTime" />
<alpha
android:interpolator="@android:anim/decelerate_interpolator"
android:fromAlpha="0.0"
android:toAlpha="1.0"
android:duration="@android:integer/config_shortAnimTime" />
</set>

@ -1,24 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
** Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
**
** 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.
*/
-->
<translate
xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXDelta="100%p"
android:toXDelta="0"
android:duration="325" />

@ -1,38 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
** Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
**
** 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.
*/
-->
<set
xmlns:android="http://schemas.android.com/apk/res/android">
<scale
android:fromXScale="1.0"
android:toXScale="0.3"
android:fromYScale="1.0"
android:toYScale="0.3"
android:pivotX="50%"
android:pivotY="0%"
android:duration="@android:integer/config_shortAnimTime" />
<alpha
android:interpolator="@android:anim/accelerate_interpolator"
android:fromAlpha="1.0"
android:toAlpha="0.0"
android:duration="@android:integer/config_shortAnimTime" />
</set>

@ -1,38 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
** Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
**
** 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.
*/
-->
<set
xmlns:android="http://schemas.android.com/apk/res/android">
<scale
android:fromXScale="1.0"
android:toXScale="0.3"
android:fromYScale="1.0"
android:toYScale="0.3"
android:pivotX="100%"
android:pivotY="0%"
android:duration="@android:integer/config_shortAnimTime" />
<alpha
android:interpolator="@android:anim/accelerate_interpolator"
android:fromAlpha="1.0"
android:toAlpha="0.0"
android:duration="@android:integer/config_shortAnimTime" />
</set>

@ -1,38 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
** Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
**
** 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.
*/
-->
<set
xmlns:android="http://schemas.android.com/apk/res/android">
<scale
android:fromXScale="1.0"
android:toXScale="0.3"
android:fromYScale="1.0"
android:toYScale="0.3"
android:pivotX="0%"
android:pivotY="0%"
android:duration="@android:integer/config_shortAnimTime" />
<alpha
android:interpolator="@android:anim/accelerate_interpolator"
android:fromAlpha="1.0"
android:toAlpha="0.0"
android:duration="@android:integer/config_shortAnimTime" />
</set>

@ -1,38 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
** Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
**
** 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.
*/
-->
<set
xmlns:android="http://schemas.android.com/apk/res/android">
<scale
android:fromXScale="1.0"
android:toXScale="0.3"
android:fromYScale="1.0"
android:toYScale="0.3"
android:pivotX="50%"
android:pivotY="100%"
android:duration="@android:integer/config_shortAnimTime" />
<alpha
android:interpolator="@android:anim/accelerate_interpolator"
android:fromAlpha="1.0"
android:toAlpha="0.0"
android:duration="@android:integer/config_shortAnimTime" />
</set>

@ -1,38 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
** Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
**
** 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.
*/
-->
<set
xmlns:android="http://schemas.android.com/apk/res/android">
<scale
android:fromXScale="1.0"
android:toXScale="0.3"
android:fromYScale="1.0"
android:toYScale="0.3"
android:pivotX="100%"
android:pivotY="100%"
android:duration="@android:integer/config_shortAnimTime" />
<alpha
android:interpolator="@android:anim/accelerate_interpolator"
android:fromAlpha="1.0"
android:toAlpha="0.0"
android:duration="@android:integer/config_shortAnimTime" />
</set>

@ -1,38 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
** Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
**
** 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.
*/
-->
<set
xmlns:android="http://schemas.android.com/apk/res/android">
<scale
android:fromXScale="1.0"
android:toXScale="0.3"
android:fromYScale="1.0"
android:toYScale="0.3"
android:pivotX="0%"
android:pivotY="100%"
android:duration="@android:integer/config_shortAnimTime" />
<alpha
android:interpolator="@android:anim/accelerate_interpolator"
android:fromAlpha="1.0"
android:toAlpha="0.0"
android:duration="@android:integer/config_shortAnimTime" />
</set>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 545 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 674 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 550 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 491 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 340 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 461 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 575 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 425 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 479 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 253 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 258 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 246 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 591 B

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save