/*
* Copyright 2014 Gleb Godonoga.
*
* 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.andrada.sitracker.util;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.os.Build;
import android.text.Editable;
import android.text.Html;
import android.text.TextUtils;
import android.widget.TextView;
import com.andrada.sitracker.R;
import org.jetbrains.annotations.NotNull;
import org.xml.sax.XMLReader;
import java.util.regex.Pattern;
import static com.andrada.sitracker.util.LogUtils.LOGE;
import static com.andrada.sitracker.util.LogUtils.makeLogTag;
public class UIUtils {
public static final String TARGET_FORM_FACTOR_ACTIVITY_METADATA =
"com.andrada.sitracker.meta.TARGET_FORM_FACTOR";
public static final String TARGET_FORM_FACTOR_HANDSET = "handset";
public static final String TARGET_FORM_FACTOR_TABLET = "tablet";
public static final int ANIMATION_FADE_IN_TIME = 250;
private static final String TAG = makeLogTag(UIUtils.class);
/**
* Regex to search for HTML escape sequences.
* <p/>
* <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;.*");
private static final int[] RES_IDS_ACTION_BAR_SIZE = {R.attr.actionBarSize};
/**
* 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(@NotNull TextView view, @NotNull String text) {
if (TextUtils.isEmpty(text)) {
view.setText("");
return;
}
if ((text.contains("<") && text.contains(">")) || REGEX_HTML_ESCAPE.matcher(text).find()) {
//Sanitize urls in hrefs:
text = text.replace("<a href=\" ", "<a href=\"");
text = text.replace("<a href=' ", "<a href='");
view.setText(Html.fromHtml(text, null, new ListTagHandler()));
//Commented movement method to make the textview focusable.
//view.setMovementMethod(LinkMovementMethod.getInstance());
} else {
view.setText(text);
}
}
public static boolean hasJellyBean() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
}
public static boolean hasLollipop() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
}
public static boolean isTablet(@NotNull Context context) {
return (context.getResources().getConfiguration().screenLayout
& Configuration.SCREENLAYOUT_SIZE_MASK)
>= Configuration.SCREENLAYOUT_SIZE_LARGE;
}
/**
* 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
* @see #isTablet(android.content.Context)
*/
public static void enableDisableActivitiesByFormFactor(@NotNull 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;
if (className.contains("andrada")) {
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);
}
}
@NotNull
private static String bytesToHexString(@NotNull byte[] bytes) {
// http://stackoverflow.com/questions/332079
StringBuilder sb = new StringBuilder();
for (byte aByte : bytes) {
String hex = Integer.toHexString(0xFF & aByte);
if (hex.length() == 1) {
sb.append('0');
}
sb.append(hex);
}
return sb.toString();
}
/**
* 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 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);
}
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 boolean isLandscape(Context context) {
return context != null &&
context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
}
public static class ListTagHandler implements Html.TagHandler {
boolean first = true;
String parent = null;
int index = 1;
@Override
public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader) {
if (tag.equals("ul")) parent = "ul";
else if (tag.equals("ol")) parent = "ol";
if (tag.equals("li")) {
if (parent.equals("ul")) {
if (first) {
output.append("\n\t•");
first = false;
} else {
first = true;
}
} else {
if (first) {
output.append("\n\t").append(String.valueOf(index)).append(". ");
first = false;
index++;
} else {
first = true;
}
}
}
}
}
}