2012-10-01 02:56:29 +00:00
|
|
|
/**
|
2011-12-20 18:20:44 +00:00
|
|
|
* Copyright (C) 2011 Whisper Systems
|
2012-10-01 02:56:29 +00:00
|
|
|
*
|
2011-12-20 18:20:44 +00:00
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
2012-10-01 02:56:29 +00:00
|
|
|
*
|
2011-12-20 18:20:44 +00:00
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
package org.thoughtcrime.securesms.util;
|
|
|
|
|
2014-01-11 11:34:11 +00:00
|
|
|
import android.annotation.SuppressLint;
|
2013-07-17 22:13:00 +00:00
|
|
|
import android.content.Context;
|
2014-07-23 22:40:45 +00:00
|
|
|
import android.content.pm.PackageManager;
|
2014-11-12 19:15:05 +00:00
|
|
|
import android.graphics.Shader;
|
2013-02-08 19:57:54 +00:00
|
|
|
import android.graphics.Typeface;
|
2014-11-12 19:15:05 +00:00
|
|
|
import android.graphics.drawable.BitmapDrawable;
|
|
|
|
import android.graphics.drawable.Drawable;
|
2014-02-19 21:46:49 +00:00
|
|
|
import android.os.Build;
|
|
|
|
import android.provider.Telephony;
|
2014-11-12 19:15:05 +00:00
|
|
|
import android.telephony.TelephonyManager;
|
2013-02-08 19:57:54 +00:00
|
|
|
import android.text.Spannable;
|
|
|
|
import android.text.SpannableString;
|
2014-11-12 19:15:05 +00:00
|
|
|
import android.text.TextUtils;
|
2013-02-08 19:57:54 +00:00
|
|
|
import android.text.style.StyleSpan;
|
2014-11-12 19:15:05 +00:00
|
|
|
import android.widget.EditText;
|
2013-02-04 08:13:07 +00:00
|
|
|
|
2014-11-12 19:15:05 +00:00
|
|
|
import org.whispersystems.textsecure.api.util.PhoneNumberFormatter;
|
|
|
|
import org.whispersystems.textsecure.api.util.InvalidNumberException;
|
2013-07-17 02:52:02 +00:00
|
|
|
|
2013-07-19 00:42:45 +00:00
|
|
|
import java.io.ByteArrayOutputStream;
|
|
|
|
import java.io.IOException;
|
|
|
|
import java.io.InputStream;
|
2014-11-12 19:15:05 +00:00
|
|
|
import java.io.OutputStream;
|
2013-04-26 18:23:43 +00:00
|
|
|
import java.io.UnsupportedEncodingException;
|
2014-11-12 19:15:05 +00:00
|
|
|
import java.security.NoSuchAlgorithmException;
|
|
|
|
import java.security.SecureRandom;
|
|
|
|
import java.util.Collection;
|
|
|
|
import java.util.Collections;
|
|
|
|
import java.util.LinkedList;
|
|
|
|
import java.util.List;
|
2012-12-27 20:00:14 +00:00
|
|
|
import java.util.concurrent.ExecutorService;
|
|
|
|
import java.util.concurrent.ThreadPoolExecutor;
|
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
|
2013-04-26 18:23:43 +00:00
|
|
|
import ws.com.google.android.mms.pdu.CharacterSets;
|
2013-04-26 01:59:49 +00:00
|
|
|
import ws.com.google.android.mms.pdu.EncodedStringValue;
|
|
|
|
|
2011-12-20 18:20:44 +00:00
|
|
|
public class Util {
|
|
|
|
|
2014-11-12 19:15:05 +00:00
|
|
|
public static String join(Collection<String> list, String delimiter) {
|
|
|
|
StringBuilder result = new StringBuilder();
|
|
|
|
int i=0;
|
2012-10-01 02:56:29 +00:00
|
|
|
|
2014-11-12 19:15:05 +00:00
|
|
|
for (String item : list) {
|
|
|
|
result.append(item);
|
2012-10-01 02:56:29 +00:00
|
|
|
|
2014-11-12 19:15:05 +00:00
|
|
|
if (++i < list.size())
|
|
|
|
result.append(delimiter);
|
|
|
|
}
|
2012-10-01 02:56:29 +00:00
|
|
|
|
2014-11-12 19:15:05 +00:00
|
|
|
return result.toString();
|
2011-12-20 18:20:44 +00:00
|
|
|
}
|
2012-10-01 02:56:29 +00:00
|
|
|
|
2012-12-27 20:00:14 +00:00
|
|
|
public static ExecutorService newSingleThreadedLifoExecutor() {
|
2013-01-06 23:46:26 +00:00
|
|
|
ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingLifoQueue<Runnable>());
|
|
|
|
|
|
|
|
executor.execute(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
// Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
|
|
|
|
Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
return executor;
|
2012-12-27 20:00:14 +00:00
|
|
|
}
|
|
|
|
|
2013-04-26 01:59:49 +00:00
|
|
|
public static boolean isEmpty(EncodedStringValue[] value) {
|
|
|
|
return value == null || value.length == 0;
|
|
|
|
}
|
|
|
|
|
2014-11-12 19:15:05 +00:00
|
|
|
public static boolean isEmpty(EditText value) {
|
|
|
|
return value == null || value.getText() == null || TextUtils.isEmpty(value.getText().toString());
|
2013-02-08 19:57:54 +00:00
|
|
|
}
|
|
|
|
|
2014-11-12 19:15:05 +00:00
|
|
|
public static CharSequence getBoldedString(String value) {
|
2013-02-08 19:57:54 +00:00
|
|
|
SpannableString spanned = new SpannableString(value);
|
2014-11-12 19:15:05 +00:00
|
|
|
spanned.setSpan(new StyleSpan(Typeface.BOLD), 0,
|
2013-02-08 19:57:54 +00:00
|
|
|
spanned.length(),
|
|
|
|
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
|
|
|
|
|
|
return spanned;
|
|
|
|
}
|
|
|
|
|
2013-04-26 18:23:43 +00:00
|
|
|
public static String toIsoString(byte[] bytes) {
|
|
|
|
try {
|
|
|
|
return new String(bytes, CharacterSets.MIMENAME_ISO_8859_1);
|
|
|
|
} catch (UnsupportedEncodingException e) {
|
2014-04-20 21:18:17 +00:00
|
|
|
throw new AssertionError("ISO_8859_1 must be supported!");
|
2013-04-26 18:23:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static byte[] toIsoBytes(String isoString) {
|
|
|
|
try {
|
|
|
|
return isoString.getBytes(CharacterSets.MIMENAME_ISO_8859_1);
|
|
|
|
} catch (UnsupportedEncodingException e) {
|
2014-04-20 21:18:17 +00:00
|
|
|
throw new AssertionError("ISO_8859_1 must be supported!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static byte[] toUtf8Bytes(String utf8String) {
|
|
|
|
try {
|
|
|
|
return utf8String.getBytes(CharacterSets.MIMENAME_UTF_8);
|
|
|
|
} catch (UnsupportedEncodingException e) {
|
|
|
|
throw new AssertionError("UTF_8 must be supported!");
|
2013-04-26 18:23:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-17 02:52:02 +00:00
|
|
|
public static void wait(Object lock, int timeout) {
|
|
|
|
try {
|
|
|
|
lock.wait(timeout);
|
|
|
|
} catch (InterruptedException ie) {
|
|
|
|
throw new AssertionError(ie);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-26 20:44:15 +00:00
|
|
|
public static String canonicalizeNumber(Context context, String number)
|
|
|
|
throws InvalidNumberException
|
|
|
|
{
|
2013-07-17 22:13:00 +00:00
|
|
|
String localNumber = TextSecurePreferences.getLocalNumber(context);
|
|
|
|
return PhoneNumberFormatter.formatNumber(number, localNumber);
|
|
|
|
}
|
|
|
|
|
2014-10-21 04:06:34 +00:00
|
|
|
public static String canonicalizeNumberOrGroup(Context context, String number)
|
|
|
|
throws InvalidNumberException
|
|
|
|
{
|
|
|
|
if (GroupUtil.isEncodedGroup(number)) return number;
|
|
|
|
else return canonicalizeNumber(context, number);
|
|
|
|
}
|
|
|
|
|
2014-12-12 09:03:24 +00:00
|
|
|
public static byte[] readFully(InputStream in) throws IOException {
|
2014-11-12 19:15:05 +00:00
|
|
|
ByteArrayOutputStream bout = new ByteArrayOutputStream();
|
|
|
|
byte[] buffer = new byte[4096];
|
|
|
|
int read;
|
|
|
|
|
|
|
|
while ((read = in.read(buffer)) != -1) {
|
|
|
|
bout.write(buffer, 0, read);
|
|
|
|
}
|
2013-07-19 00:42:45 +00:00
|
|
|
|
2014-11-12 19:15:05 +00:00
|
|
|
in.close();
|
|
|
|
|
2014-12-12 09:03:24 +00:00
|
|
|
return bout.toByteArray();
|
2014-11-12 19:15:05 +00:00
|
|
|
}
|
|
|
|
|
2014-12-12 09:03:24 +00:00
|
|
|
public static String readFullyAsString(InputStream in) throws IOException {
|
|
|
|
return new String(readFully(in));
|
|
|
|
}
|
|
|
|
|
|
|
|
public static long copy(InputStream in, OutputStream out) throws IOException {
|
2014-11-12 19:15:05 +00:00
|
|
|
byte[] buffer = new byte[4096];
|
2013-07-19 00:42:45 +00:00
|
|
|
int read;
|
2014-12-12 09:03:24 +00:00
|
|
|
long total = 0;
|
2013-07-19 00:42:45 +00:00
|
|
|
|
|
|
|
while ((read = in.read(buffer)) != -1) {
|
2014-11-12 19:15:05 +00:00
|
|
|
out.write(buffer, 0, read);
|
2014-12-12 09:03:24 +00:00
|
|
|
total += read;
|
2013-07-19 00:42:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
in.close();
|
2014-11-12 19:15:05 +00:00
|
|
|
out.close();
|
2014-12-12 09:03:24 +00:00
|
|
|
|
|
|
|
return total;
|
2014-11-12 19:15:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public static String getDeviceE164Number(Context context) {
|
|
|
|
String localNumber = ((TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE))
|
|
|
|
.getLine1Number();
|
|
|
|
|
|
|
|
if (!TextUtils.isEmpty(localNumber) && !localNumber.startsWith("+"))
|
|
|
|
{
|
|
|
|
if (localNumber.length() == 10) localNumber = "+1" + localNumber;
|
|
|
|
else localNumber = "+" + localNumber;
|
|
|
|
|
|
|
|
return localNumber;
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static List<String> split(String source, String delimiter) {
|
|
|
|
List<String> results = new LinkedList<>();
|
|
|
|
|
|
|
|
if (TextUtils.isEmpty(source)) {
|
|
|
|
return results;
|
|
|
|
}
|
|
|
|
|
|
|
|
String[] elements = source.split(delimiter);
|
|
|
|
Collections.addAll(results, elements);
|
|
|
|
|
|
|
|
return results;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static byte[][] split(byte[] input, int firstLength, int secondLength) {
|
|
|
|
byte[][] parts = new byte[2][];
|
|
|
|
|
|
|
|
parts[0] = new byte[firstLength];
|
|
|
|
System.arraycopy(input, 0, parts[0], 0, firstLength);
|
|
|
|
|
|
|
|
parts[1] = new byte[secondLength];
|
|
|
|
System.arraycopy(input, firstLength, parts[1], 0, secondLength);
|
|
|
|
|
|
|
|
return parts;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static byte[] combine(byte[]... elements) {
|
|
|
|
try {
|
|
|
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
|
|
|
|
|
|
for (byte[] element : elements) {
|
|
|
|
baos.write(element);
|
|
|
|
}
|
|
|
|
|
|
|
|
return baos.toByteArray();
|
|
|
|
} catch (IOException e) {
|
|
|
|
throw new AssertionError(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static byte[] trim(byte[] input, int length) {
|
|
|
|
byte[] result = new byte[length];
|
|
|
|
System.arraycopy(input, 0, result, 0, result.length);
|
|
|
|
|
|
|
|
return result;
|
2013-07-19 00:42:45 +00:00
|
|
|
}
|
2013-03-26 04:26:03 +00:00
|
|
|
|
2014-01-11 11:34:11 +00:00
|
|
|
@SuppressLint("NewApi")
|
2013-11-11 21:06:58 +00:00
|
|
|
public static boolean isDefaultSmsProvider(Context context){
|
|
|
|
return (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) ||
|
2013-12-03 07:06:16 +00:00
|
|
|
(context.getPackageName().equals(Telephony.Sms.getDefaultSmsPackage(context)));
|
2013-11-11 21:06:58 +00:00
|
|
|
}
|
|
|
|
|
2014-07-23 22:40:45 +00:00
|
|
|
public static int getCurrentApkReleaseVersion(Context context) {
|
|
|
|
try {
|
|
|
|
return context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionCode;
|
|
|
|
} catch (PackageManager.NameNotFoundException e) {
|
|
|
|
throw new AssertionError(e);
|
|
|
|
}
|
|
|
|
}
|
2014-11-12 19:15:05 +00:00
|
|
|
|
|
|
|
public static String getSecret(int size) {
|
|
|
|
byte[] secret = getSecretBytes(size);
|
|
|
|
return Base64.encodeBytes(secret);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static byte[] getSecretBytes(int size) {
|
|
|
|
byte[] secret = new byte[size];
|
|
|
|
getSecureRandom().nextBytes(secret);
|
|
|
|
return secret;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static SecureRandom getSecureRandom() {
|
|
|
|
try {
|
|
|
|
return SecureRandom.getInstance("SHA1PRNG");
|
|
|
|
} catch (NoSuchAlgorithmException e) {
|
|
|
|
throw new AssertionError(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* source: http://stackoverflow.com/a/9500334
|
|
|
|
*/
|
|
|
|
public static void fixBackgroundRepeat(Drawable bg) {
|
|
|
|
if (bg != null) {
|
|
|
|
if (bg instanceof BitmapDrawable) {
|
|
|
|
BitmapDrawable bmp = (BitmapDrawable) bg;
|
|
|
|
bmp.mutate();
|
|
|
|
bmp.setTileModeXY(Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2011-12-20 18:20:44 +00:00
|
|
|
}
|