/* * Copyright (C) 2015-2017 Emanuel Moecklin * * 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.onegravity.rteditor.utils; import android.content.Context; import android.content.res.Configuration; import android.net.Uri; import android.util.DisplayMetrics; import android.view.Display; import android.view.WindowManager; import com.onegravity.rteditor.api.RTApi; import com.onegravity.rteditor.utils.io.IOUtils; import java.io.Closeable; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URISyntaxException; import java.net.URLDecoder; import java.net.URLEncoder; import java.text.Bidi; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; /** * Miscellaneous helper methods */ public abstract class Helper { private static float sDensity = Float.MAX_VALUE; private static float sDensity4Fonts = Float.MAX_VALUE; private static final int LEADING_MARGIN = 28; private static int sLeadingMarging = -1; public static void closeQuietly(Closeable closeable) { IOUtils.closeQuietly(closeable); } public static float getDisplayDensity() { synchronized (Helper.class) { if (sDensity == Float.MAX_VALUE) { sDensity = getDisplayMetrics().density; } return sDensity; } } /** * Convert absolute pixels to scale dependent pixels. * This scales the size by scale dependent screen density (accessibility setting) and * the global display setting for message composition fields */ public static int convertPxToSp(int pxSize) { return Math.round((float) pxSize * getDisplayDensity4Fonts()); } /** * Convert scale dependent pixels to absolute pixels. * This scales the size by scale dependent screen density (accessibility setting) and * the global display setting for message composition fields */ public static int convertSpToPx(int spSize) { return Math.round((float) spSize / getDisplayDensity4Fonts()); } private static DisplayMetrics getDisplayMetrics() { Display display = ((WindowManager) RTApi.getApplicationContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); DisplayMetrics metrics = new DisplayMetrics(); display.getMetrics(metrics); return metrics; } private static float getDisplayDensity4Fonts() { synchronized (Helper.class) { if (sDensity4Fonts == Float.MAX_VALUE) { sDensity4Fonts = getDisplayMetrics().density * getFontScale(); } return sDensity4Fonts; } } private static float getFontScale() { Configuration config = RTApi.getApplicationContext().getResources().getConfiguration(); return config.fontScale; } public static int getLeadingMarging() { if (sLeadingMarging == -1) { float density = Helper.getDisplayDensity(); sLeadingMarging = Math.round(LEADING_MARGIN * density); } return sLeadingMarging; } /** * This method encodes the query part of an url * @param url an url (e.g. http://www.1gravity.com?query=üö) * @return The url with an encoded query, e.g. http://www.1gravity.com?query%3D%C3%BC%C3%B6 */ public static String encodeUrl(String url) { Uri uri = Uri.parse(url); try { Map<String, List<String>> splitQuery = splitQuery(uri); StringBuilder encodedQuery = new StringBuilder(); for (String key : splitQuery.keySet()) { for (String value : splitQuery.get(key)) { if (encodedQuery.length() > 0) { encodedQuery.append("&"); } encodedQuery.append(key + "=" + URLEncoder.encode(value, "UTF-8")); } } String queryString = encodedQuery != null && encodedQuery.length() > 0 ? "?" + encodedQuery : ""; URI baseUri = new URI(uri.getScheme(), uri.getAuthority(), uri.getPath(), null, uri.getFragment()); return baseUri + queryString; } catch (UnsupportedEncodingException ignore) {} catch (URISyntaxException ignore) {} return uri.toString(); } /** * This method decodes an url with encoded query string * @param url an url with encoded query string (e.g. http://www.1gravity.com?query%C3%BC%C3%B6) * @return The decoded url, e.g. http://www.1gravity.com?query=üö */ public static String decodeQuery(String url) { try { return URLDecoder.decode(url, "UTF-8"); } catch (UnsupportedEncodingException ignore) {} return url; } /** * Splits the query parameters into key value pairs. * See: http://stackoverflow.com/a/13592567/534471. */ private static Map<String, List<String>> splitQuery(Uri uri) throws UnsupportedEncodingException { final Map<String, List<String>> query_pairs = new LinkedHashMap<>(); String query = uri.getQuery(); if (query == null) return query_pairs; final String[] pairs = query.split("&"); for (String pair : pairs) { final int idx = pair.indexOf("="); final String key = idx > 0 ? URLDecoder.decode(pair.substring(0, idx), "UTF-8") : pair; if (!query_pairs.containsKey(key)) { query_pairs.put(key, new LinkedList<String>()); } final String value = idx > 0 && pair.length() > idx + 1 ? URLDecoder.decode(pair.substring(idx + 1), "UTF-8") : ""; query_pairs.get(key).add(value); } return query_pairs; } /** * This method determines if the direction of a substring is right-to-left. * If the string is empty that determination is based on the default system language * Locale.getDefault(). * The method can handle invalid substring definitions (start > end etc.), in which case the * method returns False. * * @return True if the text direction is right-to-left, false otherwise. */ public static boolean isRTL(CharSequence s, int start, int end) { if (s == null || s.length() == 0) { // empty string --> determine the direction from the default language return isRTL(Locale.getDefault()); } if (start == end) { // if no character is selected we need to expand the selection start = Math.max(0, --start); if (start == end) { end = Math.min(s.length(), ++end); } } try { Bidi bidi = new Bidi(s.subSequence(start, end).toString(), Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT); return ! bidi.baseIsLeftToRight(); } catch (IndexOutOfBoundsException e) { return false; } } private static boolean isRTL(Locale locale) { int directionality = Character.getDirectionality(locale.getDisplayName().charAt(0)); return directionality == Character.DIRECTIONALITY_RIGHT_TO_LEFT || directionality == Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC; } }