Documents some utilities

This commit is contained in:
Vavassor 2017-07-27 22:03:45 -04:00
parent bfdd0cb3a2
commit 368d8e5901
11 changed files with 83 additions and 11 deletions

View File

@ -15,6 +15,13 @@
package com.keylesspalace.tusky.util; package com.keylesspalace.tusky.util;
/**
* This is a synchronization primitive related to {@link java.util.concurrent.CountDownLatch}
* except that it starts at zero and can count upward.
* <p>
* The intended use case is for waiting for all tasks to be finished when the number of tasks isn't
* known ahead of time, or may change while waiting.
*/
public class CountUpDownLatch { public class CountUpDownLatch {
private int count; private int count;

View File

@ -20,8 +20,10 @@ import android.content.Context;
import com.keylesspalace.tusky.R; import com.keylesspalace.tusky.R;
public class DateUtils { public class DateUtils {
/* This is a rough duplicate of android.text.format.DateUtils.getRelativeTimeSpanString, /**
* but even with the FORMAT_ABBREV_RELATIVE flag it wasn't abbreviating enough. */ * This is a rough duplicate of {@link android.text.format.DateUtils#getRelativeTimeSpanString},
* but even with the FORMAT_ABBREV_RELATIVE flag it wasn't abbreviating enough.
*/
public static String getRelativeTimeSpanString(Context context, long then, long now) { public static String getRelativeTimeSpanString(Context context, long then, long now) {
final long MINUTE = 60; final long MINUTE = 60;
final long HOUR = 60 * MINUTE; final long HOUR = 60 * MINUTE;

View File

@ -32,6 +32,10 @@ import java.io.InputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
/**
* Reduces the file size of images to fit under a given limit by resizing them, maintaining both
* aspect ratio and orientation.
*/
public class DownsizeImageTask extends AsyncTask<Uri, Void, Boolean> { public class DownsizeImageTask extends AsyncTask<Uri, Void, Boolean> {
private static final String TAG = "DownsizeImageTask"; private static final String TAG = "DownsizeImageTask";
private int sizeLimit; private int sizeLimit;
@ -39,6 +43,11 @@ public class DownsizeImageTask extends AsyncTask<Uri, Void, Boolean> {
private Listener listener; private Listener listener;
private List<byte[]> resultList; private List<byte[]> resultList;
/**
* @param sizeLimit the maximum number of bytes each image can take
* @param contentResolver to resolve the specified images' URIs
* @param listener to whom the results are given
*/
public DownsizeImageTask(int sizeLimit, ContentResolver contentResolver, Listener listener) { public DownsizeImageTask(int sizeLimit, ContentResolver contentResolver, Listener listener) {
this.sizeLimit = sizeLimit; this.sizeLimit = sizeLimit;
this.contentResolver = contentResolver; this.contentResolver = contentResolver;
@ -223,6 +232,7 @@ public class DownsizeImageTask extends AsyncTask<Uri, Void, Boolean> {
super.onPostExecute(successful); super.onPostExecute(successful);
} }
/** Used to communicate the results of the task. */
public interface Listener { public interface Listener {
void onSuccess(List<byte[]> contentList); void onSuccess(List<byte[]> contentList);
void onFailure(); void onFailure();

View File

@ -15,6 +15,11 @@ import android.support.annotation.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
/**
* Represents one link and its parameters from the link header of an HTTP message.
*
* @see <a href="https://tools.ietf.org/html/rfc5988">RFC5988</a>
*/
public class HttpHeaderLink { public class HttpHeaderLink {
private static class Parameter { private static class Parameter {
public String name; public String name;
@ -114,6 +119,10 @@ public class HttpHeaderLink {
return -1; return -1;
} }
/**
* @param line the entire link header, not including the initial "Link:"
* @return all links found in the header
*/
public static List<HttpHeaderLink> parse(@Nullable String line) { public static List<HttpHeaderLink> parse(@Nullable String line) {
List<HttpHeaderLink> linkList = new ArrayList<>(); List<HttpHeaderLink> linkList = new ArrayList<>();
if (line != null) { if (line != null) {
@ -133,6 +142,11 @@ public class HttpHeaderLink {
return linkList; return linkList;
} }
/**
* @param links intended to be those returned by parse()
* @param relationType of the parameter "rel", commonly "next" or "prev"
* @return the link matching the given relation type
*/
@Nullable @Nullable
public static HttpHeaderLink findByRelationType(List<HttpHeaderLink> links, public static HttpHeaderLink findByRelationType(List<HttpHeaderLink> links,
String relationType) { String relationType) {

View File

@ -46,6 +46,16 @@ public class LinkHelper {
} }
} }
/**
* Finds links, mentions, and hashtags in a piece of text and makes them clickable, associating
* them with callbacks to notify when they're clicked.
*
* @param view the returned text will be put in
* @param content containing text with mentions, links, or hashtags
* @param mentions any '@' mentions which are known to be in the content
* @param useCustomTabs whether to use custom tabs when opening web links
* @param listener to notify about particular spans that are clicked
*/
public static void setClickableText(TextView view, Spanned content, public static void setClickableText(TextView view, Spanned content,
@Nullable Status.Mention[] mentions, boolean useCustomTabs, @Nullable Status.Mention[] mentions, boolean useCustomTabs,
final LinkListener listener) { final LinkListener listener) {

View File

@ -43,6 +43,10 @@ import java.io.InputStream;
public class MediaUtils { public class MediaUtils {
public static final int MEDIA_SIZE_UNKNOWN = -1; public static final int MEDIA_SIZE_UNKNOWN = -1;
/**
* Copies the entire contents of the given stream into a byte array and returns it. Beware of
* OutOfMemoryError for streams of unknown size.
*/
@Nullable @Nullable
public static byte[] inputStreamGetBytes(InputStream stream) { public static byte[] inputStreamGetBytes(InputStream stream) {
ByteArrayOutputStream buffer = new ByteArrayOutputStream(); ByteArrayOutputStream buffer = new ByteArrayOutputStream();
@ -59,6 +63,12 @@ public class MediaUtils {
return buffer.toByteArray(); return buffer.toByteArray();
} }
/**
* Fetches the size of the media represented by the given URI, assuming it is openable and
* the ContentResolver is able to resolve it.
*
* @return the size of the media or {@link MediaUtils#MEDIA_SIZE_UNKNOWN}
*/
public static long getMediaSize(ContentResolver contentResolver, Uri uri) { public static long getMediaSize(ContentResolver contentResolver, Uri uri) {
long mediaSize; long mediaSize;
Cursor cursor = contentResolver.query(uri, null, null, null, null); Cursor cursor = contentResolver.query(uri, null, null, null, null);
@ -73,7 +83,7 @@ public class MediaUtils {
return mediaSize; return mediaSize;
} }
// Download an image with picasso /** Download an image with picasso asynchronously and call the given listener when completed. */
public static Target picassoImageTarget(final Context context, final MediaListener mediaListener) { public static Target picassoImageTarget(final Context context, final MediaListener mediaListener) {
final String imageName = "temp"; final String imageName = "temp";
return new Target() { return new Target() {

View File

@ -42,9 +42,16 @@ import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
public class NotificationMaker { public class NotificationMaker {
public static final String TAG = "NotificationMaker"; public static final String TAG = "NotificationMaker";
/**
* Takes a given Mastodon notification and either creates a new Android notification or updates
* the state of the existing notification to reflect the new interaction.
*
* @param context to access application preferences and services
* @param notifyId an arbitrary number to reference this notification for any future action
* @param body a new Mastodon notification
*/
public static void make(final Context context, final int notifyId, Notification body) { public static void make(final Context context, final int notifyId, Notification body) {
final SharedPreferences preferences = final SharedPreferences preferences =
PreferenceManager.getDefaultSharedPreferences(context); PreferenceManager.getDefaultSharedPreferences(context);

View File

@ -46,18 +46,18 @@ import okhttp3.Request;
import okhttp3.Response; import okhttp3.Response;
public class OkHttpUtils { public class OkHttpUtils {
static final String TAG = "OkHttpUtils"; // logging tag private static final String TAG = "OkHttpUtils"; // logging tag
/** /**
* Makes a Builder with the maximum range of TLS versions and cipher suites enabled. * Makes a Builder with the maximum range of TLS versions and cipher suites enabled.
* * <p>
* It first tries the "approved" list of cipher suites given in OkHttp (the default in * It first tries the "approved" list of cipher suites given in OkHttp (the default in
* ConnectionSpec.MODERN_TLS) and if that doesn't work falls back to the set of ALL enabled, * ConnectionSpec.MODERN_TLS) and if that doesn't work falls back to the set of ALL enabled,
* then falls back to plain http. * then falls back to plain http.
* * <p>
* API level 24 has a regression in elliptic curves where it only supports secp256r1, so this * API level 24 has a regression in elliptic curves where it only supports secp256r1, so this
* first tries a fallback without elliptic curves at all, and then tries them after. * first tries a fallback without elliptic curves at all, and then tries them after.
* * <p>
* TLS 1.1 and 1.2 have to be manually enabled on API levels 16-20. * TLS 1.1 and 1.2 have to be manually enabled on API levels 16-20.
*/ */
@NonNull @NonNull
@ -104,7 +104,6 @@ public class OkHttpUtils {
}; };
} }
/** /**
* Android version Nougat has a regression where elliptic curve cipher suites are supported, but * Android version Nougat has a regression where elliptic curve cipher suites are supported, but
* only the curve secp256r1 is allowed. So, first it's best to just disable all elliptic * only the curve secp256r1 is allowed. So, first it's best to just disable all elliptic

View File

@ -19,7 +19,7 @@ import java.util.List;
import static com.keylesspalace.tusky.util.StringUtils.QUOTE; import static com.keylesspalace.tusky.util.StringUtils.QUOTE;
/** /**
* Inspect and Get the information from an URL * Inspect and get the information from a URL.
*/ */
public class ParserUtils { public class ParserUtils {
private static final String TAG = "ParserUtils"; private static final String TAG = "ParserUtils";
@ -56,7 +56,7 @@ public class ParserUtils {
clipboard.setPrimaryClip(clip); clipboard.setPrimaryClip(clip);
} }
// parse the HTML page /** parse the HTML page */
private HeaderInfo parsePageHeaderInfo(String urlStr) throws Exception { private HeaderInfo parsePageHeaderInfo(String urlStr) throws Exception {
Connection con = Jsoup.connect(urlStr); Connection con = Jsoup.connect(urlStr);
HeaderInfo headerInfo = new HeaderInfo(); HeaderInfo headerInfo = new HeaderInfo();

View File

@ -23,8 +23,16 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
public class SpanUtils { public class SpanUtils {
/**
* @see <a href="https://github.com/tootsuite/mastodon/blob/master/app/models/tag.rb">
* Tag#HASHTAG_RE</a>.
*/
private static final String TAG_REGEX = "(?:^|[^/)\\w])#([\\w_]*[\\p{Alpha}_][\\w_]*)"; private static final String TAG_REGEX = "(?:^|[^/)\\w])#([\\w_]*[\\p{Alpha}_][\\w_]*)";
private static Pattern TAG_PATTERN = Pattern.compile(TAG_REGEX, Pattern.CASE_INSENSITIVE); private static Pattern TAG_PATTERN = Pattern.compile(TAG_REGEX, Pattern.CASE_INSENSITIVE);
/**
* @see <a href="https://github.com/tootsuite/mastodon/blob/master/app/models/account.rb">
* Account#MENTION_RE</a>
*/
private static final String MENTION_REGEX = private static final String MENTION_REGEX =
"(?:^|[^/[:word:]])@([a-z0-9_]+(?:@[a-z0-9\\.\\-]+[a-z0-9]+)?)"; "(?:^|[^/[:word:]])@([a-z0-9_]+(?:@[a-z0-9\\.\\-]+[a-z0-9]+)?)";
private static Pattern MENTION_PATTERN = private static Pattern MENTION_PATTERN =
@ -98,6 +106,7 @@ public class SpanUtils {
} }
} }
/** Takes text containing mentions and hashtags and makes them the given colour. */
public static void highlightSpans(Spannable text, int colour) { public static void highlightSpans(Spannable text, int colour) {
// Strip all existing colour spans. // Strip all existing colour spans.
int n = text.length(); int n = text.length();

View File

@ -26,6 +26,10 @@ import android.support.v4.content.ContextCompat;
import android.util.TypedValue; import android.util.TypedValue;
import android.widget.ImageView; import android.widget.ImageView;
/**
* Provides runtime compatibility to obtain theme information and re-theme views, especially where
* the ability to do so is not supported in resource files.
*/
public class ThemeUtils { public class ThemeUtils {
public static Drawable getDrawable(Context context, @AttrRes int attribute, public static Drawable getDrawable(Context context, @AttrRes int attribute,
@DrawableRes int fallbackDrawable) { @DrawableRes int fallbackDrawable) {