/* * Copyright 2009 Andrew Shu * * This file is part of "reddit is fun". * * "reddit is fun" is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * "reddit is fun" 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with "reddit is fun". If not, see <http://www.gnu.org/licenses/>. */ package com.andrewshu.android.reddit.common.util; import java.lang.reflect.Method; import java.util.ArrayList; import org.apache.http.HttpException; import org.apache.http.HttpResponse; import android.app.Activity; import android.net.Uri; import android.text.style.URLSpan; import android.util.Log; import com.andrewshu.android.reddit.R; import com.andrewshu.android.reddit.common.Common; import com.andrewshu.android.reddit.common.Constants; import com.andrewshu.android.reddit.things.ThingInfo; public class Util { private static final String TAG = "Util"; public static ArrayList<String> extractUris(URLSpan[] spans) { int size = spans.length; ArrayList<String> accumulator = new ArrayList<String>(); for (int i = 0; i < size; i++) { accumulator.add(spans[i].getURL()); } return accumulator; } /** * Convert HTML tags so they will be properly recognized by * android.text.Html.fromHtml() * @param html unescaped HTML * @return converted HTML */ public static String convertHtmlTags(String html) { // Handle <code> html = html.replaceAll("<code>", "<tt>").replaceAll("</code>", "</tt>"); // Handle <pre> int preIndex = html.indexOf("<pre>"); int preEndIndex = -6; // -"</pre>".length() StringBuilder bodyConverted = new StringBuilder(); while (preIndex != -1) { // get the text between previous </pre> and next <pre>. bodyConverted = bodyConverted.append(html.substring(preEndIndex + 6, preIndex)); preEndIndex = html.indexOf("</pre>", preIndex); // Replace newlines with <br> inside the <pre></pre> // Retain <pre> tags since android.text.Html.fromHtml() will ignore them anyway. bodyConverted = bodyConverted.append(html.substring(preIndex, preEndIndex).replaceAll("\n", "<br>")) .append("</pre>"); preIndex = html.indexOf("<pre>", preEndIndex); } html = bodyConverted.append(html.substring(preEndIndex + 6)).toString(); // Handle <li> html = html.replaceAll("<li>(<p>)?", "• ") .replaceAll("(</p>)?</li>", "<br>"); // Handle <strong> and <em>, which are normally <b> and <i> respectively, but reversed in Android. // ANDROID BUG: http://code.google.com/p/android/issues/detail?id=3473 html = html.replaceAll("<strong>", "<b>").replaceAll("</strong>", "</b>") .replaceAll("<em>", "<i>").replaceAll("</em>", "</i>"); return html; } /** * To the second, not millisecond like reddit * @param timeSeconds * @return */ public static String getTimeAgo(long utcTimeSeconds) { long systime = System.currentTimeMillis() / 1000; long diff = systime - utcTimeSeconds; if (diff <= 0) return "very recently"; else if (diff < 60) { if (diff == 1) return "1 second ago"; else return diff + " seconds ago"; } else if (diff < 3600) { if ((diff / 60) == 1) return "1 minute ago"; else return (diff / 60) + " minutes ago"; } else if (diff < 86400) { // 86400 seconds in a day if ((diff / 3600) == 1) return "1 hour ago"; else return (diff / 3600) + " hours ago"; } else if (diff < 604800) { // 86400 * 7 if ((diff / 86400) == 1) return "1 day ago"; else return (diff / 86400) + " days ago"; } else if (diff < 2592000) { // 86400 * 30 if ((diff / 604800) == 1) return "1 week ago"; else return (diff / 604800) + " weeks ago"; } else if (diff < 31536000) { // 86400 * 365 if ((diff / 2592000) == 1) return "1 month ago"; else return (diff / 2592000) + " months ago"; } else { if ((diff / 31536000) == 1) return "1 year ago"; else return (diff / 31536000) + " years ago"; } } public static String getTimeAgo(double utcTimeSeconds) { return getTimeAgo((long)utcTimeSeconds); } public static String showNumComments(int comments) { if (comments == 1) { return "1 comment"; } else { return comments + " comments"; } } public static String showNumPoints(int score) { if (score == 1) { return "1 point"; } else { return score + " points"; } } public static String absolutePathToURL(String path) { if (path.startsWith("/")) return Constants.REDDIT_BASE_URL + path; return path; } public static String nameToId(String name) { // indexOf('_') == -1 if not found; -1 + 1 == 0 return name.substring(name.indexOf('_') + 1); } public static boolean isHttpStatusOK(HttpResponse response) { if (response == null || response.getStatusLine() == null) { return false; } return response.getStatusLine().getStatusCode() == 200; } public static String getResponseErrorMessage(String line) throws Exception{ String error = null; if (StringUtils.isEmpty(line)) { error = "Connection error when subscribing. Try again."; throw new HttpException("No content returned from subscribe POST"); } if (line.contains("WRONG_PASSWORD")) { error = "Wrong password."; throw new Exception("Wrong password."); } if (line.contains("USER_REQUIRED")) { // The modhash probably expired throw new Exception("User required. Huh?"); } Common.logDLong(TAG, line); return error; } // =============== // Theme // =============== public static boolean isLightTheme(int theme) { return theme == R.style.Reddit_Light_Medium || theme == R.style.Reddit_Light_Large || theme == R.style.Reddit_Light_Larger || theme == R.style.Reddit_Light_Huge; } public static boolean isDarkTheme(int theme) { return theme == R.style.Reddit_Dark_Medium || theme == R.style.Reddit_Dark_Large || theme == R.style.Reddit_Dark_Larger || theme == R.style.Reddit_Dark_Huge; } public static int getInvertedTheme(int theme) { switch (theme) { case R.style.Reddit_Light_Medium: return R.style.Reddit_Dark_Medium; case R.style.Reddit_Light_Large: return R.style.Reddit_Dark_Large; case R.style.Reddit_Light_Larger: return R.style.Reddit_Dark_Larger; case R.style.Reddit_Light_Huge: return R.style.Reddit_Dark_Huge; case R.style.Reddit_Dark_Medium: return R.style.Reddit_Light_Medium; case R.style.Reddit_Dark_Large: return R.style.Reddit_Light_Large; case R.style.Reddit_Dark_Larger: return R.style.Reddit_Light_Larger; case R.style.Reddit_Dark_Huge: return R.style.Reddit_Light_Huge; default: return R.style.Reddit_Light_Medium; } } public static int getThemeResourceFromPrefs(String themePref, String textSizePref) { if (Constants.PREF_THEME_LIGHT.equals(themePref)) { if (Constants.PREF_TEXT_SIZE_MEDIUM.equals(textSizePref)) return R.style.Reddit_Light_Medium; else if (Constants.PREF_TEXT_SIZE_LARGE.equals(textSizePref)) return R.style.Reddit_Light_Large; else if (Constants.PREF_TEXT_SIZE_LARGER.equals(textSizePref)) return R.style.Reddit_Light_Larger; else if (Constants.PREF_TEXT_SIZE_HUGE.equals(textSizePref)) return R.style.Reddit_Light_Huge; } else /* if (Constants.PREF_THEME_DARK.equals(themePref)) */ { if (Constants.PREF_TEXT_SIZE_MEDIUM.equals(textSizePref)) return R.style.Reddit_Dark_Medium; else if (Constants.PREF_TEXT_SIZE_LARGE.equals(textSizePref)) return R.style.Reddit_Dark_Large; else if (Constants.PREF_TEXT_SIZE_LARGER.equals(textSizePref)) return R.style.Reddit_Dark_Larger; else if (Constants.PREF_TEXT_SIZE_HUGE.equals(textSizePref)) return R.style.Reddit_Dark_Huge; } return R.style.Reddit_Light_Medium; } /** * Return the theme and textSize String prefs */ public static String[] getPrefsFromThemeResource(int theme) { switch (theme) { case R.style.Reddit_Light_Medium: return new String[] { Constants.PREF_THEME_LIGHT, Constants.PREF_TEXT_SIZE_MEDIUM }; case R.style.Reddit_Light_Large: return new String[] { Constants.PREF_THEME_LIGHT, Constants.PREF_TEXT_SIZE_LARGE }; case R.style.Reddit_Light_Larger: return new String[] { Constants.PREF_THEME_LIGHT, Constants.PREF_TEXT_SIZE_LARGER }; case R.style.Reddit_Light_Huge: return new String[] { Constants.PREF_THEME_LIGHT, Constants.PREF_TEXT_SIZE_HUGE }; case R.style.Reddit_Dark_Medium: return new String[] { Constants.PREF_THEME_DARK, Constants.PREF_TEXT_SIZE_MEDIUM }; case R.style.Reddit_Dark_Large: return new String[] { Constants.PREF_THEME_DARK, Constants.PREF_TEXT_SIZE_LARGE }; case R.style.Reddit_Dark_Larger: return new String[] { Constants.PREF_THEME_DARK, Constants.PREF_TEXT_SIZE_LARGER }; case R.style.Reddit_Dark_Huge: return new String[] { Constants.PREF_THEME_DARK, Constants.PREF_TEXT_SIZE_HUGE }; default: return new String[] { Constants.PREF_THEME_LIGHT, Constants.PREF_TEXT_SIZE_MEDIUM }; } } public static int getTextAppearanceResource(int themeResource, int androidTextAppearanceStyle) { switch (themeResource) { case R.style.Reddit_Light_Medium: case R.style.Reddit_Dark_Medium: switch (androidTextAppearanceStyle) { case android.R.style.TextAppearance_Small: return R.style.TextAppearance_Medium_Small; case android.R.style.TextAppearance_Medium: return R.style.TextAppearance_Medium_Medium; case android.R.style.TextAppearance_Large: return R.style.TextAppearance_Medium_Large; default: return R.style.TextAppearance_Medium_Medium; } case R.style.Reddit_Light_Large: case R.style.Reddit_Dark_Large: switch (androidTextAppearanceStyle) { case android.R.style.TextAppearance_Small: return R.style.TextAppearance_Large_Small; case android.R.style.TextAppearance_Medium: return R.style.TextAppearance_Large_Medium; case android.R.style.TextAppearance_Large: return R.style.TextAppearance_Large_Large; default: return R.style.TextAppearance_Large_Medium; } case R.style.Reddit_Light_Larger: case R.style.Reddit_Dark_Larger: switch (androidTextAppearanceStyle) { case android.R.style.TextAppearance_Small: return R.style.TextAppearance_Larger_Small; case android.R.style.TextAppearance_Medium: return R.style.TextAppearance_Larger_Medium; case android.R.style.TextAppearance_Large: return R.style.TextAppearance_Larger_Large; default: return R.style.TextAppearance_Larger_Medium; } case R.style.Reddit_Light_Huge: case R.style.Reddit_Dark_Huge: switch (androidTextAppearanceStyle) { case android.R.style.TextAppearance_Small: return R.style.TextAppearance_Huge_Small; case android.R.style.TextAppearance_Medium: return R.style.TextAppearance_Huge_Medium; case android.R.style.TextAppearance_Large: return R.style.TextAppearance_Huge_Large; default: return R.style.TextAppearance_Huge_Medium; } default: return R.style.TextAppearance_Medium_Medium; } } // ======================= // Mail Notification // ======================= public static long getMillisFromMailNotificationPref(String pref) { if (Constants.PREF_MAIL_NOTIFICATION_SERVICE_OFF.equals(pref)) { return 0; } else if (Constants.PREF_MAIL_NOTIFICATION_SERVICE_5MIN.equals(pref)) { return 5 * 60 * 1000; } else if (Constants.PREF_MAIL_NOTIFICATION_SERVICE_30MIN.equals(pref)) { return 30 * 60 * 1000; } else if (Constants.PREF_MAIL_NOTIFICATION_SERVICE_1HOUR.equals(pref)) { return 1 * 3600 * 1000; } else if (Constants.PREF_MAIL_NOTIFICATION_SERVICE_6HOURS.equals(pref)) { return 6 * 3600 * 1000; } else /* if (Constants.PREF_MAIL_NOTIFICATION_SERVICE_1DAY.equals(pref)) */ { return 24 * 3600 * 1000; } } // =============== // Transitions // =============== public static void overridePendingTransition(Method activity_overridePendingTransition, Activity act, int enterAnim, int exitAnim) { // only available in Android 2.0 (SDK Level 5) and later if (activity_overridePendingTransition != null) { try { activity_overridePendingTransition.invoke(act, enterAnim, exitAnim); } catch (Exception ex) { if (Constants.LOGGING) Log.e(TAG, "overridePendingTransition", ex); } } } // =============== // Uri // =============== static Uri createCommentUri(String linkId, String commentId, int commentContext) { return Uri.parse(new StringBuilder(Constants.REDDIT_BASE_URL + "/comments/") .append(linkId) .append("/z/") .append(commentId) .append("?context=") .append(commentContext) .toString()); } public static Uri createCommentUri(ThingInfo commentThingInfo, int commentContext) { if (commentThingInfo.getContext() != null) return Uri.parse(absolutePathToURL(commentThingInfo.getContext())); if (commentThingInfo.getLink_id() != null) return createCommentUri(nameToId(commentThingInfo.getLink_id()), commentThingInfo.getId(), commentContext); return null; } public static Uri createProfileUri(String username) { return Uri.parse(new StringBuilder(Constants.REDDIT_BASE_URL + "/user/") .append(username) .toString()); } public static Uri createSubmitUri(String subreddit) { if (Constants.FRONTPAGE_STRING.equals(subreddit)) return Uri.parse(Constants.REDDIT_BASE_URL + "/submit"); return Uri.parse(new StringBuilder(Constants.REDDIT_BASE_URL + "/r/") .append(subreddit) .append("/submit") .toString()); } static Uri createSubmitUri(ThingInfo thingInfo) { return createSubmitUri(thingInfo.getSubreddit()); } public static Uri createSubredditUri(String subreddit) { if (Constants.FRONTPAGE_STRING.equals(subreddit)) return Uri.parse(Constants.REDDIT_BASE_URL + "/"); return Uri.parse(new StringBuilder(Constants.REDDIT_BASE_URL + "/r/") .append(subreddit) .toString()); } static Uri createSubredditUri(ThingInfo thingInfo) { return createSubredditUri(thingInfo.getSubreddit()); } static Uri createThreadUri(String subreddit, String threadId) { return Uri.parse(new StringBuilder(Constants.REDDIT_BASE_URL + "/r/") .append(subreddit) .append("/comments/") .append(threadId) .toString()); } public static Uri createThreadUri(ThingInfo threadThingInfo) { return createThreadUri(threadThingInfo.getSubreddit(), threadThingInfo.getId()); } public static boolean isRedditUri(Uri uri) { if (uri == null) return false; String host = uri.getHost(); return host != null && (host.equals("reddit.com") || host.endsWith(".reddit.com")); } public static boolean isRedditShortenedUri(Uri uri) { if (uri == null) return false; String host = uri.getHost(); return host != null && host.equals("redd.it"); } /** * Creates mobile version of <code>uri</code> if applicable. * * @return original uri if no mobile version of uri is known */ public static Uri optimizeMobileUri(Uri uri) { if (isNonMobileWikipediaUri(uri)) { uri = createMobileWikpediaUri(uri); } return uri; } /** * @return if uri points to a non-mobile wikpedia uri. */ static boolean isNonMobileWikipediaUri(Uri uri) { if (uri == null) return false; String host = uri.getHost(); return host != null && host.endsWith(".wikipedia.org") && !host.contains(".m.wikipedia.org"); } /** * @return mobile version of a wikipedia uri */ static Uri createMobileWikpediaUri(Uri uri) { String uriString = uri.toString(); return Uri.parse(uriString.replace(".wikipedia.org/", ".m.wikipedia.org/")); } public static boolean isYoutubeUri(Uri uri) { if (uri == null) return false; String host = uri.getHost(); return host != null && (host.endsWith(".youtube.com") || host.equals("youtu.be")); } public static boolean isAndroidMarketUri(Uri uri) { if (uri == null) return false; String host = uri.getHost(); return host != null && host.equals("market.android.com"); } }