Java tutorial
/* * Copyright 2011 - AndroidQuery.com (tinyeeliu@gmail.com) * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.androidquery; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.lang.reflect.Constructor; import java.nio.channels.FileChannel; import java.util.Iterator; import java.util.Map; import java.util.WeakHashMap; import org.apache.http.HttpEntity; import org.apache.http.HttpHost; import android.app.Activity; import android.app.Dialog; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Paint; import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.text.Editable; import android.text.Spanned; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnLongClickListener; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import android.view.ViewGroup.MarginLayoutParams; import android.view.ViewParent; import android.view.animation.Animation; import android.view.animation.Animation.AnimationListener; import android.view.animation.AnimationUtils; import android.webkit.WebView; import android.widget.AbsListView; import android.widget.AbsListView.OnScrollListener; import android.widget.Adapter; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemSelectedListener; import android.widget.BaseAdapter; import android.widget.Button; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.EditText; import android.widget.ExpandableListAdapter; import android.widget.ExpandableListView; import android.widget.Gallery; import android.widget.GridView; import android.widget.ImageView; import android.widget.ListView; import android.widget.ProgressBar; import android.widget.RatingBar; import android.widget.SeekBar; import android.widget.Spinner; import android.widget.TextView; import com.androidquery.auth.AccountHandle; import com.androidquery.callback.AbstractAjaxCallback; import com.androidquery.callback.AjaxCallback; import com.androidquery.callback.BitmapAjaxCallback; import com.androidquery.callback.ImageOptions; import com.androidquery.callback.Transformer; import com.androidquery.util.AQUtility; import com.androidquery.util.Common; import com.androidquery.util.Constants; import com.androidquery.util.WebImage; /** * The core class of AQuery. Contains all the methods available from an AQuery object. * * @param <AQuery> the generic type */ public class AQuery implements Constants { private View root; private Activity act; private Context context; protected View view; protected Object progress; protected AccountHandle ah; private Transformer trans; private int policy = Constants.CACHE_DEFAULT; //private Integer policy = null; private HttpHost proxy; protected AQuery create(View view) { AQuery result = null; try { Constructor<AQuery> c = getConstructor(); result = (AQuery) c.newInstance(view); result.act = act; } catch (Exception e) { //should never happen e.printStackTrace(); } return result; } private Constructor<AQuery> constructor; @SuppressWarnings("unchecked") private Constructor<AQuery> getConstructor() { if (constructor == null) { try { constructor = (Constructor<AQuery>) getClass().getConstructor(View.class); } catch (Exception e) { //should never happen e.printStackTrace(); } } return constructor; } /** * Instantiates a new AQuery object. * * @param act Activity that's the parent of the to-be-operated views. */ public AQuery(Activity act) { this.act = act; } /** * Instantiates a new AQuery object. * * @param root View container that's the parent of the to-be-operated views. */ public AQuery(View root) { this.root = root; this.view = root; } /** * Instantiates a new AQuery object. This constructor should be used for Fragments. * * @param act Activity * @param root View container that's the parent of the to-be-operated views. */ public AQuery(Activity act, View root) { this.root = root; this.view = root; this.act = act; } /** * Instantiates a new AQuery object. * * @param context Context that will be used in async operations. */ public AQuery(Context context) { this.context = context; } private View findView(int id) { View result = null; if (root != null) { result = root.findViewById(id); } else if (act != null) { result = act.findViewById(id); } return result; } private View findView(String tag) { //((ViewGroup)findViewById(android.R.id.content)).getChildAt(0) View result = null; if (root != null) { result = root.findViewWithTag(tag); } else if (act != null) { //result = act.findViewById(id); View top = ((ViewGroup) act.findViewById(android.R.id.content)).getChildAt(0); if (top != null) { result = top.findViewWithTag(tag); } } return result; } private View findView(int... path) { View result = findView(path[0]); for (int i = 1; i < path.length && result != null; i++) { result = result.findViewById(path[i]); } return result; } /** * Return a new AQuery object that uses the found view as a root. * * @param id the id * @return new AQuery object */ public AQuery find(int id) { View view = findView(id); return create(view); } /** * Return a new AQuery object that uses the found parent as a root. * If no parent with matching id is found, operating view will be null and isExist() will return false. * * * @param id the parent id * @return new AQuery object */ public AQuery parent(int id) { View node = view; View result = null; while (node != null) { if (node.getId() == id) { result = node; break; } ViewParent p = node.getParent(); if (!(p instanceof View)) break; node = (View) p; } return create(result); } /** * Recycle this AQuery object. * * The method is designed to avoid recreating an AQuery object repeatedly, such as when in list adapter getView method. * * @param root The new root of the recycled AQuery. * @return self */ public AQuery recycle(View root) { this.root = root; this.view = root; reset(); this.context = null; return self(); } @SuppressWarnings("unchecked") private AQuery self() { return (AQuery) this; } /** * Return the current operating view. * * @return the view */ public View getView() { return view; } /** * Points the current operating view to the first view found with the id under the root. * * @param id the id * @return self */ public AQuery id(int id) { return id(findView(id)); } /** * Points the current operating view to the specified view. * * @param view * @return self */ public AQuery id(View view) { this.view = view; reset(); return self(); } /** * Points the current operating view to the specified view with tag. * * @param tag * @return self */ public AQuery id(String tag) { return id(findView(tag)); } /** * Find the first view with first id, under that view, find again with 2nd id, etc... * * @param path The id path. * @return self */ public AQuery id(int... path) { return id(findView(path)); } /** * Find the progress bar and show the progress for the next ajax/image request. * Once ajax or image is called, current progress view is consumed. * Subsequent ajax/image calls won't show progress view unless progress is called again. * * If a file or network requests is required, the progress bar is set to be "VISIBLE". * Once the requests completes, progress bar is set to "GONE". * * @param id the id of the progress bar to be shown * @return self */ public AQuery progress(int id) { progress = findView(id); return self(); } /** * Set the progress bar and show the progress for the next ajax/image request. * * Once ajax or image is called, current progress view is consumed. * Subsequent ajax/image calls won't show progress view unless progress is called again. * * If a file or network requests is required, the progress bar is set to be "VISIBLE". * Once the requests completes, progress bar is set to "GONE". * * @param view the progress bar to be shown * @return self */ public AQuery progress(Object view) { progress = view; return self(); } /** * Set the progress dialog and show the progress for the next ajax/image request. * * Progress dialogs cannot be reused. They are dismissed on ajax callback. * * If a file or network requests is required, the dialog is shown. * Once the requests completes, dialog is dismissed. * * It's the caller responsibility to dismiss the dialog when the activity terminates before the ajax is completed. * Calling aq.dismiss() in activity's onDestroy() will ensure all dialogs are properly dismissed. * * @param dialog * @return self */ public AQuery progress(Dialog dialog) { progress = dialog; return self(); } /** * Apply the account handler for authentication for the next ajax request. * * @param handle the account handler * @return self */ public AQuery auth(AccountHandle handle) { ah = handle; return self(); } /** * Apply the transformer to convert raw data to desired object type for the next ajax request. * * @param transformer transformer * @return self */ public AQuery transformer(Transformer transformer) { trans = transformer; return self(); } public AQuery policy(int cachePolicy) { policy = cachePolicy; return self(); } /** * Apply the proxy info to next ajax request. * * @param transformer transformer * @return self */ public AQuery proxy(String host, int port) { proxy = new HttpHost(host, port); return self(); } /** * Set the rating of a RatingBar. * * @param rating the rating * @return self */ public AQuery rating(float rating) { if (view instanceof RatingBar) { RatingBar rb = (RatingBar) view; rb.setRating(rating); } return self(); } /** * Set the text of a TextView. * * @param resid the resid * @return self */ public AQuery text(int resid) { if (view instanceof TextView) { TextView tv = (TextView) view; tv.setText(resid); } return self(); } /** * Set the text of a TextView with localized formatted string * from application's package's default string table * * @param resid the resid * @return self * @see Context#getString(int, Object...) */ public AQuery text(int resid, Object... formatArgs) { Context context = getContext(); if (context != null) { CharSequence text = context.getString(resid, formatArgs); text(text); } return self(); } /** * Set the text of a TextView. * * @param text the text * @return self */ public AQuery text(CharSequence text) { if (view instanceof TextView) { TextView tv = (TextView) view; tv.setText(text); } return self(); } /** * Set the text of a TextView. Hide the view (gone) if text is empty. * * @param text the text * @param goneIfEmpty hide if text is null or length is 0 * @return self */ public AQuery text(CharSequence text, boolean goneIfEmpty) { if (goneIfEmpty && (text == null || text.length() == 0)) { return gone(); } else { return text(text); } } /** * Set the text of a TextView. * * @param text the text * @return self */ public AQuery text(Spanned text) { if (view instanceof TextView) { TextView tv = (TextView) view; tv.setText(text); } return self(); } /** * Set the text color of a TextView. * * @param color the color * @return self */ public AQuery textColor(int color) { if (view instanceof TextView) { TextView tv = (TextView) view; tv.setTextColor(color); } return self(); } /** * Set the text typeface of a TextView. * * @param typeface typeface * @return self */ public AQuery typeface(Typeface tf) { if (view instanceof TextView) { TextView tv = (TextView) view; tv.setTypeface(tf); } return self(); } /** * Set the text size (in sp) of a TextView. * * @param size size * @return self */ public AQuery textSize(float size) { if (view instanceof TextView) { TextView tv = (TextView) view; tv.setTextSize(size); } return self(); } /** * Set the adapter of an AdapterView. * * @param adapter adapter * @return self */ @SuppressWarnings({ "unchecked", "rawtypes" }) public AQuery adapter(Adapter adapter) { if (view instanceof AdapterView) { AdapterView av = (AdapterView) view; av.setAdapter(adapter); } return self(); } /** * Set the adapter of an ExpandableListView. * * @param adapter adapter * @return self */ public AQuery adapter(ExpandableListAdapter adapter) { if (view instanceof ExpandableListView) { ExpandableListView av = (ExpandableListView) view; av.setAdapter(adapter); } return self(); } /** * Set the image of an ImageView. * * @param resid the resource id * @return self * * @see testImage1 */ public AQuery image(int resid) { if (view instanceof ImageView) { ImageView iv = (ImageView) view; iv.setTag(AQuery.TAG_URL, null); if (resid == 0) { iv.setImageBitmap(null); } else { iv.setImageResource(resid); } } return self(); } /** * Set the image of an ImageView. * * @param drawable the drawable * @return self * * @see testImage2 * */ public AQuery image(Drawable drawable) { if (view instanceof ImageView) { ImageView iv = (ImageView) view; iv.setTag(AQuery.TAG_URL, null); iv.setImageDrawable(drawable); } return self(); } /** * Set the image of an ImageView. * * @param bm Bitmap * @return self * * @see testImage3 */ public AQuery image(Bitmap bm) { if (view instanceof ImageView) { ImageView iv = (ImageView) view; iv.setTag(AQuery.TAG_URL, null); iv.setImageBitmap(bm); } return self(); } /** * Set the image of an ImageView. * * @param url Image url. * @return self * * @see testImage4 */ public AQuery image(String url) { return image(url, true, true, 0, 0); } /** * Set the image of an ImageView. * * @param url The image url. * @param memCache Use memory cache. * @param fileCache Use file cache. * @return self * * @see testImage5 */ public AQuery image(String url, boolean memCache, boolean fileCache) { return image(url, memCache, fileCache, 0, 0); } /** * Set the image of an ImageView. * * @param url The image url. * @param memCache Use memory cache. * @param fileCache Use file cache. * @param targetWidth Target width for down sampling when reading large images. 0 = no downsampling. * @param fallbackId Fallback image if result is network fetch and image convert failed. 0 = no fallback. * @return self * * @see testImage6 */ public AQuery image(String url, boolean memCache, boolean fileCache, int targetWidth, int fallbackId) { return image(url, memCache, fileCache, targetWidth, fallbackId, null, 0); } /** * Set the image of an ImageView. * * @param url The image url. * @param memCache Use memory cache. * @param fileCache Use file cache. * @param targetWidth Target width for down sampling when reading large images. 0 = no downsampling. * @param fallbackId Fallback image if result is network fetch and image convert failed. 0 = no fallback. * @param preset Default image to show before real image loaded. null = no preset. * @param animId Apply this animation when image is loaded. 0 = no animation. Also accept AQuery.FADE_IN as a predefined 500ms fade in animation. * @return self * * @see testImage7 * */ public AQuery image(String url, boolean memCache, boolean fileCache, int targetWidth, int fallbackId, Bitmap preset, int animId) { return image(url, memCache, fileCache, targetWidth, fallbackId, preset, animId, 0); } /** * Set the image of an ImageView. * * @param url The image url. * @param memCache Use memory cache. * @param fileCache Use file cache. * @param targetWidth Target width for down sampling when reading large images. 0 = no downsampling. * @param fallbackId Fallback image if result is network fetch and image convert failed. 0 = no fallback. * @param preset Default image to show before real image loaded. null = no preset. * @param animId Apply this animation when image is loaded. 0 = no animation. Also accept AQuery.FADE_IN as a predefined 500ms fade in animation. * @param ratio The desired aspect ratio of the imageview. Ratio is height / width, or AQuery.RATIO_PRESERVE to preserve the original aspect ratio of the image. * @return self * * @see testImage12 * */ public AQuery image(String url, boolean memCache, boolean fileCache, int targetWidth, int fallbackId, Bitmap preset, int animId, float ratio) { return image(url, memCache, fileCache, targetWidth, fallbackId, preset, animId, ratio, 0, null); } protected AQuery image(String url, boolean memCache, boolean fileCache, int targetWidth, int fallbackId, Bitmap preset, int animId, float ratio, int round, String networkUrl) { if (view instanceof ImageView) { BitmapAjaxCallback.async(act, getContext(), (ImageView) view, url, memCache, fileCache, targetWidth, fallbackId, preset, animId, ratio, AQuery.ANCHOR_DYNAMIC, progress, ah, policy, round, proxy, networkUrl); reset(); } return self(); } public AQuery image(String url, ImageOptions options) { return image(url, options, null); } protected AQuery image(String url, ImageOptions options, String networkUrl) { if (view instanceof ImageView) { BitmapAjaxCallback.async(act, getContext(), (ImageView) view, url, progress, ah, options, proxy, networkUrl); reset(); } return self(); } /** * Set the image of an ImageView with a custom callback. * * @param callback Callback handler for setting the image. * @return self * * @see testImage8 */ public AQuery image(BitmapAjaxCallback callback) { if (view instanceof ImageView) { callback.imageView((ImageView) view); invoke(callback); } return self(); } /** * Set the image of an ImageView with a custom callback. * * @param url The image url. * @param memCache Use memory cache. * @param fileCache Use file cache. * @param targetWidth Target width for down sampling when reading large images. * @param resId Fallback image if result is network fetch and image convert failed. * @param callback Callback handler for setting the image. * @return self * * @see testImage9 */ public AQuery image(String url, boolean memCache, boolean fileCache, int targetWidth, int resId, BitmapAjaxCallback callback) { callback.targetWidth(targetWidth).fallback(resId).url(url).memCache(memCache).fileCache(fileCache); return image(callback); } /** * Set the image of an ImageView from a file. * * @param file The image file. * @param targetWidth Target width for down sampling when reading large images. * @return self * * @see testImage10 */ public AQuery image(File file, int targetWidth) { return image(file, true, targetWidth, null); } /** * Set the image of an ImageView from a file with a custom callback. * * @param file The image file. * @param memCache Use memory cache. * @param targetWidth Target width for down sampling when reading large images. * @param callback Callback handler for setting the image. * @return self * * @see testImage11 */ public AQuery image(File file, boolean memCache, int targetWidth, BitmapAjaxCallback callback) { if (callback == null) callback = new BitmapAjaxCallback(); callback.file(file); String url = null; if (file != null) url = file.getAbsolutePath(); return image(url, memCache, true, targetWidth, 0, callback); } /** * Set the image of an ImageView from a file with aspect ratio. * * @param bm The image bitmap. * @param ratio The desired aspect ratio of the imageview. Ratio is height / width, or AQuery.RATIO_PRESERVE to preserve the original aspect ratio of the image. * * @return self * */ public AQuery image(Bitmap bm, float ratio) { BitmapAjaxCallback cb = new BitmapAjaxCallback(); cb.ratio(ratio).bitmap(bm); return image(cb); } /** * Set tag object of a view. * * @param tag * @return self */ public AQuery tag(Object tag) { if (view != null) { view.setTag(tag); } return self(); } /** * Set tag object of a view. * * @param key * @param tag * @return self */ public AQuery tag(int key, Object tag) { if (view != null) { view.setTag(key, tag); } return self(); } /** * Set a view to be transparent. * * @param transparent the transparent * @return self */ public AQuery transparent(boolean transparent) { if (view != null) { AQUtility.transparent(view, transparent); } return self(); } /** * Enable a view. * * @param enabled state * @return self */ public AQuery enabled(boolean enabled) { if (view != null) { view.setEnabled(enabled); } return self(); } /** * Set checked state of a compound button. * * @param checked state * @return self */ public AQuery checked(boolean checked) { if (view instanceof CompoundButton) { CompoundButton cb = (CompoundButton) view; cb.setChecked(checked); } return self(); } /** * Get checked state of a compound button. * * @return checked */ public boolean isChecked() { boolean checked = false; if (view instanceof CompoundButton) { CompoundButton cb = (CompoundButton) view; checked = cb.isChecked(); } return checked; } /** * Set clickable for a view. * * @param clickable * @return self */ public AQuery clickable(boolean clickable) { if (view != null) { view.setClickable(clickable); } return self(); } /** * Set view visibility to View.GONE. * * @return self */ public AQuery gone() { /* if(view != null && view.getVisibility() != View.GONE){ view.setVisibility(View.GONE); } return self(); */ return visibility(View.GONE); } /** * Set view visibility to View.INVISIBLE. * * @return self */ public AQuery invisible() { /* if(view != null && view.getVisibility() != View.INVISIBLE){ view.setVisibility(View.INVISIBLE); } return self(); */ return visibility(View.INVISIBLE); } /** * Set view visibility to View.VISIBLE. * * @return self */ public AQuery visible() { /* if(view != null && view.getVisibility() != View.VISIBLE){ view.setVisibility(View.VISIBLE); } return self(); */ return visibility(View.VISIBLE); } /** * Set view visibility, such as View.VISIBLE. * * @return self */ public AQuery visibility(int visibility) { if (view != null && view.getVisibility() != visibility) { view.setVisibility(visibility); } return self(); } /** * Set view background. * * @param id the id * @return self */ public AQuery background(int id) { if (view != null) { if (id != 0) { view.setBackgroundResource(id); } else { view.setBackgroundDrawable(null); } } return self(); } /** * Set view background color. * * @param color * @return self */ public AQuery backgroundColor(int color) { if (view != null) { view.setBackgroundColor(color); } return self(); } /** * Notify a ListView that the data of it's adapter is changed. * * @return self */ public AQuery dataChanged() { if (view instanceof AdapterView) { AdapterView<?> av = (AdapterView<?>) view; Adapter a = av.getAdapter(); if (a instanceof BaseAdapter) { BaseAdapter ba = (BaseAdapter) a; ba.notifyDataSetChanged(); } } return self(); } /** * Checks if the current view exist. * * @return true, if is exist */ public boolean isExist() { return view != null; } /** * Gets the tag of the view. * * @return tag */ public Object getTag() { Object result = null; if (view != null) { result = view.getTag(); } return result; } /** * Gets the tag of the view. * @param id the id * * @return tag */ public Object getTag(int id) { Object result = null; if (view != null) { result = view.getTag(id); } return result; } /** * Gets the current view as an image view. * * @return ImageView */ public ImageView getImageView() { return (ImageView) view; } /** * Gets the current view as an Gallery. * * @return Gallery */ public Gallery getGallery() { return (Gallery) view; } /** * Gets the current view as a text view. * * @return TextView */ public TextView getTextView() { return (TextView) view; } /** * Gets the current view as an edit text. * * @return EditText */ public EditText getEditText() { return (EditText) view; } /** * Gets the current view as an progress bar. * * @return ProgressBar */ public ProgressBar getProgressBar() { return (ProgressBar) view; } /** * Gets the current view as seek bar. * * @return SeekBar */ public SeekBar getSeekBar() { return (SeekBar) view; } /** * Gets the current view as a button. * * @return Button */ public Button getButton() { return (Button) view; } /** * Gets the current view as a checkbox. * * @return CheckBox */ public CheckBox getCheckBox() { return (CheckBox) view; } /** * Gets the current view as a listview. * * @return ListView */ public ListView getListView() { return (ListView) view; } /** * Gets the current view as a ExpandableListView. * * @return ExpandableListView */ public ExpandableListView getExpandableListView() { return (ExpandableListView) view; } /** * Gets the current view as a gridview. * * @return GridView */ public GridView getGridView() { return (GridView) view; } /** * Gets the current view as a RatingBar. * * @return RatingBar */ public RatingBar getRatingBar() { return (RatingBar) view; } /** * Gets the current view as a webview. * * @return WebView */ public WebView getWebView() { return (WebView) view; } /** * Gets the current view as a spinner. * * @return Spinner */ public Spinner getSpinner() { return (Spinner) view; } /** * Gets the editable. * * @return the editable */ public Editable getEditable() { Editable result = null; if (view instanceof EditText) { result = ((EditText) view).getEditableText(); } return result; } /** * Gets the text of a TextView. * * @return the text */ public CharSequence getText() { CharSequence result = null; if (view instanceof TextView) { result = ((TextView) view).getText(); } return result; } /** * Gets the selected item if current view is an adapter view. * * @return selected */ public Object getSelectedItem() { Object result = null; if (view instanceof AdapterView<?>) { result = ((AdapterView<?>) view).getSelectedItem(); } return result; } /** * Gets the selected item position if current view is an adapter view. * * Returns AdapterView.INVALID_POSITION if not valid. * * @return selected position */ public int getSelectedItemPosition() { int result = AdapterView.INVALID_POSITION; if (view instanceof AdapterView<?>) { result = ((AdapterView<?>) view).getSelectedItemPosition(); } return result; } private static final Class<?>[] ON_CLICK_SIG = { View.class }; /** * Register a callback method for when the view is clicked. Method must have signature of method(View view). * * @param handler The handler that has the public callback method. * @param method The method name of the callback. * @return self */ public AQuery clicked(Object handler, String method) { Common common = new Common().forward(handler, method, true, ON_CLICK_SIG); return clicked(common); } /** * Register a callback method for when the view is clicked. * * @param listener The callback method. * @return self */ public AQuery clicked(OnClickListener listener) { if (view != null) { view.setOnClickListener(listener); } return self(); } /** * Register a callback method for when the view is long clicked. Method must have signature of method(View view). * * @param handler The handler that has the public callback method. * @param method The method name of the callback. * @return self */ public AQuery longClicked(Object handler, String method) { Common common = new Common().forward(handler, method, true, ON_CLICK_SIG); return longClicked(common); } /** * Register a callback method for when the view is long clicked. * * @param listener The callback method. * @return self */ public AQuery longClicked(OnLongClickListener listener) { if (view != null) { view.setOnLongClickListener(listener); } return self(); } private static Class<?>[] ON_ITEM_SIG = { AdapterView.class, View.class, int.class, long.class }; /** * Register a callback method for when an item is clicked in the ListView. Method must have signature of method(AdapterView<?> parent, View v, int pos, long id). * * @param handler The handler that has the public callback method. * @param method The method name of the callback. * @return self */ public AQuery itemClicked(Object handler, String method) { Common common = new Common().forward(handler, method, true, ON_ITEM_SIG); return itemClicked(common); } /** * Register a callback method for when an item is clicked in the ListView. * * @param listener The callback method. * @return self */ public AQuery itemClicked(OnItemClickListener listener) { if (view instanceof AdapterView) { AdapterView<?> alv = (AdapterView<?>) view; alv.setOnItemClickListener(listener); } return self(); } /** * Register a callback method for when an item is selected. Method must have signature of method(AdapterView<?> parent, View v, int pos, long id). * * @param handler The handler that has the public callback method. * @param method The method name of the callback. * @return self */ public AQuery itemSelected(Object handler, String method) { Common common = new Common().forward(handler, method, true, ON_ITEM_SIG); return itemSelected(common); } /** * Register a callback method for when an item is selected. * * @param listener The item selected listener. * @return self */ public AQuery itemSelected(OnItemSelectedListener listener) { if (view instanceof AdapterView) { AdapterView<?> alv = (AdapterView<?>) view; alv.setOnItemSelectedListener(listener); } return self(); } /** * Set selected item of an AdapterView. * * @param position The position of the item to be selected. * @return self */ public AQuery setSelection(int position) { if (view instanceof AdapterView) { AdapterView<?> alv = (AdapterView<?>) view; alv.setSelection(position); } return self(); } private static Class<?>[] ON_SCROLLED_STATE_SIG = { AbsListView.class, int.class }; /** * Register a callback method for when a list is scrolled to bottom. Method must have signature of method(AbsListView view, int scrollState). * * @param handler The handler that has the public callback method. * @param method The method name of the callback. * @return self */ public AQuery scrolledBottom(Object handler, String method) { if (view instanceof AbsListView) { setScrollListener().forward(handler, method, true, ON_SCROLLED_STATE_SIG); } return self(); } private Common setScrollListener() { AbsListView lv = (AbsListView) view; Common common = (Common) lv.getTag(AQuery.TAG_SCROLL_LISTENER); if (common == null) { common = new Common(); lv.setOnScrollListener(common); lv.setTag(AQuery.TAG_SCROLL_LISTENER, common); AQUtility.debug("set scroll listenr"); } return common; } /** * Register an on scroll listener to a list view, grid view (or any AbsListView). * * @param listener * @return self */ public AQuery scrolled(OnScrollListener listener) { if (view instanceof AbsListView) { setScrollListener().forward(listener); } return self(); } private static final Class<?>[] TEXT_CHANGE_SIG = { CharSequence.class, int.class, int.class, int.class }; /** * Register a callback method for when a textview text is changed. Method must have signature of method(CharSequence s, int start, int before, int count)). * * @param handler The handler that has the public callback method. * @param method The method name of the callback. * @return self */ public AQuery textChanged(Object handler, String method) { if (view instanceof TextView) { TextView tv = (TextView) view; Common common = new Common().forward(handler, method, true, TEXT_CHANGE_SIG); tv.addTextChangedListener(common); } return self(); } private static Class<?>[] PENDING_TRANSITION_SIG = { int.class, int.class }; /** * Call the overridePendingTransition of the activity. Only applies when device API is 5+. * * @param enterAnim the enter animation * @param exitAnim the exit animation * @return self */ public AQuery overridePendingTransition5(int enterAnim, int exitAnim) { if (act != null) { AQUtility.invokeHandler(act, "overridePendingTransition", false, false, PENDING_TRANSITION_SIG, enterAnim, exitAnim); } return self(); } private static final Class<?>[] OVER_SCROLL_SIG = { int.class }; /** * Call the setOverScrollMode of the view. Only applies when device API is 9+. * * @param mode AQuery.OVER_SCROLL_ALWAYS, AQuery.OVER_SCROLL_ALWAYS, AQuery.OVER_SCROLL_IF_CONTENT_SCROLLS * @return self */ public AQuery setOverScrollMode9(int mode) { if (view instanceof AbsListView) { AQUtility.invokeHandler(view, "setOverScrollMode", false, false, OVER_SCROLL_SIG, mode); } return self(); } private static Class<?>[] LAYER_TYPE_SIG = { int.class, Paint.class }; /** * Call the setLayerType of the view. Only applies when device API is 11+. * * Type must be AQuery.LAYER_TYPE_SOFTWARE or AQuery.LAYER_TYPE_HARDWARE. * * @param type the type * @param paint the paint * @return self */ public AQuery setLayerType11(int type, Paint paint) { if (view != null) { AQUtility.invokeHandler(view, "setLayerType", false, false, LAYER_TYPE_SIG, type, paint); } return self(); } /** * Invoke the method on the current view. * * @param method The name of the method * @param sig The signature of the method * @param params Input parameters * @return object The returning object of the method. Null if no such method or return void. */ public Object invoke(String method, Class<?>[] sig, Object... params) { Object handler = view; if (handler == null) handler = act; return AQUtility.invokeHandler(handler, method, false, false, sig, params); } /** * Set the activity to be hardware accelerated. Only applies when device API is 11+. * * @return self */ public AQuery hardwareAccelerated11() { if (act != null) { act.getWindow().setFlags(AQuery.FLAG_HARDWARE_ACCELERATED, AQuery.FLAG_HARDWARE_ACCELERATED); } return self(); } /** * Clear a view. Applies to ImageView, WebView, and TextView. * * @return self */ public AQuery clear() { if (view != null) { if (view instanceof ImageView) { ImageView iv = ((ImageView) view); iv.setImageBitmap(null); iv.setTag(AQuery.TAG_URL, null); } else if (view instanceof WebView) { WebView wv = ((WebView) view); wv.stopLoading(); wv.clearView(); wv.setTag(AQuery.TAG_URL, null); } else if (view instanceof TextView) { TextView tv = ((TextView) view); tv.setText(""); } } return self(); } /** * Set the margin of a view. Notes all parameters are in DIP, not in pixel. * * @param leftDip the left dip * @param topDip the top dip * @param rightDip the right dip * @param bottomDip the bottom dip * @return self */ public AQuery margin(float leftDip, float topDip, float rightDip, float bottomDip) { if (view != null) { LayoutParams lp = view.getLayoutParams(); if (lp instanceof MarginLayoutParams) { Context context = getContext(); int left = AQUtility.dip2pixel(context, leftDip); int top = AQUtility.dip2pixel(context, topDip); int right = AQUtility.dip2pixel(context, rightDip); int bottom = AQUtility.dip2pixel(context, bottomDip); ((MarginLayoutParams) lp).setMargins(left, top, right, bottom); view.setLayoutParams(lp); } } return self(); } /** * Set the width of a view in dip. * Can also be ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, or ViewGroup.LayoutParams.MATCH_PARENT. * * @param dip width in dip * @return self */ public AQuery width(int dip) { size(true, dip, true); return self(); } /** * Set the height of a view in dip. * Can also be ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, or ViewGroup.LayoutParams.MATCH_PARENT. * * @param dip height in dip * @return self */ public AQuery height(int dip) { size(false, dip, true); return self(); } /** * Set the width of a view in dip or pixel. * Can also be ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, or ViewGroup.LayoutParams.MATCH_PARENT. * * @param width width * @param dip dip or pixel * @return self */ public AQuery width(int width, boolean dip) { size(true, width, dip); return self(); } /** * Set the height of a view in dip or pixel. * Can also be ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, or ViewGroup.LayoutParams.MATCH_PARENT. * * @param height height * @param dip dip or pixel * @return self */ public AQuery height(int height, boolean dip) { size(false, height, dip); return self(); } private void size(boolean width, int n, boolean dip) { if (view != null) { LayoutParams lp = view.getLayoutParams(); Context context = getContext(); if (n > 0 && dip) { n = AQUtility.dip2pixel(context, n); } if (width) { lp.width = n; } else { lp.height = n; } view.setLayoutParams(lp); } } /** * Return the context of activity or view. * * @return Context */ public Context getContext() { if (act != null) { return act; } if (root != null) { return root.getContext(); } return context; } /** * Advanced Ajax callback. User must manually prepare the callback object settings (url, type, etc...) by using its methods. * * @param callback callback handler * @return self * * @see testAjax1 */ public <K> AQuery ajax(AjaxCallback<K> callback) { return invoke(callback); } protected <K> AQuery invoke(AbstractAjaxCallback<?, K> cb) { if (ah != null) { cb.auth(ah); } if (progress != null) { cb.progress(progress); } if (trans != null) { cb.transformer(trans); } //if(policy != null){ cb.policy(policy); //} if (proxy != null) { cb.proxy(proxy.getHostName(), proxy.getPort()); } if (act != null) { cb.async(act); } else { cb.async(getContext()); } reset(); return self(); } protected void reset() { ah = null; progress = null; trans = null; policy = CACHE_DEFAULT; proxy = null; } /** * Ajax call with various callback data types. * * @param url url * @param type data type * @param callback callback handler * @return self * */ public <K> AQuery ajax(String url, Class<K> type, AjaxCallback<K> callback) { callback.type(type).url(url); return ajax(callback); } /** * Ajax call with various callback data types with file caching. * * The expire param is the duration to consider cached data expired (if hit). * For example, expire = 15 * 60 * 1000 means if the cache data is within 15 minutes old, * return cached data immediately, otherwise go fetch the source again. * * * @param url url * @param type data type * @param expire duration in millseconds, 0 = always use cache * @param callback callback handler * @return self * * */ public <K> AQuery ajax(String url, Class<K> type, long expire, AjaxCallback<K> callback) { callback.type(type).url(url).fileCache(true).expire(expire); return ajax(callback); } /** * Ajax call with various callback data types. * * The handler signature must be (String url, <K> object, AjaxStatus status) * * @param url url * @param type data type * @param handler the handler object with the callback method to be called * @param callback callback method name * @return self * * */ public <K> AQuery ajax(String url, Class<K> type, Object handler, String callback) { AjaxCallback<K> cb = new AjaxCallback<K>(); cb.type(type).weakHandler(handler, callback); return ajax(url, type, cb); } /** * Ajax call with various callback data types with file caching. * * The expire param is the duration to consider cache data expired (if hit). * For example, expire = 15 * 60 * 1000 means if the cache data is within 15 minutes old, * return cached data immediately, otherwise go fetch the source again. * * * @param url url * @param type data type * @param expire duration in millseconds, 0 = always use cache * @param handler the handler object with the callback method to be called * @param callback callback method name * @return self * * */ public <K> AQuery ajax(String url, Class<K> type, long expire, Object handler, String callback) { AjaxCallback<K> cb = new AjaxCallback<K>(); cb.type(type).weakHandler(handler, callback).fileCache(true).expire(expire); return ajax(url, type, cb); } /** * Ajax call with POST method. * * The handler signature must be (String url, <K> object, AjaxStatus status) * * @param url url * @param params * @param type data type * @param callback callback method name * @return self * * */ public <K> AQuery ajax(String url, Map<String, ?> params, Class<K> type, AjaxCallback<K> callback) { callback.type(type).url(url).params(params); return ajax(callback); } /** * Ajax call with POST method. * * The handler signature must be (String url, <K> object, AjaxStatus status) * * @param url url * @param params * @param type data type * @param callback callback method name * @return self * * */ public <K> AQuery ajax(String url, Map<String, ?> params, Class<K> type, Object handler, String callback) { AjaxCallback<K> cb = new AjaxCallback<K>(); cb.type(type).weakHandler(handler, callback); return ajax(url, params, type, cb); } /** * Ajax HTTP delete. * * @param url url * @param type data type * @param callback callback handler * @return self * */ public <K> AQuery delete(String url, Class<K> type, AjaxCallback<K> callback) { callback.url(url).type(type).method(AQuery.METHOD_DELETE); return ajax(callback); } /** * Ajax HTTP put. * * @param url url * @param contentHeader Content-Type header * @param type reponse type * @param callback callback * @return self * */ public <K> AQuery put(String url, String contentHeader, HttpEntity entity, Class<K> type, AjaxCallback<K> callback) { callback.url(url).type(type).method(AQuery.METHOD_PUT).header("Content-Type", contentHeader) .param(AQuery.POST_ENTITY, entity); return ajax(callback); } /** * Ajax HTTP delete. * * The handler signature must be (String url, <K> object, AjaxStatus status) * * @param url url * @param type data type * @param handler the handler object with the callback method to be called * @param callback callback method name * @return self * * */ public <K> AQuery delete(String url, Class<K> type, Object handler, String callback) { AjaxCallback<K> cb = new AjaxCallback<K>(); cb.weakHandler(handler, callback); return delete(url, type, cb); } /** * Ajax call with that block until response is ready. This method cannot be called on UI thread. * * * @param callback callback * @return self * */ public <K> AQuery sync(AjaxCallback<K> callback) { ajax(callback); callback.block(); return self(); } /** * Cache the url to file cache without any callback. * * * @param url url to cache * @param expire duration in millseconds, 0 = never consider cached data as expired * * @return self * * @see testCache */ public AQuery cache(String url, long expire) { return ajax(url, byte[].class, expire, null, null); } /** * Stop all ajax activities. Should only be called when app exits. * * * @return self */ public AQuery ajaxCancel() { AjaxCallback.cancel(); return self(); } /** * Return file cached by ajax or image requests. Returns null if url is not cached. * * @param url * @return File */ public File getCachedFile(String url) { //return AQUtility.getExistedCacheByUrl(AQUtility.getCacheDir(getContext()), url); File result = AQUtility.getExistedCacheByUrl(AQUtility.getCacheDir(getContext(), AQuery.CACHE_PERSISTENT), url); if (result == null) result = AQUtility.getExistedCacheByUrl(AQUtility.getCacheDir(getContext(), AQuery.CACHE_DEFAULT), url); return result; } /** * Delete any cached file for the url. * * @param url * @return self */ public AQuery invalidate(String url) { File file = getCachedFile(url); if (file != null) file.delete(); return self(); } /** * Return bitmap cached by image requests. Returns null if url is not cached. * * @param url * @return Bitmap */ public Bitmap getCachedImage(String url) { return getCachedImage(url, 0); } /** * Return bitmap cached by image requests. Returns null if url is not cached. * * @param url * @param targetWidth The desired downsampled width. * * @return Bitmap */ public Bitmap getCachedImage(String url, int targetWidth) { Bitmap result = BitmapAjaxCallback.getMemoryCached(url, targetWidth); if (result == null) { File file = getCachedFile(url); if (file != null) { result = BitmapAjaxCallback.getResizedImage(file.getAbsolutePath(), null, targetWidth, true, 0); } } return result; } /** * Return cached bitmap with a resourceId. Returns null if url is not cached. * * Use this method instead of BitmapFactory.decodeResource(getResources(), resId) for caching. * * @param resId * * @return Bitmap */ public Bitmap getCachedImage(int resId) { return BitmapAjaxCallback.getMemoryCached(getContext(), resId); } /** * @deprecated As of release 0.21.3, replaced by shouldDelay(int position, View convertView, ViewGroup parent, String url) * * This method is less efficient and promote file check which could hold up the UI thread. * * {@link #shouldDelay(int position, View convertView, ViewGroup parent, String url)} */ @Deprecated public boolean shouldDelay(View convertView, ViewGroup parent, String url, float velocity) { return Common.shouldDelay(convertView, parent, url, velocity, true); } /** * @deprecated As of release 0.21.3, replaced by shouldDelay(int position, View convertView, ViewGroup parent, String url) * * This method is less efficient and promote file check which could hold up the UI thread. * * {@link #shouldDelay(int position, View convertView, ViewGroup parent, String url)} */ @Deprecated public boolean shouldDelay(View convertView, ViewGroup parent, String url, float velocity, boolean fileCheck) { return Common.shouldDelay(convertView, parent, url, velocity, fileCheck); } /** * Determines if a group item of an expandable list should delay loading a url resource. * * Designed to be used inside * getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) of an expandable list adapter. * * @param groupPosition the group position of the item * @param isExpanded the group is expanded * @param convertView the list item view * @param parent the parent input of getView * @param url the content url to be checked if cached and is available immediately * * @return delay should delay loading a particular resource */ public boolean shouldDelay(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent, String url) { return Common.shouldDelay(groupPosition, -1, convertView, parent, url); } /** * Determines if a child item of an expandable list item should delay loading a url resource. * * Designed to be used inside * getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) of an expandable list adapter. * * @param groupPosition the group position of the item * @param childPosition the child position of the item * @param isLastChild the item is last child * @param convertView the list item view * @param parent the parent input of getView * @param url the content url to be checked if cached and is available immediately * * @return delay should delay loading a particular resource */ public boolean shouldDelay(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent, String url) { return Common.shouldDelay(groupPosition, childPosition, convertView, parent, url); } /** * Determines if a list or gallery view item should delay loading a url resource because the view is scrolling very fast. * The primary purpose of this method is to skip loading remote resources (such as images) over the internet * until the list stop flinging and the user is focusing on the displaying items. * * If the scrolling stops and there are delayed items displaying, the getView method will be called again to force * the delayed items to be redrawn. During redraw, this method will always return false, thus allowing a particular * resource to be loaded. * * Designed to be used inside getView(int position, View convertView, ViewGroup parent) of an adapter. * * * <br> * <br> * Example usage: * <pre> * public View getView(int position, View convertView, ViewGroup parent) { * * ... * * if(aq.shouldDelay(position, convertView, parent, tbUrl)){ * aq.id(R.id.tb).image(placeholder); * }else{ * aq.id(R.id.tb).image(tbUrl, true, true, 0, 0, placeholder, 0, 0); * } * * ... * * } * </pre> * * <br> * NOTE: * * <br> * This method uses the setOnScrollListener() method and will override any previously non-aquery assigned scroll listener. * If a scrolled listener is required, use the aquery method scrolled(OnScrollListener listener) to set the listener * instead of directly calling setOnScrollListener(). * * @param position the position of the item * @param convertView the list item view * @param parent the parent input of getView * @param url the content url to be checked if cached and is available immediately * * @return delay should delay loading a particular resource */ public boolean shouldDelay(int position, View convertView, ViewGroup parent, String url) { if (parent instanceof ExpandableListView) { throw new IllegalArgumentException("Please use the other shouldDelay methods for expandable list."); } return Common.shouldDelay(position, convertView, parent, url); } /** * Create a temporary file on EXTERNAL storage (sdcard) that holds the cached content of the url. * Returns null if url is not cached, or the system cannot create such file (sdcard is absent, such as in emulator). * * The returned file is accessable to all apps, therefore it is ideal for sharing content (such as photo) via the intent mechanism. * * <br> * <br> * Example Usage: * * <pre> * Intent intent = new Intent(Intent.ACTION_SEND); * intent.setType("image/jpeg"); * intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(file)); * startActivityForResult(Intent.createChooser(intent, "Share via:"), 0); * </pre> * * <br> * The temp file will be deleted when AQUtility.cleanCacheAsync is invoked, or the file can be explicitly deleted after use. * * @param url The url of the desired cached content. * @param filename The desired file name, which might be used by other apps to describe the content, such as an email attachment. * @return temp file * */ public File makeSharedFile(String url, String filename) { File file = null; try { File cached = getCachedFile(url); if (cached != null) { File temp = AQUtility.getTempDir(); if (temp != null) { file = new File(temp, filename); file.createNewFile(); FileInputStream fis = new FileInputStream(cached); FileOutputStream fos = new FileOutputStream(file); FileChannel ic = fis.getChannel(); FileChannel oc = fos.getChannel(); try { ic.transferTo(0, ic.size(), oc); } finally { AQUtility.close(fis); AQUtility.close(fos); AQUtility.close(ic); AQUtility.close(oc); } } } } catch (Exception e) { AQUtility.debug(e); } return file; } /** * Starts an animation on the view. * * <br> * contributed by: marcosbeirigo * * @param animId Id of the desired animation. * @return self * */ public AQuery animate(int animId) { return animate(animId, null); } /** * Starts an animation on the view. * * <br> * contributed by: marcosbeirigo * * @param animId Id of the desired animation. * @param listener The listener to recieve notifications from the animation on its events. * @return self * * */ public AQuery animate(int animId, AnimationListener listener) { Animation anim = AnimationUtils.loadAnimation(getContext(), animId); anim.setAnimationListener(listener); return animate(anim); } /** * Starts an animation on the view. * * <br> * contributed by: marcosbeirigo * * @param anim The desired animation. * @return self * */ public AQuery animate(Animation anim) { if (view != null && anim != null) { view.startAnimation(anim); } return self(); } /** * Trigger click event * * <br> * contributed by: neocoin * * @return self * * @see View#performClick() */ public AQuery click() { if (view != null) { view.performClick(); } return self(); } /** * Trigger long click event * * <br> * contributed by: neocoin * * @return self * * @see View#performClick() */ public AQuery longClick() { if (view != null) { view.performLongClick(); } return self(); } //weak hash map that holds the dialogs so they will never memory leaked private static WeakHashMap<Dialog, Void> dialogs = new WeakHashMap<Dialog, Void>(); /** * Show a dialog. Method dismiss() or dismissAll() should be called later. * * @return self * */ public AQuery show(Dialog dialog) { try { if (dialog != null) { dialog.show(); dialogs.put(dialog, null); } } catch (Exception e) { } return self(); } /** * Dismiss a dialog previously shown with show(). * * @return self * */ public AQuery dismiss(Dialog dialog) { try { if (dialog != null) { dialogs.remove(dialog); dialog.dismiss(); } } catch (Exception e) { } return self(); } /** * Dismiss any AQuery dialogs. * * @return self * */ public AQuery dismiss() { Iterator<Dialog> keys = dialogs.keySet().iterator(); while (keys.hasNext()) { Dialog d = keys.next(); try { d.dismiss(); } catch (Exception e) { } keys.remove(); } return self(); } /** * Load the webview with an image with a url. * * Zoom is enabled without zoom control. Default background color is solid black (0xFF000000). * * @param url The image url * @return self * */ public AQuery webImage(String url) { return webImage(url, true, false, 0xFF000000); } /** * Load the webview with an image with a url. * * Zoom control can only be disabled for API level 14+. Lower level apis will always show zoom control if zoom is enabled. * * Note that color is AARRGGBB, where AA is the alpha value. Solid color (0xFF??????) should be used for performance reason. * Transparent background is not well supported by WebView in most devices. * * @param url The image url * @param zoom Image is zoomable * @param control Show zoom control (API level 14+) * @param color The background color * @return self * */ public AQuery webImage(String url, boolean zoom, boolean control, int color) { if (view instanceof WebView) { setLayerType11(AQuery.LAYER_TYPE_SOFTWARE, null); WebImage wi = new WebImage((WebView) view, url, progress, zoom, control, color); wi.load(); progress = null; } return self(); } /** * Inflate a view from xml layout. * * This method is similar to LayoutInflater.inflate() but with sanity checks against the * layout type of the convert view. * * If the convertView is null or the convertView type doesn't matches layoutId type, a new view * is inflated. Otherwise the convertView will be returned for reuse. * * @param convertView the view to be reused * @param layoutId the desired view type * @param root the view root for layout params, can be null * @return self * */ public View inflate(View convertView, int layoutId, ViewGroup root) { if (convertView != null) { Integer layout = (Integer) convertView.getTag(AQuery.TAG_LAYOUT); if (layout != null && layout.intValue() == layoutId) { return convertView; } } LayoutInflater inflater = null; if (act != null) { inflater = act.getLayoutInflater(); } else { inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); } View view = inflater.inflate(layoutId, root, false); view.setTag(AQuery.TAG_LAYOUT, layoutId); return view; } public AQuery expand(int position, boolean expand) { if (view instanceof ExpandableListView) { ExpandableListView elv = (ExpandableListView) view; if (expand) { elv.expandGroup(position); } else { elv.collapseGroup(position); } } return self(); } public AQuery expand(boolean expand) { if (view instanceof ExpandableListView) { ExpandableListView elv = (ExpandableListView) view; ExpandableListAdapter ela = elv.getExpandableListAdapter(); if (ela != null) { int count = ela.getGroupCount(); for (int i = 0; i < count; i++) { if (expand) { elv.expandGroup(i); } else { elv.collapseGroup(i); } } } } return self(); } /** * Download a file asynchronously. * * @param url url * @param target the file to be saved * @param cb callback to be called when done * @return self * */ public AQuery download(String url, File target, AjaxCallback<File> cb) { cb.url(url).type(File.class).targetFile(target); return ajax(cb); } /** * Download a file asynchronously. * * @param url url * @param target the file to be saved * @param handler the callback handler * @param callback the callback method * @return self * */ public AQuery download(String url, File target, Object handler, String callback) { AjaxCallback<File> cb = new AjaxCallback<File>(); cb.weakHandler(handler, callback); return download(url, target, cb); } private Object localTag; public void setLocalTag(Object obj) { localTag = obj; } public Object getLocalTag() { return localTag; } }