813 lines
26 KiB
Java
813 lines
26 KiB
Java
/*
|
||
* Copyright (C) 2015 Hippo Seven
|
||
*
|
||
* 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.hippo.util;
|
||
|
||
import android.annotation.SuppressLint;
|
||
import android.content.Context;
|
||
import android.os.AsyncTask;
|
||
import android.os.Build;
|
||
import android.os.Vibrator;
|
||
import android.support.annotation.NonNull;
|
||
import android.text.TextUtils;
|
||
import android.webkit.MimeTypeMap;
|
||
|
||
import java.io.ByteArrayOutputStream;
|
||
import java.io.Closeable;
|
||
import java.io.EOFException;
|
||
import java.io.File;
|
||
import java.io.FileInputStream;
|
||
import java.io.FileOutputStream;
|
||
import java.io.IOException;
|
||
import java.io.InputStream;
|
||
import java.io.OutputStream;
|
||
import java.lang.reflect.Method;
|
||
import java.text.DateFormat;
|
||
import java.text.SimpleDateFormat;
|
||
import java.util.Collection;
|
||
import java.util.Date;
|
||
import java.util.Locale;
|
||
|
||
public final class Utils {
|
||
@SuppressWarnings("unused")
|
||
private static String TAG = Utils.class.getSimpleName();
|
||
|
||
public static final DateFormat DATE_FORMATE_FOR_GALLERY = new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.US);
|
||
|
||
public static final DateFormat DATE_FORMATE_FOR_UPDATE = new SimpleDateFormat("yyyyMMdd", Locale.US);
|
||
|
||
public static final String EMPTY_STRING = "";
|
||
|
||
/**
|
||
* Colse is. Don't worry about anything.
|
||
*
|
||
* @param is
|
||
*/
|
||
public static void closeQuietly(Closeable is) {
|
||
try {
|
||
if (is != null)
|
||
is.close();
|
||
} catch (IOException e) {
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Put InputStream to File, default bufferSize is 512 * 1024
|
||
*
|
||
* @param is
|
||
* @param file
|
||
* @throws java.io.IOException
|
||
*/
|
||
public static void inputStream2File(InputStream is, File file) throws IOException {
|
||
OutputStream os = new FileOutputStream(file);
|
||
copy(is, os);
|
||
os.close();
|
||
}
|
||
|
||
/**
|
||
* Copy from is to os
|
||
*
|
||
* @param is
|
||
* @param os
|
||
* @throws java.io.IOException
|
||
*/
|
||
public static void copy(InputStream is, OutputStream os) throws IOException {
|
||
copy(is, os, 512 * 1024);
|
||
}
|
||
|
||
/**
|
||
* Copy from is to os
|
||
*
|
||
* @param is
|
||
* @param os
|
||
* @param size Buffer size
|
||
* @throws java.io.IOException
|
||
*/
|
||
public static void copy(InputStream is, OutputStream os, int size) throws IOException {
|
||
byte[] buffer = new byte[size];
|
||
int bytesRead;
|
||
while((bytesRead = is.read(buffer)) !=-1)
|
||
os.write(buffer, 0, bytesRead);
|
||
os.flush();
|
||
}
|
||
|
||
/**
|
||
* Get String from InputStream
|
||
*
|
||
* @param is
|
||
* @param charset
|
||
* @param size The InputStream size you estimate
|
||
* @return
|
||
*/
|
||
public static String inputStream2String(InputStream is, String charset, int size) {
|
||
ByteArrayOutputStream baos = new ByteArrayOutputStream(size);
|
||
String str = null;
|
||
try {
|
||
copy(is, baos, 1024);
|
||
str = baos.toString(charset);
|
||
} catch (IOException e) {
|
||
e.printStackTrace();
|
||
} finally {
|
||
closeQuietly(baos);
|
||
}
|
||
return str;
|
||
}
|
||
|
||
/**
|
||
* Not work for dir, Copy from scr to dst, no matter dst exist or not.
|
||
*
|
||
* @param src
|
||
* @param dst
|
||
* @return True for success, false for fail
|
||
*/
|
||
public static boolean copyFile(File src, File dst) {
|
||
FileInputStream fis = null;
|
||
FileOutputStream fos = null;
|
||
try {
|
||
fis = new FileInputStream(src);
|
||
fos = new FileOutputStream(dst);
|
||
copy(fis, fos);
|
||
} catch (Throwable e) {
|
||
return false;
|
||
} finally {
|
||
closeQuietly(fis);
|
||
closeQuietly(fos);
|
||
}
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* If you want to copy on new thread, use it to know
|
||
* success or not.
|
||
*/
|
||
public static interface OnCopyFileOverListener {
|
||
public void onCopyFileOver(boolean success, File src, File dst);
|
||
}
|
||
|
||
/**
|
||
* Copy file in new thread
|
||
*
|
||
* @param src
|
||
* @param dst
|
||
* @param l
|
||
*/
|
||
public static void copyFileInNewThread(final File src, final File dst, final OnCopyFileOverListener l) {
|
||
execute(false, new AsyncTask<Void, Void, Boolean>() {
|
||
@Override
|
||
protected Boolean doInBackground(Void... params) {
|
||
return copyFile(src, dst);
|
||
}
|
||
|
||
@Override
|
||
protected void onPostExecute(Boolean result) {
|
||
if (l != null)
|
||
l.onCopyFileOver(result, src, dst);
|
||
}
|
||
}, (Void[]) null);
|
||
}
|
||
|
||
/**
|
||
* Try to delete file or dir and it's children.
|
||
*
|
||
* @param file The file to deleted.
|
||
* @return True if file is delete, children included.
|
||
*/
|
||
public static boolean deleteFile(File file) {
|
||
if (file == null) {
|
||
return false;
|
||
}
|
||
|
||
boolean result = true;
|
||
|
||
File[] files = file.listFiles();
|
||
if (files != null) {
|
||
for (File f : files)
|
||
deleteFile(f);
|
||
}
|
||
if (file.exists()) {
|
||
// Avoid EBUSY (Device or resource busy) error
|
||
final File to = new File(file.getAbsolutePath()
|
||
+ System.currentTimeMillis());
|
||
if (file.renameTo(to))
|
||
result &= to.delete();
|
||
else
|
||
result &= file.delete();
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* If you want to copy on new thread, use it to know
|
||
* success or not.
|
||
*/
|
||
public static interface OnDeleteFileOverListener {
|
||
public void onDeleteFileOver(boolean success, File file);
|
||
}
|
||
|
||
/**
|
||
* Start a new thread to delete dir
|
||
*/
|
||
public static void deleteFileInNewThread(final File file, final OnDeleteFileOverListener l) {
|
||
execute(false, new AsyncTask<Void, Void, Boolean>() {
|
||
@Override
|
||
protected Boolean doInBackground(Void... params) {
|
||
return deleteFile(file);
|
||
}
|
||
|
||
@Override
|
||
protected void onPostExecute(Boolean result) {
|
||
if (l != null)
|
||
l.onDeleteFileOver(result, file);
|
||
}
|
||
}, (Void[]) null);
|
||
}
|
||
|
||
public static int getDateForUpdate() {
|
||
return Utils.parseIntSafely(DATE_FORMATE_FOR_UPDATE.format(new Date()), 0);
|
||
}
|
||
|
||
// http://stackoverflow.com/questions/3758606/
|
||
public static String humanReadableByteCount(long bytes, boolean si) {
|
||
int unit = si ? 1000 : 1024;
|
||
if (bytes < unit) return bytes + " B";
|
||
int exp = (int) (Math.log(bytes) / Math.log(unit));
|
||
char pre = "KMGTPE".charAt(exp-1);
|
||
return String.format("%.1f %cB", bytes / Math.pow(unit, exp), pre);
|
||
}
|
||
|
||
/**
|
||
* Execute an {@link android.os.AsyncTask} on a thread pool
|
||
*
|
||
* @param forceSerial True to force the task to run in serial order
|
||
* @param task Task to execute
|
||
* @param args Optional arguments to pass to
|
||
* {@link android.os.AsyncTask#execute(Object[])}
|
||
* @param <T> Task argument type
|
||
*/
|
||
@SafeVarargs
|
||
@SuppressLint("NewApi")
|
||
public static <T> void execute(final boolean forceSerial, final AsyncTask<T, ?, ?> task,
|
||
final T... args) {
|
||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.DONUT) {
|
||
throw new UnsupportedOperationException(
|
||
"This class can only be used on API 4 and newer.");
|
||
}
|
||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB || forceSerial) {
|
||
task.execute(args);
|
||
} else {
|
||
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, args);
|
||
}
|
||
}
|
||
|
||
private static final String[] ESCAPE_CHARATER_LIST = {
|
||
"&",
|
||
"<",
|
||
">",
|
||
""",
|
||
"'",
|
||
"×"
|
||
};
|
||
|
||
private static final String[] UNESCAPE_CHARATER_LIST = {
|
||
"&",
|
||
"<",
|
||
">",
|
||
"\"",
|
||
"'",
|
||
"×"
|
||
};
|
||
|
||
/**
|
||
* Mostly title and url need it
|
||
* @param str
|
||
* @return
|
||
*/
|
||
public static String unescapeXml(String str) {
|
||
return replaceEach(str, ESCAPE_CHARATER_LIST, UNESCAPE_CHARATER_LIST);
|
||
}
|
||
|
||
/**
|
||
* Make file name valid by removing invalid character and set max length
|
||
* @param name
|
||
* @return
|
||
*/
|
||
public static String standardizeFilename(String name) {
|
||
String result = name;
|
||
// Remove invaild char
|
||
result = result.replaceAll("[\\\\/:*?\"<>\\|]", "");
|
||
// Make sure size
|
||
if (result.length() > 255)
|
||
result = result.substring(0, 255);
|
||
// Avoid start with whitespace or end with whitespace
|
||
result = result.replaceAll("^[\\s]+", "").replace("[\\s]+$", "");
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Joins the elements of the provided array into a single String
|
||
* containing the provided list of elements.
|
||
*
|
||
* @param array
|
||
* @param separator
|
||
* @return
|
||
*/
|
||
public static String join(final Object[] array,
|
||
final Object separator) {
|
||
final StringBuilder sb = new StringBuilder(array.length * 16);
|
||
for (int i = 0; i < array.length; i++) {
|
||
if (i != 0)
|
||
sb.append(separator);
|
||
sb.append(array[i]);
|
||
}
|
||
return sb.toString();
|
||
}
|
||
|
||
/**
|
||
* <p>
|
||
* Replaces all occurrences of Strings within another String.
|
||
* </p>
|
||
*
|
||
* <p>
|
||
* A {@code null} reference passed to this method is a no-op, or if
|
||
* any "search string" or "string to replace" is null, that replace will be
|
||
* ignored. This will not repeat. For repeating replaces, call the
|
||
* overloaded method.
|
||
* </p>
|
||
*
|
||
* <pre>
|
||
* StringUtils.replaceEach(null, *, *) = null
|
||
* StringUtils.replaceEach("", *, *) = ""
|
||
* StringUtils.replaceEach("aba", null, null) = "aba"
|
||
* StringUtils.replaceEach("aba", new String[0], null) = "aba"
|
||
* StringUtils.replaceEach("aba", null, new String[0]) = "aba"
|
||
* StringUtils.replaceEach("aba", new String[]{"a"}, null) = "aba"
|
||
* StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}) = "b"
|
||
* StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}) = "aba"
|
||
* StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}) = "wcte"
|
||
* (example of how it does not repeat)
|
||
* StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}) = "dcte"
|
||
* </pre>
|
||
*
|
||
* @param text
|
||
* text to search and replace in, no-op if null
|
||
* @param searchList
|
||
* the Strings to search for, no-op if null
|
||
* @param replacementList
|
||
* the Strings to replace them with, no-op if null
|
||
* @return the text with any replacements processed, {@code null} if
|
||
* null String input
|
||
* @throws IllegalArgumentException
|
||
* if the lengths of the arrays are not the same (null is ok,
|
||
* and/or size 0)
|
||
*/
|
||
// Get from org.apache.commons.lang3.StringUtils
|
||
public static String replaceEach(final String text, final String[] searchList, final String[] replacementList) {
|
||
return replaceEach(text, searchList, replacementList, false, 0);
|
||
}
|
||
|
||
/**
|
||
* <p>
|
||
* Replaces all occurrences of Strings within another String.
|
||
* </p>
|
||
*
|
||
* <p>
|
||
* A {@code null} reference passed to this method is a no-op, or if
|
||
* any "search string" or "string to replace" is null, that replace will be
|
||
* ignored.
|
||
* </p>
|
||
*
|
||
* <pre>
|
||
* StringUtils.replaceEach(null, *, *, *) = null
|
||
* StringUtils.replaceEach("", *, *, *) = ""
|
||
* StringUtils.replaceEach("aba", null, null, *) = "aba"
|
||
* StringUtils.replaceEach("aba", new String[0], null, *) = "aba"
|
||
* StringUtils.replaceEach("aba", null, new String[0], *) = "aba"
|
||
* StringUtils.replaceEach("aba", new String[]{"a"}, null, *) = "aba"
|
||
* StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}, *) = "b"
|
||
* StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}, *) = "aba"
|
||
* StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}, *) = "wcte"
|
||
* (example of how it repeats)
|
||
* StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, false) = "dcte"
|
||
* StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, true) = "tcte"
|
||
* StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, *) = IllegalStateException
|
||
* </pre>
|
||
*
|
||
* @param text
|
||
* text to search and replace in, no-op if null
|
||
* @param searchList
|
||
* the Strings to search for, no-op if null
|
||
* @param replacementList
|
||
* the Strings to replace them with, no-op if null
|
||
* @param repeat if true, then replace repeatedly
|
||
* until there are no more possible replacements or timeToLive < 0
|
||
* @param timeToLive
|
||
* if less than 0 then there is a circular reference and endless
|
||
* loop
|
||
* @return the text with any replacements processed, {@code null} if
|
||
* null String input
|
||
* @throws IllegalStateException
|
||
* if the search is repeating and there is an endless loop due
|
||
* to outputs of one being inputs to another
|
||
* @throws IllegalArgumentException
|
||
* if the lengths of the arrays are not the same (null is ok,
|
||
* and/or size 0)
|
||
*/
|
||
// Get from org.apache.commons.lang3.StringUtils
|
||
private static String replaceEach(
|
||
final String text, final String[] searchList, final String[] replacementList, final boolean repeat, final int timeToLive) {
|
||
|
||
// mchyzer Performance note: This creates very few new objects (one major goal)
|
||
// let me know if there are performance requests, we can create a harness to measure
|
||
|
||
if (text == null || TextUtils.isEmpty(text) || searchList == null ||
|
||
searchList.length == 0 || replacementList == null || replacementList.length == 0) {
|
||
return text;
|
||
}
|
||
|
||
// if recursing, this shouldn't be less than 0
|
||
if (timeToLive < 0) {
|
||
throw new IllegalStateException("Aborting to protect against StackOverflowError - " +
|
||
"output of one loop is the input of another");
|
||
}
|
||
|
||
final int searchLength = searchList.length;
|
||
final int replacementLength = replacementList.length;
|
||
|
||
// make sure lengths are ok, these need to be equal
|
||
if (searchLength != replacementLength) {
|
||
throw new IllegalArgumentException("Search and Replace array lengths don't match: "
|
||
+ searchLength
|
||
+ " vs "
|
||
+ replacementLength);
|
||
}
|
||
|
||
// keep track of which still have matches
|
||
final boolean[] noMoreMatchesForReplIndex = new boolean[searchLength];
|
||
|
||
// index on index that the match was found
|
||
int textIndex = -1;
|
||
int replaceIndex = -1;
|
||
int tempIndex = -1;
|
||
|
||
// index of replace array that will replace the search string found
|
||
// NOTE: logic duplicated below START
|
||
for (int i = 0; i < searchLength; i++) {
|
||
if (noMoreMatchesForReplIndex[i] || searchList[i] == null ||
|
||
TextUtils.isEmpty(searchList[i]) || replacementList[i] == null) {
|
||
continue;
|
||
}
|
||
tempIndex = text.indexOf(searchList[i]);
|
||
|
||
// see if we need to keep searching for this
|
||
if (tempIndex == -1) {
|
||
noMoreMatchesForReplIndex[i] = true;
|
||
} else {
|
||
if (textIndex == -1 || tempIndex < textIndex) {
|
||
textIndex = tempIndex;
|
||
replaceIndex = i;
|
||
}
|
||
}
|
||
}
|
||
// NOTE: logic mostly below END
|
||
|
||
// no search strings found, we are done
|
||
if (textIndex == -1) {
|
||
return text;
|
||
}
|
||
|
||
int start = 0;
|
||
|
||
// get a good guess on the size of the result buffer so it doesn't have to double if it goes over a bit
|
||
int increase = 0;
|
||
|
||
// count the replacement text elements that are larger than their corresponding text being replaced
|
||
for (int i = 0; i < searchList.length; i++) {
|
||
if (searchList[i] == null || replacementList[i] == null) {
|
||
continue;
|
||
}
|
||
final int greater = replacementList[i].length() - searchList[i].length();
|
||
if (greater > 0) {
|
||
increase += 3 * greater; // assume 3 matches
|
||
}
|
||
}
|
||
// have upper-bound at 20% increase, then let Java take over
|
||
increase = Math.min(increase, text.length() / 5);
|
||
|
||
final StringBuilder buf = new StringBuilder(text.length() + increase);
|
||
|
||
while (textIndex != -1) {
|
||
|
||
for (int i = start; i < textIndex; i++) {
|
||
buf.append(text.charAt(i));
|
||
}
|
||
buf.append(replacementList[replaceIndex]);
|
||
|
||
start = textIndex + searchList[replaceIndex].length();
|
||
|
||
textIndex = -1;
|
||
replaceIndex = -1;
|
||
tempIndex = -1;
|
||
// find the next earliest match
|
||
// NOTE: logic mostly duplicated above START
|
||
for (int i = 0; i < searchLength; i++) {
|
||
if (noMoreMatchesForReplIndex[i] || searchList[i] == null ||
|
||
TextUtils.isEmpty(searchList[i]) || replacementList[i] == null) {
|
||
continue;
|
||
}
|
||
tempIndex = text.indexOf(searchList[i], start);
|
||
|
||
// see if we need to keep searching for this
|
||
if (tempIndex == -1) {
|
||
noMoreMatchesForReplIndex[i] = true;
|
||
} else {
|
||
if (textIndex == -1 || tempIndex < textIndex) {
|
||
textIndex = tempIndex;
|
||
replaceIndex = i;
|
||
}
|
||
}
|
||
}
|
||
// NOTE: logic duplicated above END
|
||
|
||
}
|
||
final int textLength = text.length();
|
||
for (int i = start; i < textLength; i++) {
|
||
buf.append(text.charAt(i));
|
||
}
|
||
final String result = buf.toString();
|
||
if (!repeat) {
|
||
return result;
|
||
}
|
||
|
||
return replaceEach(result, searchList, replacementList, repeat, timeToLive - 1);
|
||
}
|
||
|
||
/**
|
||
* 0 for false, Non 0 for true
|
||
*
|
||
* @param integer
|
||
* @return
|
||
*/
|
||
public static boolean int2boolean(int integer) {
|
||
return integer != 0;
|
||
}
|
||
|
||
/**
|
||
* false for 0, true for 1
|
||
*
|
||
* @param bool
|
||
* @return
|
||
*/
|
||
public static int boolean2int(boolean bool) {
|
||
return bool ? 1 : 0;
|
||
}
|
||
|
||
/**
|
||
* Returns the ASCII characters up to but not including the next "\r\n", or
|
||
* "\n".
|
||
*
|
||
* @throws java.io.EOFException if the stream is exhausted before the next
|
||
* newline character.
|
||
*/
|
||
public static String readAsciiLine(final InputStream in) throws IOException {
|
||
final StringBuilder result = new StringBuilder(80);
|
||
while (true) {
|
||
final int c = in.read();
|
||
if (c == -1) {
|
||
throw new EOFException();
|
||
} else if (c == '\n') {
|
||
break;
|
||
}
|
||
|
||
result.append((char)c);
|
||
}
|
||
final int length = result.length();
|
||
if (length > 0 && result.charAt(length - 1) == '\r') {
|
||
result.setLength(length - 1);
|
||
}
|
||
return result.toString();
|
||
}
|
||
|
||
/**
|
||
* Try to make dir exists
|
||
*
|
||
* @param dir
|
||
* @param force
|
||
*/
|
||
public static void ensureDir(File dir, boolean force) {
|
||
if (!dir.exists()) {
|
||
dir.mkdirs();
|
||
} else if (force && dir.isFile()) {
|
||
dir.delete();
|
||
dir.mkdirs();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Return true if point is in the rect
|
||
*
|
||
* @param area
|
||
* @param x
|
||
* @param y
|
||
* @return
|
||
*/
|
||
public static boolean isInArea(int[] area, int x, int y) {
|
||
if (area == null)
|
||
throw new NullPointerException("area == null");
|
||
if (area.length != 4)
|
||
throw new IllegalArgumentException(
|
||
"area's length should be 4, but it's length is " + area.length);
|
||
if (x >= area[0] && x < area[2] && y >= area[1] && y < area[3])
|
||
return true;
|
||
else
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* Is color is opaque
|
||
*
|
||
* @param color
|
||
* @return
|
||
*/
|
||
// TODO put it to UiUtils.class
|
||
public static boolean isOpaque(int color) {
|
||
return color >>> 24 == 0xFF;
|
||
}
|
||
|
||
/**
|
||
* Throws AssertionError if the input is false.
|
||
* @param cond
|
||
*/
|
||
public static void assertTrue(boolean cond) {
|
||
if (!cond) {
|
||
throw new AssertionError();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* vibrator
|
||
*
|
||
* @param context
|
||
* @param milliseconds Duration
|
||
*/
|
||
public static void vibrator(Context context, long milliseconds) {
|
||
// If user force disable vibrator permission, may throw error
|
||
try {
|
||
Vibrator v = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
|
||
v.vibrate(milliseconds);
|
||
} catch (Throwable e) {
|
||
}
|
||
}
|
||
|
||
// Removes duplicate adjacent slashes and any trailing slash.
|
||
private static String fixSlashes(String origPath) {
|
||
// Remove duplicate adjacent slashes.
|
||
boolean lastWasSlash = false;
|
||
char[] newPath = origPath.toCharArray();
|
||
int length = newPath.length;
|
||
int newLength = 0;
|
||
for (int i = 0; i < length; ++i) {
|
||
char ch = newPath[i];
|
||
if (ch == '/') {
|
||
if (!lastWasSlash) {
|
||
newPath[newLength++] = File.separatorChar;
|
||
lastWasSlash = true;
|
||
}
|
||
} else {
|
||
newPath[newLength++] = ch;
|
||
lastWasSlash = false;
|
||
}
|
||
}
|
||
// Remove any trailing slash (unless this is the root of the file system).
|
||
if (lastWasSlash && newLength > 1) {
|
||
newLength--;
|
||
}
|
||
// Reuse the original string if possible.
|
||
return (newLength != length) ? new String(newPath, 0, newLength) : origPath;
|
||
}
|
||
|
||
// Joins two path components, adding a separator only if necessary.
|
||
public static String joinPath(String dirPath, String name) {
|
||
if (name == null) {
|
||
throw new NullPointerException("name == null");
|
||
}
|
||
if (dirPath == null || TextUtils.isEmpty(dirPath)) {
|
||
return fixSlashes(name);
|
||
} else if (TextUtils.isEmpty(name)) {
|
||
return fixSlashes(dirPath);
|
||
} else {
|
||
int prefixLength = dirPath.length();
|
||
boolean haveSlash = (prefixLength > 0 && dirPath.charAt(prefixLength - 1) == File.separatorChar);
|
||
if (!haveSlash) {
|
||
haveSlash = (name.length() > 0 && name.charAt(0) == File.separatorChar);
|
||
}
|
||
return fixSlashes(haveSlash ? (dirPath + name) : (dirPath + File.separatorChar + name));
|
||
}
|
||
}
|
||
|
||
public static int parseIntSafely(String str, int defaultValue) {
|
||
try {
|
||
return Integer.parseInt(str);
|
||
} catch (Throwable e) {
|
||
return defaultValue;
|
||
}
|
||
}
|
||
|
||
public static float parseFloatSafely(String str, float defaultValue) {
|
||
try {
|
||
return Float.parseFloat(str);
|
||
} catch (Throwable e) {
|
||
return defaultValue;
|
||
}
|
||
}
|
||
|
||
public static int[] toIntArray(Collection<? extends Number> collection) {
|
||
Object[] boxedArray = collection.toArray();
|
||
int len = boxedArray.length;
|
||
int[] array = new int[len];
|
||
for (int i = 0; i < len; i++) {
|
||
// checkNotNull for GWT (do not optimize)
|
||
array[i] = ((Number) (boxedArray[i])).intValue();
|
||
}
|
||
return array;
|
||
}
|
||
|
||
// Throws NullPointerException if the input is null.
|
||
public static <T> T checkNotNull(T object) {
|
||
if (object == null) throw new NullPointerException();
|
||
return object;
|
||
}
|
||
|
||
/**
|
||
* Get extension from target string, int lower case
|
||
*
|
||
* @param name
|
||
* @param defautl
|
||
* @return
|
||
*/
|
||
public static String getExtension(String name, String defautl) {
|
||
String ext = MimeTypeMap.getFileExtensionFromUrl(name);
|
||
if (TextUtils.isEmpty(ext))
|
||
ext = defautl;
|
||
return ext;
|
||
}
|
||
|
||
/**
|
||
* It will return null if can't find mime
|
||
*
|
||
* @param url
|
||
* @return
|
||
*/
|
||
public static String getMimeType(String url) {
|
||
String type = null;
|
||
String extension = MimeTypeMap.getFileExtensionFromUrl(url);
|
||
if (extension != null) {
|
||
MimeTypeMap mime = MimeTypeMap.getSingleton();
|
||
type = mime.getMimeTypeFromExtension(extension);
|
||
}
|
||
return type;
|
||
}
|
||
|
||
/**
|
||
* If get error return "";
|
||
*
|
||
* @param key
|
||
* @return
|
||
*/
|
||
public static String getSystemProperties(String key) {
|
||
try {
|
||
@SuppressWarnings("rawtypes")
|
||
Class c = Class.forName("android.os.SystemProperties");
|
||
@SuppressWarnings("unchecked")
|
||
Method m = c.getDeclaredMethod("get", String.class);
|
||
m.setAccessible(true);
|
||
String result = (String) m.invoke(null, key);
|
||
return result == null ? EMPTY_STRING : result;
|
||
} catch (Throwable e) {
|
||
return EMPTY_STRING;
|
||
}
|
||
}
|
||
|
||
public static boolean contain(@NonNull Object[] array, Object obj) {
|
||
for (Object o : array) {
|
||
if (o.equals(obj)) {
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
}
|