/*
* Copyright 2014 Google Inc. All rights reserved.
*
* 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.sonaive.v2ex.util;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.Typeface;
import android.os.Build;
import android.text.Html;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.text.method.LinkMovementMethod;
import android.text.style.StyleSpan;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.sonaive.v2ex.BuildConfig;
import com.sonaive.v2ex.R;
import com.sonaive.v2ex.widget.LoadingStatus;
import java.util.regex.Pattern;
import static com.sonaive.v2ex.util.LogUtils.LOGE;
import static com.sonaive.v2ex.util.LogUtils.makeLogTag;
/**
* An assortment of UI helpers.
*/
public class UIUtils {
private static final String TAG = makeLogTag(UIUtils.class);
public static final String TARGET_FORM_FACTOR_ACTIVITY_METADATA =
"com.sonavie.v2ex.meta.TARGET_FORM_FACTOR";
public static final String TARGET_FORM_FACTOR_HANDSET = "handset";
public static final String TARGET_FORM_FACTOR_TABLET = "tablet";
/**
* Flags used with {@link android.text.format.DateUtils#formatDateRange}.
*/
private static final int TIME_FLAGS = DateUtils.FORMAT_SHOW_TIME
| DateUtils.FORMAT_SHOW_WEEKDAY | DateUtils.FORMAT_ABBREV_WEEKDAY;
/**
* Regex to search for HTML escape sequences.
*
* <p></p>Searches for any continuous string of characters starting with an ampersand and ending with a
* semicolon. (Example: &)
*/
private static final Pattern REGEX_HTML_ESCAPE = Pattern.compile(".*&\\S;.*");
/**
* Populate the given {@link android.widget.TextView} with the requested text, formatting
* through {@link android.text.Html#fromHtml(String)} when applicable. Also sets
* {@link android.widget.TextView#setMovementMethod} so inline links are handled.
*/
public static void setTextMaybeHtml(TextView view, String text) {
if (TextUtils.isEmpty(text)) {
view.setText("");
return;
}
if ((text.contains("<") && text.contains(">")) || REGEX_HTML_ESCAPE.matcher(text).find()) {
view.setText(Html.fromHtml(text));
view.setMovementMethod(LinkMovementMethod.getInstance());
} else {
view.setText(text);
}
}
/**
* Given a snippet string with matching segments surrounded by curly
* braces, turn those areas into bold spans, removing the curly braces.
*/
public static Spannable buildStyledSnippet(String snippet) {
final SpannableStringBuilder builder = new SpannableStringBuilder(snippet);
// Walk through string, inserting bold snippet spans
int startIndex, endIndex = -1, delta = 0;
while ((startIndex = snippet.indexOf('{', endIndex)) != -1) {
endIndex = snippet.indexOf('}', startIndex);
// Remove braces from both sides
builder.delete(startIndex - delta, startIndex - delta + 1);
builder.delete(endIndex - delta - 1, endIndex - delta);
// Insert bold style
builder.setSpan(new StyleSpan(Typeface.BOLD),
startIndex - delta, endIndex - delta - 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
//builder.setSpan(new ForegroundColorSpan(0xff111111),
// startIndex - delta, endIndex - delta - 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
delta += 2;
}
return builder;
}
public static void preferPackageForIntent(Context context, Intent intent, String packageName) {
PackageManager pm = context.getPackageManager();
for (ResolveInfo resolveInfo : pm.queryIntentActivities(intent, 0)) {
if (resolveInfo.activityInfo.packageName.equals(packageName)) {
intent.setPackage(packageName);
break;
}
}
}
private static final int BRIGHTNESS_THRESHOLD = 130;
/**
* Calculate whether a color is light or dark, based on a commonly known
* brightness formula.
*
* @see {@literal http://en.wikipedia.org/wiki/HSV_color_space%23Lightness}
*/
public static boolean isColorDark(int color) {
return ((30 * Color.red(color) +
59 * Color.green(color) +
11 * Color.blue(color)) / 100) <= BRIGHTNESS_THRESHOLD;
}
public static boolean isTablet(Context context) {
return context.getResources().getConfiguration().smallestScreenWidthDp >= 600;
}
private static final long sAppLoadTime = System.currentTimeMillis();
public static long getCurrentTime(final Context context) {
if (BuildConfig.DEBUG) {
return context.getSharedPreferences("mock_data", Context.MODE_PRIVATE)
.getLong("mock_current_time", System.currentTimeMillis())
+ System.currentTimeMillis() - sAppLoadTime;
// return ParserUtils.parseTime("2012-06-27T09:44:45.000-07:00")
// + System.currentTimeMillis() - sAppLoadTime;
} else {
return System.currentTimeMillis();
}
}
/**
* Enables and disables {@linkplain android.app.Activity activities} based on their
* {@link #TARGET_FORM_FACTOR_ACTIVITY_METADATA}" meta-data and the current device.
* Values should be either "handset", "tablet", or not present (meaning universal).
* <p>
* <a href="http://stackoverflow.com/questions/13202805">Original code</a> by Dandre Allison.
* @param context the current context of the device
*/
public static void enableDisableActivitiesByFormFactor(Context context) {
final PackageManager pm = context.getPackageManager();
boolean isTablet = isTablet(context);
try {
PackageInfo pi = pm.getPackageInfo(context.getPackageName(),
PackageManager.GET_ACTIVITIES | PackageManager.GET_META_DATA);
if (pi == null) {
LOGE(TAG, "No package info found for our own package.");
return;
}
final ActivityInfo[] activityInfos = pi.activities;
for (ActivityInfo info : activityInfos) {
String targetDevice = null;
if (info.metaData != null) {
targetDevice = info.metaData.getString(TARGET_FORM_FACTOR_ACTIVITY_METADATA);
}
boolean tabletActivity = TARGET_FORM_FACTOR_TABLET.equals(targetDevice);
boolean handsetActivity = TARGET_FORM_FACTOR_HANDSET.equals(targetDevice);
boolean enable = !(handsetActivity && isTablet)
&& !(tabletActivity && !isTablet);
String className = info.name;
pm.setComponentEnabledSetting(
new ComponentName(context, Class.forName(className)),
enable
? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
: PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
}
} catch (PackageManager.NameNotFoundException e) {
LOGE(TAG, "No package info found for our own package.", e);
} catch (ClassNotFoundException e) {
LOGE(TAG, "Activity not found within package.", e);
}
}
/**
* If an activity's intent is for a Google I/O web URL that the app can handle
* natively, this method translates the intent to the equivalent native intent.
*/
public static void tryTranslateHttpIntent(Activity activity) {
// Intent intent = activity.getIntent();
// if (intent == null) {
// return;
// }
//
// Uri uri = intent.getData();
// if (uri == null || TextUtils.isEmpty(uri.getPath())) {
// return;
// }
//
// String prefixPath = Config.SESSION_DETAIL_WEB_URL_PREFIX.getPath();
// String path = uri.getPath();
//
// if (Config.SESSION_DETAIL_WEB_URL_PREFIX.getScheme().equals(uri.getScheme()) &&
// Config.SESSION_DETAIL_WEB_URL_PREFIX.getHost().equals(uri.getHost()) &&
// path.startsWith(prefixPath)) {
// String sessionId = path.substring(prefixPath.length());
// activity.setIntent(new Intent(
// Intent.ACTION_VIEW,
// ScheduleContract.Sessions.buildSessionUri(sessionId)));
// }
}
private static final int[] RES_IDS_ACTION_BAR_SIZE = { R.attr.actionBarSize };
/** Calculates the Action Bar height in pixels. */
public static int calculateActionBarSize(Context context) {
if (context == null) {
return 0;
}
Resources.Theme curTheme = context.getTheme();
if (curTheme == null) {
return 0;
}
TypedArray att = curTheme.obtainStyledAttributes(RES_IDS_ACTION_BAR_SIZE);
if (att == null) {
return 0;
}
float size = att.getDimension(0, 0);
att.recycle();
return (int) size;
}
public static int setColorAlpha(int color, float alpha) {
int alpha_int = Math.min(Math.max((int)(alpha * 255.0f), 0), 255);
return Color.argb(alpha_int, Color.red(color), Color.green(color), Color.blue(color));
}
public static int scaleColor(int color, float factor, boolean scaleAlpha) {
return Color.argb(scaleAlpha ? (Math.round(Color.alpha(color) * factor)) : Color.alpha(color),
Math.round(Color.red(color) * factor), Math.round(Color.green(color) * factor),
Math.round(Color.blue(color) * factor));
}
public static void setStartPadding(final Context context, View view, int padding) {
if (isRtl(context)) {
view.setPadding(view.getPaddingLeft(), view.getPaddingTop(), padding, view.getPaddingBottom());
} else {
view.setPadding(padding, view.getPaddingTop(), view.getPaddingRight(), view.getPaddingBottom());
}
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
public static boolean isRtl(final Context context) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
return false;
} else {
return context.getResources().getConfiguration().getLayoutDirection()
== View.LAYOUT_DIRECTION_RTL;
}
}
public static void setAccessibilityIgnore(View view) {
view.setClickable(false);
view.setFocusable(false);
view.setContentDescription("");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
}
}
public static void setUpButterBar(View butterBar, String messageText, String actionText,
View.OnClickListener listener) {
if (butterBar == null) {
LOGE(TAG, "Failed to set up butter bar: it's null.");
return;
}
TextView textView = (TextView) butterBar.findViewById(R.id.butter_bar_text);
if (textView != null) {
textView.setText(messageText);
}
Button button = (Button) butterBar.findViewById(R.id.butter_bar_button);
if (button != null) {
button.setText(actionText == null ? "" : actionText);
button.setVisibility(!TextUtils.isEmpty(actionText) ? View.VISIBLE : View.GONE);
}
button.setOnClickListener(listener);
butterBar.setVisibility(View.VISIBLE);
}
public static void invalidateFooterState(Context context, View footer, LoadingStatus loadingState) {
TextView emptyTextView = (TextView) footer.findViewById(android.R.id.empty);
View progressBar = footer.findViewById(R.id.progress_bar);
if (loadingState == LoadingStatus.LOADING) {
emptyTextView.setVisibility(View.GONE);
progressBar.setVisibility(View.VISIBLE);
} else if (loadingState == LoadingStatus.FINISH) {
emptyTextView.setVisibility(View.GONE);
progressBar.setVisibility(View.GONE);
} else if (loadingState == LoadingStatus.NO_MORE_DATA) {
emptyTextView.setVisibility(View.VISIBLE);
progressBar.setVisibility(View.GONE);
emptyTextView.setText(context.getString(R.string.no_more_data));
} else {
// TODO
}
}
public static float getProgress(int value, int min, int max) {
if (min == max) {
throw new IllegalArgumentException("Max (" + max + ") cannot equal min (" + min + ")");
}
return (value - min) / (float) (max - min);
}
}