Merge and resolve conflicts from upstream/master

pull/14/head
Sam Bosley 12 years ago
commit c1bbcdc766

@ -140,6 +140,11 @@ public abstract class Property<TYPE> extends Field implements Cloneable {
PropertyVisitor<RETURN, PARAMETER> visitor, PARAMETER data) {
return visitor.visitInteger(this, data);
}
@Override
public IntegerProperty as(String newAlias) {
return (IntegerProperty) super.as(newAlias);
}
}
/**

@ -244,20 +244,14 @@ public class DateUtilities {
return DateUtilities.getRelativeDay(context, date, true);
}
private static final Calendar calendar = Calendar.getInstance();
public static long getStartOfDay(long time) {
Date date = new Date(time);
date.setHours(0);
date.setMinutes(0);
date.setSeconds(0);
return date.getTime();
}
public static long getEndOfDay(long time) {
Date date = new Date(time);
date.setHours(23);
date.setMinutes(59);
date.setSeconds(59);
return date.getTime();
calendar.setTimeInMillis(time);
calendar.set(Calendar.HOUR, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
return calendar.getTimeInMillis();
}
private static long clearTime(Date date) {

@ -6,9 +6,7 @@
package com.todoroo.astrid.api;
import android.app.PendingIntent;
import android.graphics.Bitmap;
import android.os.Parcel;
import android.os.Parcelable;
import android.graphics.drawable.BitmapDrawable;
/**
* Represents an intent that can be called on a task
@ -16,7 +14,7 @@ import android.os.Parcelable;
* @author Tim Su <tim@todoroo.com>
*
*/
public class TaskAction implements Parcelable {
public class TaskAction {
/**
* Label
@ -31,7 +29,7 @@ public class TaskAction implements Parcelable {
/**
* Quick action icon
*/
public Bitmap icon = null;
public BitmapDrawable icon = null;
/**
* Quick action drawable resource
@ -46,7 +44,7 @@ public class TaskAction implements Parcelable {
* @param intent
* intent to invoke. {@link #EXTRAS_TASK_ID} will be passed
*/
public TaskAction(String text, PendingIntent intent, Bitmap icon) {
public TaskAction(String text, PendingIntent intent, BitmapDrawable icon) {
super();
this.text = text;
this.intent = intent;
@ -61,38 +59,38 @@ public class TaskAction implements Parcelable {
public int describeContents() {
return 0;
}
/**
* {@inheritDoc}
*/
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(text);
dest.writeParcelable(intent, 0);
dest.writeParcelable(icon, 0);
dest.writeInt(drawable);
}
/**
* Parcelable creator
*/
public static final Parcelable.Creator<TaskAction> CREATOR = new Parcelable.Creator<TaskAction>() {
/**
* {@inheritDoc}
*/
public TaskAction createFromParcel(Parcel source) {
TaskAction action = new TaskAction(source.readString(),
(PendingIntent)source.readParcelable(PendingIntent.class.getClassLoader()),
(Bitmap)source.readParcelable(Bitmap.class.getClassLoader()));
action.drawable = source.readInt();
return action;
}
/**
* {@inheritDoc}
*/
public TaskAction[] newArray(int size) {
return new TaskAction[size];
};
};
//
// /**
// * {@inheritDoc}
// */
// public void writeToParcel(Parcel dest, int flags) {
// dest.writeString(text);
// dest.writeParcelable(intent, 0);
// dest.writeParcelable(icon, 0);
// dest.writeInt(drawable);
// }
//
// /**
// * Parcelable creator
// */
// public static final Parcelable.Creator<TaskAction> CREATOR = new Parcelable.Creator<TaskAction>() {
// /**
// * {@inheritDoc}
// */
// public TaskAction createFromParcel(Parcel source) {
// TaskAction action = new TaskAction(source.readString(),
// (PendingIntent)source.readParcelable(PendingIntent.class.getClassLoader()),
// (Bitmap)source.readParcelable(Bitmap.class.getClassLoader()));
// action.drawable = source.readInt();
// return action;
// }
//
// /**
// * {@inheritDoc}
// */
// public TaskAction[] newArray(int size) {
// return new TaskAction[size];
// };
// };
}

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
<!--
** Copyright (c) 2012 Todoroo Inc
**
** See the file "LICENSE" for the full license governing this code.
** See the file "LICENSE" for the full license governing this code.
-->
<project name="astrid" default="help">
@ -59,10 +59,10 @@
<!-- extension targets. Uncomment the ones where you want to do custom work
in between standard targets -->
<target name="-set-mode-check" depends="">
<fail if="build.is.mode.set"
message="Cannot run two different modes at the same time. If you are running more than one debug/release/instrument type targets, call them from different Ant calls." />
</target>
<target name="-set-mode-check" depends="">
<fail if="build.is.mode.set"
message="Cannot run two different modes at the same time. If you are running more than one debug/release/instrument type targets, call them from different Ant calls." />
</target>
<target name="-pre-build" depends="get-version, copy-sources, setup-lite, updatekeys, updatekeys-release, update-market-strategy">
<mkdir dir="gen" />
@ -71,7 +71,7 @@
</target>
<target name="-post-astrid-build" depends="teardown-lite" />
<target name="copy-sources">
<delete dir="${source.dir}" />
<mkdir dir="${source.dir}" />
@ -96,7 +96,7 @@
select="\1" />
<echo message="Astrid: version ${manifest.version.code}, named ${manifest.version.name}" />
</target>
<target name="warnings">
<echo>====== context classes without setContext =====</echo>
<exec executable="sh">
@ -123,7 +123,7 @@
<replaceregexp file="${source.dir}/com/todoroo/astrid/actfm/sync/ActFmInvoker.java"
match="APP_SECRET = .*"
replace="APP_SECRET = &quot;${apikey.actfm.secret}&quot;;" />
<replaceregexp file="${source.dir}/com/todoroo/astrid/taskrabbit/TaskRabbitActivity.java"
match="TASK_RABBIT_CLIENT_ID = .*"
replace="TASK_RABBIT_CLIENT_ID = &quot;${apikey.taskrabbit.clientid}&quot;;" />
@ -133,31 +133,31 @@
<replaceregexp file="${source.dir}/com/todoroo/astrid/taskrabbit/TaskRabbitActivity.java"
match="TASK_RABBIT_URL = .*"
replace="TASK_RABBIT_URL = &quot;${apikey.taskrabbit.url}&quot;;" />
<replaceregexp file="${source.dir}/com/todoroo/astrid/taskrabbit/TaskRabbitMapActivity.java"
match="MAPS_API_KEY = .*"
replace="MAPS_API_KEY = &quot;${apikey.maps}&quot;;" />
<replaceregexp file="${source.dir}/com/todoroo/astrid/gtasks/api/GtasksInvoker.java"
match="API_KEY = .*"
replace="API_KEY = &quot;${apikey.gtasks}&quot;;" />
<replaceregexp file="${source.dir}/com/todoroo/astrid/utility/Constants.java"
match="AWS_SECRET_KEY_ID = .*"
replace="AWS_SECRET_KEY_ID = &quot;${apikey.amazon.secret}&quot;;" />
<replaceregexp file="${source.dir}/com/todoroo/astrid/service/abtesting/ABTestInvoker.java"
match="API_KEY = .*"
replace="API_KEY = &quot;${apikey.analytics.id}&quot;;" />
<replaceregexp file="${source.dir}/com/todoroo/astrid/service/abtesting/ABTestInvoker.java"
match="API_SECRET = .*"
replace="API_SECRET = &quot;${apikey.analytics.secret}&quot;;" />
<antcall target="updatekeys-lite" />
<replaceregexp file="${source.dir}/com/todoroo/astrid/billing/BillingConstants.java"
match="PUB_KEY_REPLACE_CHAR = .*"
replace="PUB_KEY_REPLACE_CHAR = &#39;${apikey.googleplay.replacechar}&#39;;" />
<replaceregexp file="${source.dir}/com/todoroo/astrid/billing/BillingConstants.java"
match="PUB_KEY_OBFUSCATED = .*"
replace="PUB_KEY_OBFUSCATED = &quot;${apikey.googleplay.pubkey}&quot;;" />
@ -172,11 +172,11 @@
replace="API_SECRET = &quot;${apikey.analytics.lite.secret}&quot;;" />
</target>
<target name="updatekeys-pre" if="pre.astrid" description="use pre.astrid.com">
<target name="updatekeys-pre" if="pre.astrid" description="use pre.astrid-dev.com">
<property file="${apikey.keyfile}" />
<replaceregexp file="${source.dir}/com/todoroo/astrid/actfm/sync/ActFmInvoker.java"
match="URL = .*"
replace="URL = &quot;//pre.astrid.com/api/&quot;;" />
replace="URL = &quot;//pre.astrid-dev.com/api/&quot;;" />
</target>
<!-- update api keys that require release signing -->
@ -185,9 +185,9 @@
<property file="${apikey.keyfile}" />
<replaceregexp file="${source.dir}/com/todoroo/astrid/actfm/ActFmLoginActivity.java"
match="APP_ID = .*"
replace="APP_ID = &quot;${apikey.facebook.id}&quot;;" />
replace="APP_ID = &quot;${apikey.facebook.id}&quot;;" />
</target>
<target name="-release-prompt-for-password" description="override to set signature">
<property file="${signjar.passfile}" /> <echo message="${signjar.passfile}" />
@ -201,14 +201,14 @@
<target name="update-market-strategy" if="custom.market.strategy">
<echo message="Changing market strategy to ${custom.market.strategy}" />
<replace token="market://" value="disabled://"
<replace token="market://" value="disabled://"
dir="${source.dir}" />
<replaceregexp file="${source.dir}/com/todoroo/astrid/utility/Constants.java"
match="AndroidMarketStrategy"
replace="${custom.market.strategy}" />
</target>
<target name="obfuscate" depends="-set-debug-files, -set-debug-mode, nodeps, -build-setup,
<target name="obfuscate" depends="-set-debug-files, -set-debug-mode, nodeps, -build-setup,
-set-release-mode, -release-obfuscation-check, -obfuscate" />
<target name="dex" depends="obfuscate, -dex" />
@ -234,14 +234,14 @@
<!-- build lite release package with updated version name -->
<target name="release-lite" depends="clean, set-lite-property, release" />
<target name="debug-lite" depends="clean, set-lite-property, debug" />
<target name="set-lite-property">
<property name="lite.enabled" value="true" />
<subant target="setup-lite">
<fileset file="../api/build.xml"/>
</subant>
</target>
<target name="setup-lite" if="lite.enabled">
<copy file="AndroidManifest.xml" tofile="AndroidManifest_old.xml" />
<replaceregexp file="${source.dir}/com/todoroo/astrid/utility/Constants.java"
@ -300,14 +300,14 @@
replace="ASTRID_DIR = &quot;/astridlite&quot;;"
/>
<move file="${source.dir}/com/timsu/astrid" tofile="${source.dir}/com/todoroo/astridlite" />
<copy todir="res_old">
<fileset dir="res"/>
</copy>
<replace dir="res" token="com.timsu.astrid" value="com.todoroo.astridlite"/>
<replace dir="${source.dir}" token="com.timsu.astrid" value="com.todoroo.astridlite"/>
<replaceregexp match="&gt;(.*\s)task(.*)"
replace="&gt;\1to-do\2"
flags="g">
@ -333,7 +333,7 @@
flags="g"
/>
</target>
<target name="teardown-lite" if="lite.enabled">
<delete dir="res" />
<move file="res_old" tofile="res"/>
@ -342,7 +342,7 @@
<fileset file="../api/build.xml"/>
</subant>
</target>
<!-- build custom unsigned package with updated version name -->
<target name="unsigned-custom" depends="clean">
<fail message="need to set custom.version.name">
@ -458,7 +458,7 @@
location="../release/${ant.project.name}-${manifest.version.code}-${manifest.version.name}-release.apk" />
</else>
</if>
<zipalign-helper in.package="${out.unaligned.file}"
out.package="${out.final.file}" />
<copy file="${out.final.file}" tofile="${out.release.file}" />

@ -9,6 +9,7 @@ import org.json.JSONObject;
import android.app.Activity;
import android.content.Intent;
import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.os.Bundle;
@ -70,6 +71,8 @@ public abstract class CommentsFragment extends ListFragment {
protected final ImageDiskCache imageCache;
protected Resources resources;
@Autowired ActFmSyncService actFmSyncService;
@Autowired ActFmPreferenceService actFmPreferenceService;
@ -136,6 +139,8 @@ public abstract class CommentsFragment extends ListFragment {
addCommentField.setOnTouchListener(onTouch);
setUpUpdateList();
resources = getResources();
}
protected void setUpUpdateList() {

@ -19,6 +19,7 @@ import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Color;
import android.net.Uri;
@ -71,6 +72,7 @@ import com.todoroo.astrid.tags.TagService;
import com.todoroo.astrid.ui.PeopleContainer;
import com.todoroo.astrid.ui.PeopleContainer.ParseSharedException;
import com.todoroo.astrid.ui.PopupControlSet;
import com.todoroo.astrid.utility.ResourceDrawableCache;
public class EditPeopleControlSet extends PopupControlSet {
@ -118,6 +120,8 @@ public class EditPeopleControlSet extends PopupControlSet {
private boolean dontClearAssignedCustom = false;
private final Resources resources;
private final List<AssignedChangedListener> listeners = new LinkedList<AssignedChangedListener>();
public interface AssignedChangedListener {
@ -137,6 +141,7 @@ public class EditPeopleControlSet extends PopupControlSet {
public EditPeopleControlSet(Activity activity, Fragment fragment, int viewLayout, int displayViewLayout, int title, int loginRequestCode) {
super(activity, viewLayout, displayViewLayout, title);
DependencyInjectionService.getInstance().inject(this);
this.resources = activity.getResources();
this.loginRequestCode = loginRequestCode;
this.fragment = fragment;
displayText.setText(activity.getString(R.string.TEA_control_who));
@ -496,7 +501,7 @@ public class EditPeopleControlSet extends PopupControlSet {
ctv.setChecked(false);
}
AsyncImageView image = (AsyncImageView) convertView.findViewById(R.id.person_image);
image.setDefaultImageResource(R.drawable.icn_default_person_image);
image.setDefaultImageDrawable(ResourceDrawableCache.getImageDrawableFromId(resources, R.drawable.icn_default_person_image));
image.setUrl(getItem(position).user.optString("picture"));
if (getItem(position).user.optInt("default_picture", 0) > 0) {
image.setDefaultImageResource(getItem(position).user.optInt("default_picture"));

@ -29,6 +29,7 @@ import com.todoroo.astrid.service.StatisticsConstants;
import com.todoroo.astrid.service.TagDataService;
import com.todoroo.astrid.tags.TagService;
import com.todoroo.astrid.utility.AstridPreferences;
import com.todoroo.astrid.utility.ResourceDrawableCache;
public class TagCommentsFragment extends CommentsFragment {
@ -104,7 +105,7 @@ public class TagCommentsFragment extends CommentsFragment {
AsyncImageView imageView = (AsyncImageView) header.findViewById(R.id.tag_picture);
imageView.setDefaultImageResource(TagService.getDefaultImageIDForTag(tagName));
imageView.setDefaultImageDrawable(ResourceDrawableCache.getImageDrawableFromId(getResources(), TagService.getDefaultImageIDForTag(tagName)));
imageView.setUrl(tagData.getPictureUrl(TagData.PICTURE, RemoteModel.PICTURE_MEDIUM));
}

@ -69,6 +69,7 @@ import com.todoroo.astrid.tags.TagService;
import com.todoroo.astrid.ui.PeopleContainer;
import com.todoroo.astrid.ui.PeopleContainer.ParseSharedException;
import com.todoroo.astrid.utility.AstridPreferences;
import com.todoroo.astrid.utility.ResourceDrawableCache;
import com.todoroo.astrid.welcome.HelpInfoPopover;
public class TagSettingsActivity extends FragmentActivity {
@ -222,7 +223,7 @@ public class TagSettingsActivity extends FragmentActivity {
findViewById(R.id.tag_silenced_container).setVisibility(View.VISIBLE);
}
picture.setDefaultImageResource(TagService.getDefaultImageIDForTag(tagData.getValue(TagData.NAME)));
picture.setDefaultImageDrawable(ResourceDrawableCache.getImageDrawableFromId(getResources(), TagService.getDefaultImageIDForTag(tagData.getValue(TagData.NAME))));
picture.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {

@ -75,6 +75,7 @@ import com.todoroo.astrid.tags.TagMemberMetadata;
import com.todoroo.astrid.tags.TagService.Tag;
import com.todoroo.astrid.utility.AstridPreferences;
import com.todoroo.astrid.utility.Flags;
import com.todoroo.astrid.utility.ResourceDrawableCache;
import com.todoroo.astrid.welcome.HelpInfoPopover;
public class TagViewFragment extends TaskListFragment {
@ -477,9 +478,10 @@ public class TagViewFragment extends TaskListFragment {
image.setLayoutParams(new LinearLayout.LayoutParams((int)(43 * displayMetrics.density),
(int)(43 * displayMetrics.density)));
image.setDefaultImageResource(R.drawable.icn_default_person_image);
image.setDefaultImageDrawable(ResourceDrawableCache.getImageDrawableFromId(resources, R.drawable.icn_default_person_image));
if (Task.USER_ID_UNASSIGNED.equals(Long.toString(member.optLong("id", 0))))
image.setDefaultImageResource(R.drawable.icn_anyone);
image.setDefaultImageDrawable(ResourceDrawableCache.getImageDrawableFromId(resources, R.drawable.icn_anyone));
image.setScaleType(ImageView.ScaleType.FIT_CENTER);
try {

@ -15,7 +15,6 @@ import java.util.Comparator;
import java.util.List;
import java.util.TimeZone;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.message.BasicNameValuePair;
@ -35,6 +34,7 @@ import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.andlib.utility.Pair;
import com.todoroo.andlib.utility.Preferences;
import com.todoroo.astrid.utility.Constants;
import com.twmacinta.util.MD5;
@SuppressWarnings("nls")
public class ActFmInvoker {
@ -287,7 +287,9 @@ public class ActFmInvoker {
}
sigBuilder.append(APP_SECRET);
String signature = DigestUtils.md5Hex(sigBuilder.toString());
MD5 md5 = new MD5();
md5.Update(sigBuilder.toString(), null);
String signature = md5.asHex();
requestBuilder.append("sig").append('=').append(signature);
return requestBuilder.toString();
}

@ -5,7 +5,7 @@
*/
package com.todoroo.astrid.core;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import android.app.PendingIntent;
@ -14,12 +14,10 @@ import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.text.Spannable;
import android.text.TextUtils;
import android.text.style.URLSpan;
import android.text.util.Linkify;
@ -39,51 +37,47 @@ import com.todoroo.astrid.notes.NotesAction;
*/
public class LinkActionExposer {
private PackageManager pm;
public static TaskAction getActionsForTask(Context context, Task task, boolean hasAttachments, boolean hasNotes) {
if (task == null) return null;
public List<TaskAction> getActionsForTask(Context context, Task task, boolean hasAttachments) {
List<TaskAction> result = new ArrayList<TaskAction>();
if (task == null) return result;
String notes = task.getValue(Task.NOTES);
Spannable titleSpan = Spannable.Factory.getInstance().newSpannable(task.getValue(Task.TITLE));
Linkify.addLinks(titleSpan, Linkify.ALL);
URLSpan[] urlSpans = titleSpan.getSpans(0, titleSpan.length(), URLSpan.class);
if(urlSpans.length == 0 && TextUtils.isEmpty(notes) &&
if(urlSpans.length == 0 && !hasNotes &&
!hasAttachments)
return result;
return null;
pm = context.getPackageManager();
PackageManager pm = context.getPackageManager();
for(URLSpan urlSpan : urlSpans) {
String url = urlSpan.getURL();
int start = titleSpan.getSpanStart(urlSpan);
int end = titleSpan.getSpanEnd(urlSpan);
String text = titleSpan.subSequence(start, end).toString();
TaskAction taskAction = createLinkAction(context, task.getId(), url, text);
TaskAction taskAction = createLinkAction(context, task.getId(), url, text, pm);
if (taskAction != null)
result.add(taskAction);
return taskAction;
}
Resources r = context.getResources();
if (hasAttachments) {
Bitmap icon = ((BitmapDrawable) r.getDrawable(R.drawable.action_attachments)).getBitmap();
BitmapDrawable icon = getBitmapDrawable(R.drawable.action_attachments, r);
FilesAction filesAction = new FilesAction("", null, icon); //$NON-NLS-1$
result.add(filesAction);
return filesAction;
}
if (!TextUtils.isEmpty(notes) && !Preferences.getBoolean(R.string.p_showNotes, false)) {
Bitmap icon = ((BitmapDrawable) r.getDrawable(R.drawable.action_notes)).getBitmap();
if (hasNotes && !Preferences.getBoolean(R.string.p_showNotes, false)) {
BitmapDrawable icon = getBitmapDrawable(R.drawable.action_notes, r);
NotesAction notesAction = new NotesAction("", null, icon); //$NON-NLS-1$
result.add(notesAction);
return notesAction;
}
return result;
return null;
}
@SuppressWarnings("nls")
private TaskAction createLinkAction(Context context, long id, String url, String text) {
private static TaskAction createLinkAction(Context context, long id, String url, String text, PackageManager pm) {
Intent itemIntent = new Intent(Intent.ACTION_VIEW);
itemIntent.setData(Uri.parse(url));
List<ResolveInfo> resolveInfoList = pm.queryIntentActivities(itemIntent, 0);
@ -107,20 +101,31 @@ public class LinkActionExposer {
Resources r = context.getResources();
Drawable icon;
if (url.startsWith("mailto")) {
icon = r.getDrawable(R.drawable.action_mail);
icon = getBitmapDrawable(R.drawable.action_mail, r);
} else if (url.startsWith("tel")) {
icon = r.getDrawable(R.drawable.action_tel);
icon = getBitmapDrawable(R.drawable.action_tel, r);
} else {
icon = r.getDrawable(R.drawable.action_web);
icon = getBitmapDrawable(R.drawable.action_web, r);
}
Bitmap bitmap = ((BitmapDrawable)icon).getBitmap();
if(text.length() > 15)
text = text.substring(0, 12) + "..."; //$NON-NLS-1$
TaskAction action = new TaskAction(text,
PendingIntent.getActivity(context, (int)id, actionIntent, 0), bitmap);
PendingIntent.getActivity(context, (int)id, actionIntent, 0), (BitmapDrawable)icon);
return action;
}
private static final HashMap<Integer, BitmapDrawable> IMAGE_CACHE = new HashMap<Integer, BitmapDrawable>();
private static BitmapDrawable getBitmapDrawable(int resId, Resources resources) {
if (IMAGE_CACHE.containsKey(resId))
return IMAGE_CACHE.get(resId);
else {
BitmapDrawable b = (BitmapDrawable) resources.getDrawable(resId);
IMAGE_CACHE.put(resId, b);
return b;
}
}
}

@ -6,40 +6,38 @@
package com.todoroo.astrid.files;
import android.app.PendingIntent;
import android.graphics.Bitmap;
import android.os.Parcel;
import android.os.Parcelable;
import android.graphics.drawable.BitmapDrawable;
import com.todoroo.astrid.api.TaskAction;
public class FilesAction extends TaskAction {
public FilesAction(String text, PendingIntent intent, Bitmap icon) {
public FilesAction(String text, PendingIntent intent, BitmapDrawable icon) {
super(text, intent, icon);
}
/**
* Parcelable creator
*/
@SuppressWarnings("hiding")
public static final Parcelable.Creator<FilesAction> CREATOR = new Parcelable.Creator<FilesAction>() {
/**
* {@inheritDoc}
*/
public FilesAction createFromParcel(Parcel source) {
FilesAction action = new FilesAction(source.readString(),
(PendingIntent)source.readParcelable(PendingIntent.class.getClassLoader()),
(Bitmap)source.readParcelable(Bitmap.class.getClassLoader()));
action.drawable = source.readInt();
return action;
}
/**
* {@inheritDoc}
*/
public FilesAction[] newArray(int size) {
return new FilesAction[size];
};
};
//
// /**
// * Parcelable creator
// */
// @SuppressWarnings("hiding")
// public static final Parcelable.Creator<FilesAction> CREATOR = new Parcelable.Creator<FilesAction>() {
// /**
// * {@inheritDoc}
// */
// public FilesAction createFromParcel(Parcel source) {
// FilesAction action = new FilesAction(source.readString(),
// (PendingIntent)source.readParcelable(PendingIntent.class.getClassLoader()),
// (Bitmap)source.readParcelable(Bitmap.class.getClassLoader()));
// action.drawable = source.readInt();
// return action;
// }
//
// /**
// * {@inheritDoc}
// */
// public FilesAction[] newArray(int size) {
// return new FilesAction[size];
// };
// };
}

@ -14,6 +14,7 @@ import java.util.List;
import android.app.Activity;
import android.content.Intent;
import android.content.res.Resources;
import android.database.sqlite.SQLiteException;
import android.graphics.Bitmap;
import android.graphics.Color;
@ -73,6 +74,7 @@ import com.todoroo.astrid.service.StartupService;
import com.todoroo.astrid.service.StatisticsConstants;
import com.todoroo.astrid.service.StatisticsService;
import com.todoroo.astrid.timers.TimerActionControlSet.TimerActionListener;
import com.todoroo.astrid.utility.ResourceDrawableCache;
public class EditNoteActivity extends LinearLayout implements TimerActionListener {
@ -99,7 +101,11 @@ public class EditNoteActivity extends LinearLayout implements TimerActionListene
private ImageButton pictureButton;
private Bitmap pendingCommentPicture = null;
private final Fragment fragment;
private final AstridActivity activity;
private final Resources resources;
private final ImageDiskCache imageCache;
private final int cameraButton;
private final String linkColor;
@ -118,8 +124,12 @@ public class EditNoteActivity extends LinearLayout implements TimerActionListene
imageCache = ImageDiskCache.getInstance();
this.fragment = fragment;
this.activity = (AstridActivity) fragment.getActivity();
this.resources = fragment.getResources();
linkColor = UpdateAdapter.getLinkColor(fragment);
cameraButton = getDefaultCameraButton();
@ -367,7 +377,7 @@ public class EditNoteActivity extends LinearLayout implements TimerActionListene
public synchronized void bindView(View view, NoteOrUpdate item) {
// picture
final AsyncImageView pictureView = (AsyncImageView)view.findViewById(R.id.picture); {
pictureView.setDefaultImageResource(R.drawable.icn_default_person_image);
pictureView.setDefaultImageDrawable(ResourceDrawableCache.getImageDrawableFromId(resources, R.drawable.icn_default_person_image));
pictureView.setUrl(item.picture);
}

@ -6,40 +6,38 @@
package com.todoroo.astrid.notes;
import android.app.PendingIntent;
import android.graphics.Bitmap;
import android.os.Parcel;
import android.os.Parcelable;
import android.graphics.drawable.BitmapDrawable;
import com.todoroo.astrid.api.TaskAction;
public class NotesAction extends TaskAction {
public NotesAction(String text, PendingIntent intent, Bitmap icon) {
public NotesAction(String text, PendingIntent intent, BitmapDrawable icon) {
super(text, intent, icon);
}
/**
* Parcelable creator
*/
@SuppressWarnings("hiding")
public static final Parcelable.Creator<NotesAction> CREATOR = new Parcelable.Creator<NotesAction>() {
/**
* {@inheritDoc}
*/
public NotesAction createFromParcel(Parcel source) {
NotesAction action = new NotesAction(source.readString(),
(PendingIntent)source.readParcelable(PendingIntent.class.getClassLoader()),
(Bitmap)source.readParcelable(Bitmap.class.getClassLoader()));
action.drawable = source.readInt();
return action;
}
/**
* {@inheritDoc}
*/
public NotesAction[] newArray(int size) {
return new NotesAction[size];
};
};
//
// /**
// * Parcelable creator
// */
// @SuppressWarnings("hiding")
// public static final Parcelable.Creator<NotesAction> CREATOR = new Parcelable.Creator<NotesAction>() {
// /**
// * {@inheritDoc}
// */
// public NotesAction createFromParcel(Parcel source) {
// NotesAction action = new NotesAction(source.readString(),
// (PendingIntent)source.readParcelable(PendingIntent.class.getClassLoader()),
// (Bitmap)source.readParcelable(Bitmap.class.getClassLoader()));
// action.drawable = source.readInt();
// return action;
// }
//
// /**
// * {@inheritDoc}
// */
// public NotesAction[] newArray(int size) {
// return new NotesAction[size];
// };
// };
}

@ -27,6 +27,7 @@ import com.todoroo.astrid.data.User;
import com.todoroo.astrid.helper.AsyncImageView;
import com.todoroo.astrid.service.SyncV2Service;
import com.todoroo.astrid.service.ThemeService;
import com.todoroo.astrid.utility.ResourceDrawableCache;
public class PersonViewFragment extends TaskListFragment {
@ -67,8 +68,9 @@ public class PersonViewFragment extends TaskListFragment {
private void setupUserHeader() {
if (user != null) {
userImage.setDefaultImageResource(R.drawable.icn_default_person_image);
userImage.setDefaultImageDrawable(ResourceDrawableCache.getImageDrawableFromId(resources, R.drawable.icn_default_person_image));
userImage.setUrl(user.getPictureUrl(User.PICTURE, RemoteModel.PICTURE_MEDIUM));
userSubtitle.setText(getUserSubtitleText());
setupUserStatusButton();
} else {

@ -13,7 +13,6 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import org.apache.commons.codec.digest.DigestUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
@ -21,6 +20,7 @@ import org.json.JSONObject;
import android.text.TextUtils;
import com.todoroo.andlib.utility.Pair;
import com.twmacinta.util.MD5;
@SuppressWarnings("nls")
public class ProducteevInvoker {
@ -657,7 +657,9 @@ public class ProducteevInvoker {
}
sigBuilder.append(apiSecret);
String signature = DigestUtils.md5Hex(sigBuilder.toString());
MD5 md5 = new MD5();
md5.Update(sigBuilder.toString(), null);
String signature = md5.asHex();
requestBuilder.append("api_sig").append('=').append(signature);
return requestBuilder.toString();
}

@ -17,6 +17,7 @@ import android.app.Activity;
import android.app.Dialog;
import android.app.TimePickerDialog.OnTimeSetListener;
import android.content.Intent;
import android.content.res.Resources;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.view.View;
@ -50,6 +51,7 @@ import com.todoroo.astrid.service.StatisticsService;
import com.todoroo.astrid.service.TaskService;
import com.todoroo.astrid.tags.TagMemberMetadata;
import com.todoroo.astrid.tags.TagService;
import com.todoroo.astrid.utility.ResourceDrawableCache;
/**
* A dialog that shows your task reminder
@ -169,6 +171,7 @@ public class ReminderDialog extends Dialog {
private void addFacesToReminder(Activity activity, Task task) {
if (task == null)
return;
Resources resources = activity.getResources();
LinkedHashSet<String> pictureUrls = new LinkedHashSet<String>();
AtomicBoolean isSharedTask = new AtomicBoolean(false);
@ -188,7 +191,7 @@ public class ReminderDialog extends Dialog {
int count = 0;
for (String url : pictureUrls) {
AsyncImageView image = new AsyncImageView(activity);
image.setDefaultImageResource(R.drawable.icn_default_person_image);
image.setDefaultImageDrawable(ResourceDrawableCache.getImageDrawableFromId(resources, R.drawable.icn_default_person_image));
image.setUrl(url);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams((int) (35 * metrics.density), (int) (35 * metrics.density));

@ -33,6 +33,7 @@ import com.todoroo.astrid.service.TagDataService;
import com.todoroo.astrid.tags.TagFilterExposer;
import com.todoroo.astrid.tags.TagService.Tag;
import com.todoroo.astrid.utility.Flags;
import com.todoroo.astrid.utility.ResourceDrawableCache;
public class FeaturedTaskListFragment extends TagViewFragment {
@ -93,7 +94,7 @@ public class FeaturedTaskListFragment extends TagViewFragment {
String imageUrl = tagData.getPictureUrl(TagData.PICTURE, RemoteModel.PICTURE_MEDIUM);
if (!TextUtils.isEmpty(imageUrl)) {
imageView.setVisibility(View.VISIBLE);
imageView.setDefaultImageResource(R.drawable.default_list_0);
imageView.setDefaultImageDrawable(ResourceDrawableCache.getImageDrawableFromId(resources, R.drawable.default_list_0));
imageView.setUrl(imageUrl);
} else {
imageView.setVisibility(View.GONE);

@ -66,7 +66,7 @@
<TextView
android:id="@+id/title"
style="@style/TextAppearance.TAd_ItemTitle"
android:layout_width="fill_parent"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="100"
android:gravity="center_vertical"
@ -85,7 +85,6 @@
android:id="@+id/dueDate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:gravity="center_vertical|right" />
<ImageView
android:id="@+id/taskActionIcon"

@ -53,6 +53,7 @@
<LinearLayout
android:id="@+id/task_row"
android:baselineAligned="false"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="52dip"
@ -64,7 +65,7 @@
<!-- task name -->
<LinearLayout
android:layout_width="fill_parent"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="100"
android:orientation="vertical"

@ -45,7 +45,7 @@
<TextView
android:id="@+id/title"
style="@style/TextAppearance.TAd_ItemTitle"
android:layout_width="fill_parent"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="100"
android:gravity="center_vertical"

@ -374,9 +374,6 @@
<!-- addtocalendar: labels that map EPr_default_addtocalendar items to calendar selection in settings. -->
<item>-1</item>
</string-array>
<!-- show task decorations (corresponds to showing notes icon in the task adapter) -->
<string name="p_default_showdecorations_key">p_show_decorations</string>
<!-- ============================================================ SYNC == -->

@ -21,6 +21,7 @@ import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.database.Cursor;
import android.database.sqlite.SQLiteException;
import android.graphics.drawable.Drawable;
@ -87,6 +88,7 @@ import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.TagData;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.data.User;
import com.todoroo.astrid.files.FileMetadata;
import com.todoroo.astrid.helper.SyncActionHelper;
import com.todoroo.astrid.helper.TaskListContextMenuExtensionLoader;
import com.todoroo.astrid.helper.TaskListContextMenuExtensionLoader.ContextMenuItem;
@ -187,6 +189,7 @@ public class TaskListFragment extends ListFragment implements OnScrollListener,
new ReminderDebugContextActions.WhenReminder(),
};
protected Resources resources;
protected TaskAdapter taskAdapter = null;
protected DetailReceiver detailReceiver = new DetailReceiver();
protected RefreshReceiver refreshReceiver = new RefreshReceiver();
@ -335,6 +338,7 @@ public class TaskListFragment extends ListFragment implements OnScrollListener,
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// We have a menu item to show in action bar.
resources = getResources();
setHasOptionsMenu(true);
syncActionHelper = new SyncActionHelper(getActivity(), this);
setUpUiComponents();
@ -382,7 +386,7 @@ public class TaskListFragment extends ListFragment implements OnScrollListener,
filter = extras.getParcelable(TOKEN_FILTER);
extras.remove(TOKEN_FILTER); // Otherwise writing this filter to parcel gives infinite recursion
} else {
filter = CoreFilterExposer.buildInboxFilter(getResources());
filter = CoreFilterExposer.buildInboxFilter(resources);
}
filter.setFilterQueryOverride(null);
isInbox = CoreFilterExposer.isInbox(filter);
@ -913,6 +917,9 @@ public class TaskListFragment extends ListFragment implements OnScrollListener,
public static final String USER_IMAGE_JOIN = "for_images"; // //$NON-NLS-1$
public static final String FILE_METADATA_JOIN = "for_actions"; //$NON-NLS-1$
/**
* Fill in the Task List with current items
*
@ -968,11 +975,15 @@ public class TaskListFragment extends ListFragment implements OnScrollListener,
// Eventually, we might consider restructuring things so that this query is constructed elsewhere.
String joinedQuery =
Join.left(Metadata.TABLE.as(TR_METADATA_JOIN),
Criterion.and(Field.field(TR_METADATA_JOIN + "." + Metadata.KEY.name).eq(TaskRabbitMetadata.METADATA_KEY), //$NON-NLS-1$
Task.ID.eq(Field.field(TR_METADATA_JOIN + "." + Metadata.TASK.name)))).toString() //$NON-NLS-1$
Criterion.and(Field.field(TR_METADATA_JOIN + "." + Metadata.KEY.name).eq(TaskRabbitMetadata.METADATA_KEY),
Task.ID.eq(Field.field(TR_METADATA_JOIN + "." + Metadata.TASK.name)))).toString()
+ Join.left(Metadata.TABLE.as(TAGS_METADATA_JOIN),
tagsJoinCriterion).toString() //$NON-NLS-1$
+ Join.left(User.TABLE.as(USER_IMAGE_JOIN), Task.USER_ID.eq(Field.field(USER_IMAGE_JOIN + "." + User.UUID.name))).toString()
+ Join.left(User.TABLE.as(USER_IMAGE_JOIN),
Task.USER_ID.eq(Field.field(USER_IMAGE_JOIN + "." + User.UUID.name))).toString()
+ Join.left(Metadata.TABLE.as(FILE_METADATA_JOIN),
Criterion.and(Field.field(FILE_METADATA_JOIN + "." + Metadata.KEY.name).eq(FileMetadata.METADATA_KEY),
Task.ID.eq(Field.field(FILE_METADATA_JOIN + "." + Metadata.TASK.name))))
+ filter.getSqlQuery();
sqlQueryTemplate.set(SortHelper.adjustQueryForFlagsAndSort(

@ -22,6 +22,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Parcelable;
@ -59,6 +60,7 @@ import com.todoroo.astrid.service.MarketStrategy.NookMarketStrategy;
import com.todoroo.astrid.service.TaskService;
import com.todoroo.astrid.tags.TagService;
import com.todoroo.astrid.utility.Constants;
import com.todoroo.astrid.utility.ResourceDrawableCache;
public class FilterAdapter extends ArrayAdapter<Filter> {
@ -79,6 +81,8 @@ public class FilterAdapter extends ArrayAdapter<Filter> {
/** parent activity */
protected final Activity activity;
protected final Resources resources;
/** owner listview */
protected ListView listView;
@ -133,6 +137,7 @@ public class FilterAdapter extends ArrayAdapter<Filter> {
DependencyInjectionService.getInstance().inject(this);
this.activity = activity;
this.resources = activity.getResources();
this.listView = listView;
this.layout = rowLayout;
this.skipIntentFilters = skipIntentFilters;
@ -578,7 +583,7 @@ public class FilterAdapter extends ArrayAdapter<Filter> {
viewHolder.name.getLayoutParams().height = (int) (58 * metrics.density);
if(!nook && filter instanceof FilterWithUpdate) {
viewHolder.urlImage.setVisibility(View.VISIBLE);
viewHolder.urlImage.setDefaultImageResource(TagService.getDefaultImageIDForTag(viewHolder.name.getText().toString()));
viewHolder.urlImage.setDefaultImageDrawable(ResourceDrawableCache.getImageDrawableFromId(resources, TagService.getDefaultImageIDForTag(viewHolder.name.getText().toString())));
viewHolder.urlImage.setUrl(((FilterWithUpdate)filter).imageUrl);
}

@ -9,7 +9,6 @@ import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.atomic.AtomicReference;
@ -58,23 +57,19 @@ import android.widget.TextView;
import com.timsu.astrid.R;
import com.todoroo.andlib.data.Property;
import com.todoroo.andlib.data.Property.IntegerProperty;
import com.todoroo.andlib.data.Property.LongProperty;
import com.todoroo.andlib.data.Property.StringProperty;
import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.ContextManager;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Field;
import com.todoroo.andlib.sql.Join;
import com.todoroo.andlib.sql.Query;
import com.todoroo.andlib.utility.AndroidUtilities;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.andlib.utility.Pair;
import com.todoroo.andlib.utility.Preferences;
import com.todoroo.astrid.activity.TaskListFragment;
import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.api.PermaSql;
import com.todoroo.astrid.api.TaskAction;
import com.todoroo.astrid.api.TaskDecoration;
import com.todoroo.astrid.api.TaskDecorationExposer;
@ -83,7 +78,6 @@ import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.RemoteModel;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.data.User;
import com.todoroo.astrid.files.FileMetadata;
import com.todoroo.astrid.files.FilesAction;
import com.todoroo.astrid.files.FilesControlSet;
import com.todoroo.astrid.helper.AsyncImageView;
@ -96,6 +90,7 @@ 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
@ -113,11 +108,14 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
public static final String BROADCAST_EXTRA_TASK = "model"; //$NON-NLS-1$
private static final LongProperty TASK_RABBIT_ID = new LongProperty(Metadata.TABLE.as(TaskListFragment.TR_METADATA_JOIN),
Metadata.ID.name).as("taskRabId"); //$NON-NLS-1$
@SuppressWarnings("nls")
private static final LongProperty TASK_RABBIT_ID = new LongProperty(Metadata.TABLE.as(TaskListFragment.TR_METADATA_JOIN), Metadata.ID.name).as("taskRabId");
@SuppressWarnings("nls")
private static final StringProperty TAGS = new StringProperty(null, "group_concat(" + TaskListFragment.TAGS_METADATA_JOIN + "." + TaskToTagMetadata.TAG_NAME.name + ", ' | ')").as("tags");
@SuppressWarnings("nls")
private static final LongProperty FILE_ID_PROPERTY = new LongProperty(Metadata.TABLE.as(TaskListFragment.FILE_METADATA_JOIN), Metadata.ID.name).as("fileId");
@SuppressWarnings("nls")
private static final IntegerProperty HAS_NOTES_PROPERTY = new IntegerProperty(null, "length(" + Task.NOTES + ") > 0").as("hasNotes");
private static final StringProperty PICTURE = new StringProperty(User.TABLE.as(TaskListFragment.USER_IMAGE_JOIN), User.PICTURE.name);
@ -139,14 +137,15 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
Task.ELAPSED_SECONDS,
Task.TIMER_START,
Task.RECURRENCE,
Task.NOTES,
Task.USER_ID,
Task.USER,
Task.REMINDER_LAST,
Task.SOCIAL_REMINDER,
PICTURE,
HAS_NOTES_PROPERTY, // Whether or not the task has notes
TASK_RABBIT_ID, // Task rabbit metadata id (non-zero means it exists)
TAGS // Concatenated list of tags
TAGS, // Concatenated list of tags
FILE_ID_PROPERTY // File id
};
public static final Property<?>[] BASIC_PROPERTIES = new Property<?>[] {
@ -161,34 +160,47 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
Task.DELETION_DATE
};
public static int[] IMPORTANCE_RESOURCES = new int[] {
R.drawable.importance_check_1,
R.drawable.importance_check_2,
R.drawable.importance_check_3,
R.drawable.importance_check_4,
public static final int[] IMPORTANCE_RESOURCES = new int[] {
R.drawable.check_box_1,
R.drawable.check_box_2,
R.drawable.check_box_3,
R.drawable.check_box_4,
};
public static int[] LEGACY_IMPORTANCE_RESOURCES = new int[] {
R.drawable.importance_1,
R.drawable.importance_2,
R.drawable.importance_3,
R.drawable.importance_4,
public static final int[] IMPORTANCE_RESOURCES_CHECKED = new int[] {
R.drawable.check_box_checked_1,
R.drawable.check_box_checked_2,
R.drawable.check_box_checked_3,
R.drawable.check_box_checked_4,
};
public static int[] IMPORTANCE_RESOURCES_LARGE = new int[] {
public static final int[] IMPORTANCE_RESOURCES_LARGE = new int[] {
R.drawable.check_box_large_1,
R.drawable.check_box_large_2,
R.drawable.check_box_large_3,
R.drawable.check_box_large_4,
};
public static int[] IMPORTANCE_REPEAT_RESOURCES = new int[] {
R.drawable.importance_check_repeat_1,
R.drawable.importance_check_repeat_2,
R.drawable.importance_check_repeat_3,
R.drawable.importance_check_repeat_4,
public static final int[] IMPORTANCE_REPEAT_RESOURCES = new int[] {
R.drawable.check_box_repeat_1,
R.drawable.check_box_repeat_2,
R.drawable.check_box_repeat_3,
R.drawable.check_box_repeat_4,
};
public static final int[] IMPORTANCE_REPEAT_RESOURCES_CHECKED = new int[] {
R.drawable.check_box_repeat_checked_1,
R.drawable.check_box_repeat_checked_2,
R.drawable.check_box_repeat_checked_3,
R.drawable.check_box_repeat_checked_4,
};
private static final Drawable[] IMPORTANCE_DRAWABLES = new Drawable[IMPORTANCE_RESOURCES.length];
private static final Drawable[] IMPORTANCE_DRAWABLES_CHECKED = new Drawable[IMPORTANCE_RESOURCES_CHECKED.length];
private static final Drawable[] IMPORTANCE_DRAWABLES_LARGE = new Drawable[IMPORTANCE_RESOURCES_LARGE.length];
private static final Drawable[] IMPORTANCE_REPEAT_DRAWABLES = new Drawable[IMPORTANCE_REPEAT_RESOURCES.length];
private static final Drawable[] IMPORTANCE_REPEAT_DRAWABLES_CHECKED = new Drawable[IMPORTANCE_REPEAT_RESOURCES_CHECKED.length];
// --- instance variables
@Autowired
@ -198,6 +210,7 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
public static int APPLY_LISTENERS_ROW_BODY= 1;
public static int APPLY_LISTENERS_NONE = 2;
protected final Context context;
protected final TaskListFragment fragment;
protected final Resources resources;
protected final HashMap<Long, Boolean> completedItems = new HashMap<Long, Boolean>(0);
@ -206,7 +219,7 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
protected final int resource;
protected final LayoutInflater inflater;
private DetailLoaderThread detailLoader;
private ActionsLoaderThread actionsLoader;
// private ActionsLoaderThread actionsLoader;
private int fontSize;
protected int applyListeners = APPLY_LISTENERS_PARENT;
private long mostRecentlyMade = -1;
@ -227,6 +240,8 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
public final DecorationManager decorationManager;
private final Map<Long, TaskAction> taskActionLoader = Collections.synchronizedMap(new HashMap<Long, TaskAction>());
/**
* Constructor
*
@ -246,6 +261,7 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
super(ContextManager.getContext(), c, autoRequery);
DependencyInjectionService.getInstance().inject(this);
this.context = ContextManager.getContext();
this.query = query;
this.resource = resource;
this.titleOnlyLayout = resource == R.layout.task_adapter_row_title_only;
@ -264,7 +280,6 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
this.minRowHeight = computeMinRowHeight();
startDetailThread();
startTaskActionsThread();
decorationManager = new DecorationManager();
@ -276,6 +291,18 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
fragment.getActivity().getTheme().resolveAttribute(R.attr.asReadonlyTaskBackground, readonlyBg, false);
readonlyBackground = readonlyBg.data;
preloadDrawables(IMPORTANCE_RESOURCES, IMPORTANCE_DRAWABLES);
preloadDrawables(IMPORTANCE_RESOURCES_CHECKED, IMPORTANCE_DRAWABLES_CHECKED);
preloadDrawables(IMPORTANCE_RESOURCES_LARGE, IMPORTANCE_DRAWABLES_LARGE);
preloadDrawables(IMPORTANCE_REPEAT_RESOURCES, IMPORTANCE_REPEAT_DRAWABLES);
preloadDrawables(IMPORTANCE_REPEAT_RESOURCES_CHECKED, IMPORTANCE_REPEAT_DRAWABLES_CHECKED);
}
private void preloadDrawables(int[] resourceIds, Drawable[] drawables) {
for (int i = 0; i < resourceIds.length; i++) {
drawables[i] = resources.getDrawable(resourceIds[i]);
}
}
protected int computeMinRowHeight() {
@ -303,13 +330,6 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
}
}
private void startTaskActionsThread() {
if (!titleOnlyLayout) {
actionsLoader = new ActionsLoaderThread();
actionsLoader.start();
}
}
/* ======================================================================
* =========================================================== filterable
* ====================================================================== */
@ -396,6 +416,8 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
viewHolder.isTaskRabbit = (cursor.get(TASK_RABBIT_ID) > 0);
viewHolder.tagsString = cursor.get(TAGS);
viewHolder.imageUrl = RemoteModel.PictureHelper.getPictureUrlFromCursor(cursor, PICTURE, RemoteModel.PICTURE_THUMB);
viewHolder.hasFiles = cursor.get(FILE_ID_PROPERTY) > 0;
viewHolder.hasNotes = cursor.get(HAS_NOTES_PROPERTY) > 0;
}
Task task = viewHolder.task;
@ -429,6 +451,8 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
public boolean isTaskRabbit; // From join query, not part of the task model
public String tagsString; // From join query, not part of the task model
public String imageUrl; // From join query, not part of the task model
public boolean hasFiles; // From join query, not part of the task model
public boolean hasNotes;
public View[] decorations;
}
@ -493,13 +517,11 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
// Task action
ImageView taskAction = viewHolder.taskActionIcon;
if (taskAction != null) {
if (taskActionLoader.containsKey(task.getId())) {
TaskAction action = getTaskAction(task, viewHolder.hasFiles, viewHolder.hasNotes);
if (action != null) {
taskAction.setVisibility(View.VISIBLE);
TaskAction action = taskActionLoader.get(task.getId());
if (action != null) {
taskAction.setImageBitmap(action.icon);
taskAction.setTag(action);
}
taskAction.setImageDrawable(action.icon);
taskAction.setTag(action);
} else {
taskAction.setVisibility(View.GONE);
taskAction.setTag(null);
@ -509,10 +531,18 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
if(Math.abs(DateUtilities.now() - task.getValue(Task.MODIFICATION_DATE)) < 2000L)
mostRecentlyMade = task.getId();
if (Preferences.getBoolean(R.string.p_default_showdecorations_key, false)) {
decorationManager.request(viewHolder);
}
}
private TaskAction getTaskAction(Task task, boolean hasFiles, boolean hasNotes) {
if (titleOnlyLayout || task.isCompleted() || !task.isEditable())
return null;
if (taskActionLoader.containsKey(task.getId())) {
return taskActionLoader.get(task.getId());
} else {
TaskAction action = LinkActionExposer.getActionsForTask(context, task, hasFiles, hasNotes);
taskActionLoader.put(task.getId(), action);
return action;
}
}
@SuppressWarnings("nls")
@ -609,6 +639,13 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
}
private void showEditNotesDialog(final Task task) {
String notes = null;
Task t = taskService.fetchById(task.getId(), Task.NOTES);
if (t != null)
notes = t.getValue(Task.NOTES);
if (TextUtils.isEmpty(notes))
return;
int theme = ThemeService.getEditDialogTheme();
final Dialog dialog = new Dialog(fragment.getActivity(), theme);
dialog.setTitle(R.string.TEA_note_label);
@ -623,7 +660,7 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
});
final TextView notesField = (TextView) notesView.findViewById(R.id.notes);
notesField.setText(task.getValue(Task.NOTES));
notesField.setText(notes);
LayoutParams params = dialog.getWindow().getAttributes();
params.width = LayoutParams.FILL_PARENT;
@ -767,67 +804,6 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
}
}
private final Map<Long, TaskAction> taskActionLoader = Collections.synchronizedMap(new HashMap<Long, TaskAction>());
@SuppressWarnings("nls")
public class ActionsLoaderThread extends Thread {
public static final String FILE_COLUMN = "fileId";
private static final String METADATA_JOIN = "for_actions";
private final LongProperty fileIdProperty = new LongProperty(Metadata.TABLE.as(METADATA_JOIN),
Metadata.ID.name).as(FILE_COLUMN);
@Override
public void run() {
AndroidUtilities.sleepDeep(500L);
String groupedQuery = query.get();
groupedQuery = PermaSql.replacePlaceholders(groupedQuery);
Query q = Query.select(Task.ID, Task.TITLE, Task.NOTES, Task.COMPLETION_DATE, Task.USER_ID,
fileIdProperty)
.join(Join.left(Metadata.TABLE.as(METADATA_JOIN),
Criterion.and(Field.field(METADATA_JOIN + "." + Metadata.KEY.name).eq(FileMetadata.METADATA_KEY),
Task.ID.eq(Field.field(METADATA_JOIN + "." + Metadata.TASK.name))))).withQueryTemplate(groupedQuery);
final TodorooCursor<Task> fetchCursor = taskService.query(q);
try {
Task task = new Task();
LinkActionExposer linkActionExposer = new LinkActionExposer();
for(fetchCursor.moveToFirst(); !fetchCursor.isAfterLast(); fetchCursor.moveToNext()) {
task.clear();
task.readFromCursor(fetchCursor);
if(task.isCompleted() || !task.isEditable())
continue;
boolean hasAttachments = (fetchCursor.get(fileIdProperty) > 0);
List<TaskAction> actions = linkActionExposer.
getActionsForTask(ContextManager.getContext(), task, hasAttachments);
if (actions.size() > 0)
taskActionLoader.put(task.getId(), actions.get(0));
else
taskActionLoader.remove(task.getId());
}
} finally {
fetchCursor.close();
}
final Activity activity = fragment.getActivity();
if (activity != null) {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
if(taskActionLoader.size() > 0) {
notifyDataSetChanged();
}
}
});
}
}
}
/**
* Add detail to a task
*
@ -904,7 +880,6 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
decorationManager.clearCache();
taskDetailLoader.clear();
startDetailThread();
startTaskActionsThread();
}
/**
@ -1148,10 +1123,10 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
pictureView.setUrl(null);
if (viewHolder.isTaskRabbit) {
pictureView.setDefaultImageResource(R.drawable.task_rabbit_image);
} else if(Task.USER_ID_UNASSIGNED.equals(task.getValue(Task.USER_ID)))
pictureView.setDefaultImageResource(R.drawable.icn_anyone_transparent);
} else if (Task.USER_ID_UNASSIGNED.equals(task.getValue(Task.USER_ID)))
pictureView.setDefaultImageDrawable(ResourceDrawableCache.getImageDrawableFromId(resources, R.drawable.icn_anyone_transparent));
else {
pictureView.setDefaultImageResource(R.drawable.icn_default_person_image);
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))) {
@ -1177,18 +1152,21 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
final Task task = viewHolder.task;
final AsyncImageView pictureView = viewHolder.picture;
final CheckableImageView checkBoxView = viewHolder.completeBox; {
checkBoxView.setChecked(task.isCompleted());
boolean completed = task.isCompleted();
checkBoxView.setChecked(completed);
// disable checkbox if task is readonly
checkBoxView.setEnabled(viewHolder.task.isEditable());
int value = task.getValue(Task.IMPORTANCE);
if (value >= IMPORTANCE_RESOURCES.length)
value = IMPORTANCE_RESOURCES.length - 1;
Drawable[] boxes = IMPORTANCE_DRAWABLES;
if (!TextUtils.isEmpty(task.getValue(Task.RECURRENCE))) {
checkBoxView.setImageResource(IMPORTANCE_REPEAT_RESOURCES[value]);
boxes = completed ? IMPORTANCE_REPEAT_DRAWABLES_CHECKED : IMPORTANCE_REPEAT_DRAWABLES;
} else {
checkBoxView.setImageResource(IMPORTANCE_RESOURCES[value]);
boxes = completed ? IMPORTANCE_DRAWABLES_CHECKED : IMPORTANCE_DRAWABLES;
}
checkBoxView.setImageDrawable(boxes[value]);
if (titleOnlyLayout)
return;
@ -1202,7 +1180,7 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
if (pictureView != null && pictureView.getVisibility() == View.VISIBLE) {
checkBoxView.setVisibility(View.INVISIBLE);
if (viewHolder.pictureBorder != null)
viewHolder.pictureBorder.setBackgroundResource(IMPORTANCE_RESOURCES_LARGE[value]);
viewHolder.pictureBorder.setBackgroundDrawable(IMPORTANCE_DRAWABLES_LARGE[value]);
} else {
checkBoxView.setVisibility(View.VISIBLE);
}

@ -292,7 +292,7 @@ public final class UpgradeService {
StringBuilder changeLog = new StringBuilder();
if (from >= V4_5_0 && from < V4_5_2) {
newVersionString(changeLog, "4.5.1.1 (1/17/13)", new String[] {
newVersionString(changeLog, "4.5.2 (1/17/13)", new String[] {
"Fixed a crash that could affect some Google Tasks users",
"UI polish"
});

@ -10,7 +10,6 @@ import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
@ -25,6 +24,7 @@ import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.service.RestClient;
import com.todoroo.andlib.utility.Preferences;
import com.todoroo.astrid.service.StatisticsService;
import com.twmacinta.util.MD5;
/**
* Invoker for communicating with the Astrid Analytics server
@ -116,7 +116,9 @@ public class ABTestInvoker {
}
sigBuilder.append(API_SECRET);
String signature = DigestUtils.md5Hex(sigBuilder.toString());
MD5 md5 = new MD5();
md5.Update(sigBuilder.toString(), null);
String signature = md5.asHex();
params.add(new BasicNameValuePair("sig", signature));
try {

@ -13,6 +13,7 @@ import org.json.JSONObject;
import android.app.Activity;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.text.Editable;
import android.text.TextUtils;
@ -31,6 +32,7 @@ import com.timsu.astrid.R;
import com.todoroo.andlib.utility.Preferences;
import com.todoroo.astrid.actfm.sync.ActFmPreferenceService;
import com.todoroo.astrid.helper.AsyncImageView;
import com.todoroo.astrid.utility.ResourceDrawableCache;
public class PeopleContainer extends LinearLayout {
@ -38,11 +40,13 @@ public class PeopleContainer extends LinearLayout {
protected OnAddNewPersonListener onAddNewPerson = null;
protected Resources resources;
// --- accessors and boilerplate
public PeopleContainer(Context arg0, AttributeSet attrs) {
super(arg0, attrs);
resources = arg0.getResources();
TypedArray a = getContext().obtainStyledAttributes(attrs,
R.styleable.ContactsAutoComplete);
completeTags = a.getBoolean(R.styleable.ContactsAutoComplete_completeTags, false);
@ -113,11 +117,11 @@ public class PeopleContainer extends LinearLayout {
findViewById(R.id.icon);
imageView.setUrl(image);
if (TextUtils.isEmpty(textView.getText())) {
imageView.setDefaultImageResource(R.drawable.icn_add_contact);
imageView.setDefaultImageDrawable(ResourceDrawableCache.getImageDrawableFromId(resources, R.drawable.icn_add_contact));
removeButton.setVisibility(View.GONE);
}
else {
imageView.setDefaultImageResource(R.drawable.icn_default_person_image);
imageView.setDefaultImageDrawable(ResourceDrawableCache.getImageDrawableFromId(resources, R.drawable.icn_default_person_image));
removeButton.setVisibility(View.VISIBLE);
}
@ -140,11 +144,11 @@ public class PeopleContainer extends LinearLayout {
addPerson("", "");
}
if (TextUtils.isEmpty(textView.getText())) {
imageView.setDefaultImageResource(R.drawable.icn_add_contact);
imageView.setDefaultImageDrawable(ResourceDrawableCache.getImageDrawableFromId(resources, R.drawable.icn_add_contact));
removeButton.setVisibility(View.GONE);
}
else {
imageView.setDefaultImageResource(R.drawable.icn_default_person_image);
imageView.setDefaultImageDrawable(ResourceDrawableCache.getImageDrawableFromId(resources, R.drawable.icn_default_person_image));
removeButton.setVisibility(View.VISIBLE);
}

@ -0,0 +1,71 @@
package com.todoroo.astrid.utility;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import com.timsu.astrid.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);
}
}
}

@ -0,0 +1,897 @@
package com.twmacinta.util;
import java.io.*;
/**
* Fast implementation of RSA's MD5 hash generator in Java JDK Beta-2 or higher.
* <p>
* Originally written by Santeri Paavolainen, Helsinki Finland 1996.<br>
* (c) Santeri Paavolainen, Helsinki Finland 1996<br>
* Many changes Copyright (c) 2002 - 2010 Timothy W Macinta<br>
* <p>
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
* <p>
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
* <p>
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* <p>
* See http://www.twmacinta.com/myjava/fast_md5.php for more information
* on this file and the related files.
* <p>
* This was originally a rather straight re-implementation of the
* reference implementation given in RFC1321 by RSA. It passes the MD5
* test suite as defined in RFC1321.
* <p>
* Many optimizations made by Timothy W Macinta. Reduced time to checksum a
* test file in Java alone to roughly half the time taken compared with
* java.security.MessageDigest (within an intepretter). Also added an
* optional native method to reduce the time even further.
* See http://www.twmacinta.com/myjava/fast_md5.php for further information
* on the time improvements achieved.
* <p>
* Some bug fixes also made by Timothy W Macinta.
* <p>
* Please note: I (Timothy Macinta) have put this code in the
* com.twmacinta.util package only because it came without a package. I
* was not the the original author of the code, although I did
* optimize it (substantially) and fix some bugs.
* <p>
* This Java class has been derived from the RSA Data Security, Inc. MD5
* Message-Digest Algorithm and its reference implementation.
* <p>
* This class will attempt to use a native method to quickly compute
* checksums when the appropriate native library is available. On Linux,
* this library should be named "MD5.so" and on Windows it should be
* named "MD5.dll". The code will attempt to locate the library in the
* following locations in the order given:
*
* <ol>
* <li>The path specified by the system property
* "com.twmacinta.util.MD5.NATIVE_LIB_FILE"
* (be sure to include "MD5.so", "MD5.dll",
* or "MD5.jnilib" as appropriate at the end
* of the path).
* <li>A platform specific directory beneath the "lib/arch/" directory.
* For example, On Windows for 32 bit x86 architectures, this is
* "lib/arch/win32_x86/".
* <li>Within the "lib/" directory.
* <li>Within the current directory.
* </ol>
*
* <p>
* If the library is not found, the code will fall back to the default
* (slower) Java code.
* <p>
* As a side effect of having the code search for the native library,
* SecurityExceptions might be thrown on JVMs that have a restrictive
* SecurityManager. The initialization code attempts to silently discard
* these exceptions and continue, but many SecurityManagers will
* attempt to notify the user directly of all SecurityExceptions thrown.
* Consequently, the code has provisions for skipping the search for
* the native library. Any of these provisions may be used to skip the
* search as long as they are performed <i>before</i> the first
* instance of a com.twmacinta.util.MD5 object is constructed (note that
* the convenience stream objects will implicitly create an MD5 object).
* <p>
* The first option is to set the system property
* "com.twmacinta.util.MD5.NO_NATIVE_LIB" to "true" or "1".
* Unfortunately, SecurityManagers may also choose to disallow system
* property setting, so this won't be of use in all cases.
* <p>
* The second option is to call
* com.twmacinta.util.MD5.initNativeLibrary(true) before any MD5 objects
* are constructed.
*
* @author Santeri Paavolainen <sjpaavol@cc.helsinki.fi>
* @author Timothy W Macinta (twm@alum.mit.edu) (optimizations and bug fixes)
*/
public class MD5 {
/**
* MD5 state
**/
MD5State state;
/**
* If Final() has been called, finals is set to the current finals
* state. Any Update() causes this to be set to null.
**/
MD5State finals;
/**
* Padding for Final()
**/
static byte padding[] = {
(byte) 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
private static boolean native_lib_loaded = false;
private static boolean native_lib_init_pending = true;
/**
* Initialize MD5 internal state (object can be reused just by
* calling Init() after every Final()
**/
public synchronized void Init () {
state = new MD5State();
finals = null;
}
/**
* Class constructor
**/
public MD5 () {
if (native_lib_init_pending) _initNativeLibrary();
this.Init();
}
/**
* Initialize class, and update hash with ob.toString()
*
* @param ob Object, ob.toString() is used to update hash
* after initialization
**/
public MD5 (Object ob) {
this();
Update(ob.toString());
}
private void Decode (byte buffer[], int shift, int[] out) {
/*len += shift;
for (int i = 0; shift < len; i++, shift += 4) {
out[i] = ((int) (buffer[shift] & 0xff)) |
(((int) (buffer[shift + 1] & 0xff)) << 8) |
(((int) (buffer[shift + 2] & 0xff)) << 16) |
(((int) buffer[shift + 3]) << 24);
}*/
// unrolled loop (original loop shown above)
out[0] = ((int) (buffer[shift] & 0xff)) |
(((int) (buffer[shift + 1] & 0xff)) << 8) |
(((int) (buffer[shift + 2] & 0xff)) << 16) |
(((int) buffer[shift + 3]) << 24);
out[1] = ((int) (buffer[shift + 4] & 0xff)) |
(((int) (buffer[shift + 5] & 0xff)) << 8) |
(((int) (buffer[shift + 6] & 0xff)) << 16) |
(((int) buffer[shift + 7]) << 24);
out[2] = ((int) (buffer[shift + 8] & 0xff)) |
(((int) (buffer[shift + 9] & 0xff)) << 8) |
(((int) (buffer[shift + 10] & 0xff)) << 16) |
(((int) buffer[shift + 11]) << 24);
out[3] = ((int) (buffer[shift + 12] & 0xff)) |
(((int) (buffer[shift + 13] & 0xff)) << 8) |
(((int) (buffer[shift + 14] & 0xff)) << 16) |
(((int) buffer[shift + 15]) << 24);
out[4] = ((int) (buffer[shift + 16] & 0xff)) |
(((int) (buffer[shift + 17] & 0xff)) << 8) |
(((int) (buffer[shift + 18] & 0xff)) << 16) |
(((int) buffer[shift + 19]) << 24);
out[5] = ((int) (buffer[shift + 20] & 0xff)) |
(((int) (buffer[shift + 21] & 0xff)) << 8) |
(((int) (buffer[shift + 22] & 0xff)) << 16) |
(((int) buffer[shift + 23]) << 24);
out[6] = ((int) (buffer[shift + 24] & 0xff)) |
(((int) (buffer[shift + 25] & 0xff)) << 8) |
(((int) (buffer[shift + 26] & 0xff)) << 16) |
(((int) buffer[shift + 27]) << 24);
out[7] = ((int) (buffer[shift + 28] & 0xff)) |
(((int) (buffer[shift + 29] & 0xff)) << 8) |
(((int) (buffer[shift + 30] & 0xff)) << 16) |
(((int) buffer[shift + 31]) << 24);
out[8] = ((int) (buffer[shift + 32] & 0xff)) |
(((int) (buffer[shift + 33] & 0xff)) << 8) |
(((int) (buffer[shift + 34] & 0xff)) << 16) |
(((int) buffer[shift + 35]) << 24);
out[9] = ((int) (buffer[shift + 36] & 0xff)) |
(((int) (buffer[shift + 37] & 0xff)) << 8) |
(((int) (buffer[shift + 38] & 0xff)) << 16) |
(((int) buffer[shift + 39]) << 24);
out[10] = ((int) (buffer[shift + 40] & 0xff)) |
(((int) (buffer[shift + 41] & 0xff)) << 8) |
(((int) (buffer[shift + 42] & 0xff)) << 16) |
(((int) buffer[shift + 43]) << 24);
out[11] = ((int) (buffer[shift + 44] & 0xff)) |
(((int) (buffer[shift + 45] & 0xff)) << 8) |
(((int) (buffer[shift + 46] & 0xff)) << 16) |
(((int) buffer[shift + 47]) << 24);
out[12] = ((int) (buffer[shift + 48] & 0xff)) |
(((int) (buffer[shift + 49] & 0xff)) << 8) |
(((int) (buffer[shift + 50] & 0xff)) << 16) |
(((int) buffer[shift + 51]) << 24);
out[13] = ((int) (buffer[shift + 52] & 0xff)) |
(((int) (buffer[shift + 53] & 0xff)) << 8) |
(((int) (buffer[shift + 54] & 0xff)) << 16) |
(((int) buffer[shift + 55]) << 24);
out[14] = ((int) (buffer[shift + 56] & 0xff)) |
(((int) (buffer[shift + 57] & 0xff)) << 8) |
(((int) (buffer[shift + 58] & 0xff)) << 16) |
(((int) buffer[shift + 59]) << 24);
out[15] = ((int) (buffer[shift + 60] & 0xff)) |
(((int) (buffer[shift + 61] & 0xff)) << 8) |
(((int) (buffer[shift + 62] & 0xff)) << 16) |
(((int) buffer[shift + 63]) << 24);
}
private native void Transform_native (int[] state, byte buffer[], int shift, int length);
private void Transform (MD5State state, byte buffer[], int shift, int[] decode_buf) {
int
a = state.state[0],
b = state.state[1],
c = state.state[2],
d = state.state[3],
x[] = decode_buf;
Decode(buffer, shift, decode_buf);
/* Round 1 */
a += ((b & c) | (~b & d)) + x[ 0] + 0xd76aa478; /* 1 */
a = ((a << 7) | (a >>> 25)) + b;
d += ((a & b) | (~a & c)) + x[ 1] + 0xe8c7b756; /* 2 */
d = ((d << 12) | (d >>> 20)) + a;
c += ((d & a) | (~d & b)) + x[ 2] + 0x242070db; /* 3 */
c = ((c << 17) | (c >>> 15)) + d;
b += ((c & d) | (~c & a)) + x[ 3] + 0xc1bdceee; /* 4 */
b = ((b << 22) | (b >>> 10)) + c;
a += ((b & c) | (~b & d)) + x[ 4] + 0xf57c0faf; /* 5 */
a = ((a << 7) | (a >>> 25)) + b;
d += ((a & b) | (~a & c)) + x[ 5] + 0x4787c62a; /* 6 */
d = ((d << 12) | (d >>> 20)) + a;
c += ((d & a) | (~d & b)) + x[ 6] + 0xa8304613; /* 7 */
c = ((c << 17) | (c >>> 15)) + d;
b += ((c & d) | (~c & a)) + x[ 7] + 0xfd469501; /* 8 */
b = ((b << 22) | (b >>> 10)) + c;
a += ((b & c) | (~b & d)) + x[ 8] + 0x698098d8; /* 9 */
a = ((a << 7) | (a >>> 25)) + b;
d += ((a & b) | (~a & c)) + x[ 9] + 0x8b44f7af; /* 10 */
d = ((d << 12) | (d >>> 20)) + a;
c += ((d & a) | (~d & b)) + x[10] + 0xffff5bb1; /* 11 */
c = ((c << 17) | (c >>> 15)) + d;
b += ((c & d) | (~c & a)) + x[11] + 0x895cd7be; /* 12 */
b = ((b << 22) | (b >>> 10)) + c;
a += ((b & c) | (~b & d)) + x[12] + 0x6b901122; /* 13 */
a = ((a << 7) | (a >>> 25)) + b;
d += ((a & b) | (~a & c)) + x[13] + 0xfd987193; /* 14 */
d = ((d << 12) | (d >>> 20)) + a;
c += ((d & a) | (~d & b)) + x[14] + 0xa679438e; /* 15 */
c = ((c << 17) | (c >>> 15)) + d;
b += ((c & d) | (~c & a)) + x[15] + 0x49b40821; /* 16 */
b = ((b << 22) | (b >>> 10)) + c;
/* Round 2 */
a += ((b & d) | (c & ~d)) + x[ 1] + 0xf61e2562; /* 17 */
a = ((a << 5) | (a >>> 27)) + b;
d += ((a & c) | (b & ~c)) + x[ 6] + 0xc040b340; /* 18 */
d = ((d << 9) | (d >>> 23)) + a;
c += ((d & b) | (a & ~b)) + x[11] + 0x265e5a51; /* 19 */
c = ((c << 14) | (c >>> 18)) + d;
b += ((c & a) | (d & ~a)) + x[ 0] + 0xe9b6c7aa; /* 20 */
b = ((b << 20) | (b >>> 12)) + c;
a += ((b & d) | (c & ~d)) + x[ 5] + 0xd62f105d; /* 21 */
a = ((a << 5) | (a >>> 27)) + b;
d += ((a & c) | (b & ~c)) + x[10] + 0x02441453; /* 22 */
d = ((d << 9) | (d >>> 23)) + a;
c += ((d & b) | (a & ~b)) + x[15] + 0xd8a1e681; /* 23 */
c = ((c << 14) | (c >>> 18)) + d;
b += ((c & a) | (d & ~a)) + x[ 4] + 0xe7d3fbc8; /* 24 */
b = ((b << 20) | (b >>> 12)) + c;
a += ((b & d) | (c & ~d)) + x[ 9] + 0x21e1cde6; /* 25 */
a = ((a << 5) | (a >>> 27)) + b;
d += ((a & c) | (b & ~c)) + x[14] + 0xc33707d6; /* 26 */
d = ((d << 9) | (d >>> 23)) + a;
c += ((d & b) | (a & ~b)) + x[ 3] + 0xf4d50d87; /* 27 */
c = ((c << 14) | (c >>> 18)) + d;
b += ((c & a) | (d & ~a)) + x[ 8] + 0x455a14ed; /* 28 */
b = ((b << 20) | (b >>> 12)) + c;
a += ((b & d) | (c & ~d)) + x[13] + 0xa9e3e905; /* 29 */
a = ((a << 5) | (a >>> 27)) + b;
d += ((a & c) | (b & ~c)) + x[ 2] + 0xfcefa3f8; /* 30 */
d = ((d << 9) | (d >>> 23)) + a;
c += ((d & b) | (a & ~b)) + x[ 7] + 0x676f02d9; /* 31 */
c = ((c << 14) | (c >>> 18)) + d;
b += ((c & a) | (d & ~a)) + x[12] + 0x8d2a4c8a; /* 32 */
b = ((b << 20) | (b >>> 12)) + c;
/* Round 3 */
a += (b ^ c ^ d) + x[ 5] + 0xfffa3942; /* 33 */
a = ((a << 4) | (a >>> 28)) + b;
d += (a ^ b ^ c) + x[ 8] + 0x8771f681; /* 34 */
d = ((d << 11) | (d >>> 21)) + a;
c += (d ^ a ^ b) + x[11] + 0x6d9d6122; /* 35 */
c = ((c << 16) | (c >>> 16)) + d;
b += (c ^ d ^ a) + x[14] + 0xfde5380c; /* 36 */
b = ((b << 23) | (b >>> 9)) + c;
a += (b ^ c ^ d) + x[ 1] + 0xa4beea44; /* 37 */
a = ((a << 4) | (a >>> 28)) + b;
d += (a ^ b ^ c) + x[ 4] + 0x4bdecfa9; /* 38 */
d = ((d << 11) | (d >>> 21)) + a;
c += (d ^ a ^ b) + x[ 7] + 0xf6bb4b60; /* 39 */
c = ((c << 16) | (c >>> 16)) + d;
b += (c ^ d ^ a) + x[10] + 0xbebfbc70; /* 40 */
b = ((b << 23) | (b >>> 9)) + c;
a += (b ^ c ^ d) + x[13] + 0x289b7ec6; /* 41 */
a = ((a << 4) | (a >>> 28)) + b;
d += (a ^ b ^ c) + x[ 0] + 0xeaa127fa; /* 42 */
d = ((d << 11) | (d >>> 21)) + a;
c += (d ^ a ^ b) + x[ 3] + 0xd4ef3085; /* 43 */
c = ((c << 16) | (c >>> 16)) + d;
b += (c ^ d ^ a) + x[ 6] + 0x04881d05; /* 44 */
b = ((b << 23) | (b >>> 9)) + c;
a += (b ^ c ^ d) + x[ 9] + 0xd9d4d039; /* 33 */
a = ((a << 4) | (a >>> 28)) + b;
d += (a ^ b ^ c) + x[12] + 0xe6db99e5; /* 34 */
d = ((d << 11) | (d >>> 21)) + a;
c += (d ^ a ^ b) + x[15] + 0x1fa27cf8; /* 35 */
c = ((c << 16) | (c >>> 16)) + d;
b += (c ^ d ^ a) + x[ 2] + 0xc4ac5665; /* 36 */
b = ((b << 23) | (b >>> 9)) + c;
/* Round 4 */
a += (c ^ (b | ~d)) + x[ 0] + 0xf4292244; /* 49 */
a = ((a << 6) | (a >>> 26)) + b;
d += (b ^ (a | ~c)) + x[ 7] + 0x432aff97; /* 50 */
d = ((d << 10) | (d >>> 22)) + a;
c += (a ^ (d | ~b)) + x[14] + 0xab9423a7; /* 51 */
c = ((c << 15) | (c >>> 17)) + d;
b += (d ^ (c | ~a)) + x[ 5] + 0xfc93a039; /* 52 */
b = ((b << 21) | (b >>> 11)) + c;
a += (c ^ (b | ~d)) + x[12] + 0x655b59c3; /* 53 */
a = ((a << 6) | (a >>> 26)) + b;
d += (b ^ (a | ~c)) + x[ 3] + 0x8f0ccc92; /* 54 */
d = ((d << 10) | (d >>> 22)) + a;
c += (a ^ (d | ~b)) + x[10] + 0xffeff47d; /* 55 */
c = ((c << 15) | (c >>> 17)) + d;
b += (d ^ (c | ~a)) + x[ 1] + 0x85845dd1; /* 56 */
b = ((b << 21) | (b >>> 11)) + c;
a += (c ^ (b | ~d)) + x[ 8] + 0x6fa87e4f; /* 57 */
a = ((a << 6) | (a >>> 26)) + b;
d += (b ^ (a | ~c)) + x[15] + 0xfe2ce6e0; /* 58 */
d = ((d << 10) | (d >>> 22)) + a;
c += (a ^ (d | ~b)) + x[ 6] + 0xa3014314; /* 59 */
c = ((c << 15) | (c >>> 17)) + d;
b += (d ^ (c | ~a)) + x[13] + 0x4e0811a1; /* 60 */
b = ((b << 21) | (b >>> 11)) + c;
a += (c ^ (b | ~d)) + x[ 4] + 0xf7537e82; /* 61 */
a = ((a << 6) | (a >>> 26)) + b;
d += (b ^ (a | ~c)) + x[11] + 0xbd3af235; /* 62 */
d = ((d << 10) | (d >>> 22)) + a;
c += (a ^ (d | ~b)) + x[ 2] + 0x2ad7d2bb; /* 63 */
c = ((c << 15) | (c >>> 17)) + d;
b += (d ^ (c | ~a)) + x[ 9] + 0xeb86d391; /* 64 */
b = ((b << 21) | (b >>> 11)) + c;
state.state[0] += a;
state.state[1] += b;
state.state[2] += c;
state.state[3] += d;
}
/**
* Updates hash with the bytebuffer given (using at maximum length bytes from
* that buffer)
*
* @param stat Which state is updated
* @param buffer Array of bytes to be hashed
* @param offset Offset to buffer array
* @param length Use at maximum `length' bytes (absolute
* maximum is buffer.length)
*/
public void Update (MD5State stat, byte buffer[], int offset, int length) {
int index, partlen, i, start;
finals = null;
/* Length can be told to be shorter, but not inter */
if ((length - offset)> buffer.length)
length = buffer.length - offset;
/* compute number of bytes mod 64 */
index = (int) (stat.count & 0x3f);
stat.count += length;
partlen = 64 - index;
if (length >= partlen) {
// update state (using native method) to reflect input
if (native_lib_loaded) {
if (partlen == 64) {
partlen = 0;
} else {
for (i = 0; i < partlen; i++)
stat.buffer[i + index] = buffer[i + offset];
Transform_native(stat.state, stat.buffer, 0, 64);
}
i = partlen + ((length - partlen) / 64) * 64;
// break into chunks to guard against stack overflow in JNI
int transformLength = length - partlen;
int transformOffset = partlen + offset;
final int MAX_LENGTH = 65536; // prevent stack overflow in JNI
while (true) {
if (transformLength > MAX_LENGTH) {
Transform_native(stat.state, buffer, transformOffset, MAX_LENGTH);
transformLength -= MAX_LENGTH;
transformOffset += MAX_LENGTH;
} else {
Transform_native(stat.state, buffer, transformOffset, transformLength);
break;
}
}
}
// update state (using only Java) to reflect input
else {
int[] decode_buf = new int[16];
if (partlen == 64) {
partlen = 0;
} else {
for (i = 0; i < partlen; i++)
stat.buffer[i + index] = buffer[i + offset];
Transform(stat, stat.buffer, 0, decode_buf);
}
for (i = partlen; (i + 63) < length; i+= 64) {
Transform(stat, buffer, i + offset, decode_buf);
}
}
index = 0;
} else {
i = 0;
}
/* buffer remaining input */
if (i < length) {
start = i;
for (; i < length; i++) {
stat.buffer[index + i - start] = buffer[i + offset];
}
}
}
/*
* Update()s for other datatypes than byte[] also. Update(byte[], int)
* is only the main driver.
*/
/**
* Plain update, updates this object
**/
public void Update (byte buffer[], int offset, int length) {
Update(this.state, buffer, offset, length);
}
public void Update (byte buffer[], int length) {
Update(this.state, buffer, 0, length);
}
/**
* Updates hash with given array of bytes
*
* @param buffer Array of bytes to use for updating the hash
**/
public void Update (byte buffer[]) {
Update(buffer, 0, buffer.length);
}
/**
* Updates hash with a single byte
*
* @param b Single byte to update the hash
**/
public void Update (byte b) {
byte buffer[] = new byte[1];
buffer[0] = b;
Update(buffer, 1);
}
/**
* Update buffer with given string. Note that because the version of
* the s.getBytes() method without parameters is used to convert the
* string to a byte array, the results of this method may be different
* on different platforms. The s.getBytes() method converts the string
* into a byte array using the current platform's default character set
* and may therefore have different results on platforms with different
* default character sets. If a version that works consistently
* across platforms with different default character sets is desired,
* use the overloaded version of the Update() method which takes a
* string and a character encoding.
*
* @param s String to be update to hash (is used as s.getBytes())
**/
public void Update (String s) {
byte chars[] = s.getBytes();
Update(chars, chars.length);
}
/**
* Update buffer with given string using the given encoding. If the
* given encoding is null, the encoding "ISO8859_1" is used.
*
* @param s String to be update to hash (is used as
* s.getBytes(charset_name))
* @param charset_name The character set to use to convert s to a
* byte array, or null if the "ISO8859_1"
* character set is desired.
* @exception java.io.UnsupportedEncodingException If the named
* charset is not supported.
**/
public void Update (String s, String charset_name) throws java.io.UnsupportedEncodingException {
if (charset_name == null) charset_name = "ISO8859_1";
byte chars[] = s.getBytes(charset_name);
Update(chars, chars.length);
}
/**
* Update buffer with a single integer (only & 0xff part is used,
* as a byte)
*
* @param i Integer value, which is then converted to byte as i & 0xff
**/
public void Update (int i) {
Update((byte) (i & 0xff));
}
private byte[] Encode (int input[], int len) {
int i, j;
byte out[];
out = new byte[len];
for (i = j = 0; j < len; i++, j += 4) {
out[j] = (byte) (input[i] & 0xff);
out[j + 1] = (byte) ((input[i] >>> 8) & 0xff);
out[j + 2] = (byte) ((input[i] >>> 16) & 0xff);
out[j + 3] = (byte) ((input[i] >>> 24) & 0xff);
}
return out;
}
/**
* Returns array of bytes (16 bytes) representing hash as of the
* current state of this object. Note: getting a hash does not
* invalidate the hash object, it only creates a copy of the real
* state which is finalized.
*
* @return Array of 16 bytes, the hash of all updated bytes
**/
public synchronized byte[] Final () {
byte bits[];
int index, padlen;
MD5State fin;
if (finals == null) {
fin = new MD5State(state);
int[] count_ints = {(int) (fin.count << 3), (int) (fin.count >> 29)};
bits = Encode(count_ints, 8);
index = (int) (fin.count & 0x3f);
padlen = (index < 56) ? (56 - index) : (120 - index);
Update(fin, padding, 0, padlen);
Update(fin, bits, 0, 8);
/* Update() sets finals to null */
finals = fin;
}
return Encode(finals.state, 16);
}
private static final char[] HEX_CHARS = {'0', '1', '2', '3',
'4', '5', '6', '7',
'8', '9', 'a', 'b',
'c', 'd', 'e', 'f',};
/**
* Turns array of bytes into string representing each byte as
* unsigned hex number.
*
* @param hash Array of bytes to convert to hex-string
* @return Generated hex string
*/
public static String asHex (byte hash[]) {
char buf[] = new char[hash.length * 2];
for (int i = 0, x = 0; i < hash.length; i++) {
buf[x++] = HEX_CHARS[(hash[i] >>> 4) & 0xf];
buf[x++] = HEX_CHARS[hash[i] & 0xf];
}
return new String(buf);
}
/**
* Returns 32-character hex representation of this objects hash
*
* @return String of this object's hash
*/
public String asHex () {
return asHex(this.Final());
}
/**
* Convenience method for initNativeLibrary(false).
**/
public static synchronized final boolean initNativeLibrary () {
return initNativeLibrary(false);
}
/**
* Attempts to initialize native library support. If
* 'disallow_lib_loading' is true, will indicate that the native
* library should not be loaded now or in the future. If native
* library support has been previously loaded or disabled, this
* method has no effect.
*
* @return true iff native library support has been loaded
**/
public static synchronized final boolean initNativeLibrary (boolean disallow_lib_loading) {
if (disallow_lib_loading) {
native_lib_init_pending = false;
} else {
_initNativeLibrary();
}
return native_lib_loaded;
}
private static synchronized final void _initNativeLibrary () {
if (!native_lib_init_pending) return;
native_lib_loaded = _loadNativeLibrary();
native_lib_init_pending = false;
}
private static synchronized final boolean _loadNativeLibrary () {
try {
// don't try to load if the right property is set
String prop = System.getProperty("com.twmacinta.util.MD5.NO_NATIVE_LIB");
if (prop != null) {
prop = prop.trim();
if (prop.equalsIgnoreCase("true") || prop.equals("1")) return false;
}
// the library to load can be specified as a property
File f;
prop = System.getProperty("com.twmacinta.util.MD5.NATIVE_LIB_FILE");
if (prop != null) {
f = new File(prop);
if (f.canRead()) {
System.load(f.getAbsolutePath());
return true;
}
}
// determine the operating system and architecture
String os_name = System.getProperty("os.name");
String os_arch = System.getProperty("os.arch");
if (os_name == null || os_arch == null) return false;
os_name = os_name.toLowerCase();
os_arch = os_arch.toLowerCase();
// define settings which are OS arch architecture independent
File arch_lib_path = null;
String arch_libfile_suffix = null;
// fill in settings for Linux on x86
if (os_name.equals("linux") &&
(os_arch.equals("x86") ||
os_arch.equals("i386") ||
os_arch.equals("i486") ||
os_arch.equals("i586") ||
os_arch.equals("i686"))) {
arch_lib_path = new File(new File(new File("lib"), "arch"), "linux_x86");
arch_libfile_suffix = ".so";
}
// fill in settings for Linux on amd64
else if (os_name.equals("linux") &&
os_arch.equals("amd64")) {
arch_lib_path = new File(new File(new File("lib"), "arch"), "linux_amd64");
arch_libfile_suffix = ".so";
}
// fill in settings for Windows on x86
else if (os_name.startsWith("windows ") &&
(os_arch.equals("x86") ||
os_arch.equals("i386") ||
os_arch.equals("i486") ||
os_arch.equals("i586") ||
os_arch.equals("i686"))) {
arch_lib_path = new File(new File(new File("lib"), "arch"), "win32_x86");
arch_libfile_suffix = ".dll";
}
// fill in settings for Windows on amd64
else if (os_name.startsWith("windows ") &&
os_arch.equals("amd64")) {
arch_lib_path = new File(new File(new File("lib"), "arch"), "win_amd64");
arch_libfile_suffix = ".dll";
}
// fill in settings for Mac OS X on PPC
else if (os_name.startsWith("mac os x") &&
(os_arch.equals("ppc"))) {
arch_lib_path = new File(new File(new File("lib"), "arch"), "darwin_ppc");
arch_libfile_suffix = ".jnilib";
}
// fill in settings for Mac OS X on x86
else if (os_name.startsWith("mac os x") &&
(os_arch.equals("x86") ||
os_arch.equals("i386") ||
os_arch.equals("i486") ||
os_arch.equals("i586") ||
os_arch.equals("i686"))) {
arch_lib_path = new File(new File(new File("lib"), "arch"), "darwin_x86");
arch_libfile_suffix = ".jnilib";
}
// fill in settings for Mac OS X on x86_64
else if (os_name.startsWith("mac os x") &&
os_arch.equals("x86_64")) {
arch_lib_path = new File(new File(new File("lib"), "arch"), "darwin_x86_64");
arch_libfile_suffix = ".jnilib";
}
// fill in settings for FreeBSD on x86
else if (os_name.equals("freebsd") &&
(os_arch.equals("x86") ||
os_arch.equals("i386") ||
os_arch.equals("i486") ||
os_arch.equals("i586") ||
os_arch.equals("i686"))) {
arch_lib_path = new File(new File(new File("lib"), "arch"), "freebsd_x86");
arch_libfile_suffix = ".so";
}
// fill in settings for FreeBSD on amd64
else if (os_name.equals("freebsd") &&
os_arch.equals("amd64")) {
arch_lib_path = new File(new File(new File("lib"), "arch"), "freebsd_amd64");
arch_libfile_suffix = ".so";
}
// default to .so files with no architecture specific subdirectory
else {
arch_libfile_suffix = ".so";
}
// build the required filename
String fname = "MD5" + arch_libfile_suffix;
// try the architecture specific directory
if (arch_lib_path != null) {
f = new File(arch_lib_path, fname);
if (f.canRead()) {
System.load(f.getAbsolutePath());
return true;
}
}
// try the "lib" subdirectory
f = new File(new File("lib"), fname);
if (f.canRead()) {
System.load(f.getAbsolutePath());
return true;
}
// try the working directory
f = new File(fname);
if (f.canRead()) {
System.load(f.getAbsolutePath());
return true;
}
}
// discard SecurityExceptions
catch (SecurityException e) {}
// Intercept UnsatisfiedLinkError since the code will still
// work without the native method, but report it because it
// indicates that the architecture detection and/or support
// should be updated.
catch (UnsatisfiedLinkError e) {
e.printStackTrace();
}
// unable to load
return false;
}
/**
* Calculates and returns the hash of the contents of the given file.
**/
public static byte[] getHash (File f) throws IOException {
if (!f.exists()) throw new FileNotFoundException(f.toString());
InputStream close_me = null;
try {
long buf_size = f.length();
if (buf_size < 512) buf_size = 512;
if (buf_size > 65536) buf_size = 65536;
byte[] buf = new byte[(int) buf_size];
MD5InputStream in = new MD5InputStream(new FileInputStream(f));
close_me = in;
while (in.read(buf) != -1);
in.close();
return in.hash();
} catch (IOException e) {
if (close_me != null) try { close_me.close(); } catch (Exception e2) {}
throw e;
}
}
/**
* @return true iff the first 16 bytes of both hash1 and hash2 are
* equal; both hash1 and hash2 are null; or either hash
* array is less than 16 bytes in length and their lengths and
* all of their bytes are equal.
**/
public static boolean hashesEqual (byte[] hash1, byte[] hash2) {
if (hash1 == null) return hash2 == null;
if (hash2 == null) return false;
int targ = 16;
if (hash1.length < 16) {
if (hash2.length != hash1.length) return false;
targ = hash1.length;
} else if (hash2.length < 16) {
return false;
}
for (int i = 0; i < targ; i++) {
if (hash1[i] != hash2[i]) return false;
}
return true;
}
}

@ -0,0 +1,169 @@
package com.twmacinta.util;
import java.io.*;
/**
* MD5InputStream, a subclass of FilterInputStream implementing MD5
* functionality on a stream.
* <p>
* Originally written by Santeri Paavolainen, Helsinki Finland 1996 <br>
* (c) Santeri Paavolainen, Helsinki Finland 1996 <br>
* Some changes Copyright (c) 2002 Timothy W Macinta <br>
* <p>
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
* <p>
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
* <p>
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* <p>
* See http://www.twmacinta.com/myjava/fast_md5.php for more information
* on this file.
* <p>
* Please note: I (Timothy Macinta) have put this code in the
* com.twmacinta.util package only because it came without a package. I
* was not the the original author of the code, although I did
* optimize it (substantially) and fix some bugs.
*
* @author Santeri Paavolainen <santtu@cs.hut.fi>
* @author Timothy W Macinta (twm@alum.mit.edu) (added main() method)
**/
public class MD5InputStream extends FilterInputStream {
/**
* MD5 context
*/
private MD5 md5;
/**
* Creates a MD5InputStream
* @param in The input stream
*/
public MD5InputStream (InputStream in) {
super(in);
md5 = new MD5();
}
/**
* Read a byte of data.
* @see java.io.FilterInputStream
*/
public int read() throws IOException {
int c = in.read();
if (c == -1)
return -1;
if ((c & ~0xff) != 0) {
System.out.println("MD5InputStream.read() got character with (c & ~0xff) != 0)!");
} else {
md5.Update(c);
}
return c;
}
/**
* Reads into an array of bytes.
*
* @see java.io.FilterInputStream
*/
public int read (byte bytes[], int offset, int length) throws IOException {
int r;
if ((r = in.read(bytes, offset, length)) == -1)
return r;
md5.Update(bytes, offset, r);
return r;
}
/**
* Returns array of bytes representing hash of the stream as
* finalized for the current state.
* @see MD5#Final
*/
public byte[] hash () {
return md5.Final();
}
public MD5 getMD5() {
return md5;
}
/**
* This method is here for testing purposes only - do not rely
* on it being here.
**/
public static void main(String[] arg) {
try {
////////////////////////////////////////////////////////////////
//
// usage: java com.twmacinta.util.MD5InputStream [--use-default-md5] [--no-native-lib] filename
//
/////////
// determine the filename to use and the MD5 impelementation to use
String filename = arg[arg.length-1];
boolean use_default_md5 = false;
boolean use_native_lib = true;
for (int i = 0; i < arg.length-1; i++) {
if (arg[i].equals("--use-default-md5")) {
use_default_md5 = true;
} else if (arg[i].equals("--no-native-lib")) {
use_native_lib = false;
}
}
// initialize common variables
byte[] buf = new byte[65536];
int num_read;
// Use the default MD5 implementation that comes with Java
if (use_default_md5) {
InputStream in = new BufferedInputStream(new FileInputStream(filename));
java.security.MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
while ((num_read = in.read(buf)) != -1) {
digest.update(buf, 0, num_read);
}
System.out.println(MD5.asHex(digest.digest())+" "+filename);
in.close();
// Use the optimized MD5 implementation
} else {
// disable the native library search, if requested
if (!use_native_lib) {
MD5.initNativeLibrary(true);
}
// calculate the checksum
MD5InputStream in = new MD5InputStream(new BufferedInputStream(new FileInputStream(filename)));
while ((num_read = in.read(buf)) != -1);
System.out.println(MD5.asHex(in.hash())+" "+filename);
in.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

@ -0,0 +1,79 @@
package com.twmacinta.util;
/**
* Fast implementation of RSA's MD5 hash generator in Java JDK Beta-2 or higher<br>
* Originally written by Santeri Paavolainen, Helsinki Finland 1996 <br>
* (c) Santeri Paavolainen, Helsinki Finland 1996 <br>
* Some changes Copyright (c) 2002 Timothy W Macinta <br>
* <p>
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
* <p>
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
* <p>
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* <p>
* See http://www.twmacinta.com/myjava/fast_md5.php for more information
* on this file.
* <p>
* Contains internal state of the MD5 class
* <p>
* Please note: I (Timothy Macinta) have put this code in the
* com.twmacinta.util package only because it came without a package. I
* was not the the original author of the code, although I did
* optimize it (substantially) and fix some bugs.
*
* @author Santeri Paavolainen <sjpaavol@cc.helsinki.fi>
* @author Timothy W Macinta (twm@alum.mit.edu) (optimizations and bug fixes)
**/
class MD5State {
/**
* 128-bit state
*/
int state[];
/**
* 64-bit character count
*/
long count;
/**
* 64-byte buffer (512 bits) for storing to-be-hashed characters
*/
byte buffer[];
public MD5State() {
buffer = new byte[64];
count = 0;
state = new int[4];
state[0] = 0x67452301;
state[1] = 0xefcdab89;
state[2] = 0x98badcfe;
state[3] = 0x10325476;
}
/** Create this State as a copy of another state */
public MD5State (MD5State from) {
this();
int i;
for (i = 0; i < buffer.length; i++)
this.buffer[i] = from.buffer[i];
for (i = 0; i < state.length; i++)
this.state[i] = from.state[i];
this.count = from.count;
}
};
Loading…
Cancel
Save