/* * 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: &amp;) */ 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; } } } } } }