/*
This file is part of Subsonic.
Subsonic 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.
Subsonic 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.
You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2009 (C) Sindre Mehus
*/
package github.madmarty.madsonic.util;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
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.io.UnsupportedEncodingException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.media.AudioManager;
import android.media.AudioManager.OnAudioFocusChangeListener;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.Environment;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.support.v4.app.NotificationCompat;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Gravity;
import android.view.ViewGroup;
import android.view.KeyEvent;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.RemoteViews;
import android.widget.TextView;
import android.widget.Toast;
import github.madmarty.madsonic.R;
import github.madmarty.madsonic.activity.DownloadActivity;
import github.madmarty.madsonic.activity.SubsonicTabActivity;
import github.madmarty.madsonic.domain.MusicDirectory;
import github.madmarty.madsonic.domain.MusicDirectory.Entry;
import github.madmarty.madsonic.domain.PlayerState;
import github.madmarty.madsonic.domain.RepeatMode;
import github.madmarty.madsonic.domain.SearchResult;
import github.madmarty.madsonic.domain.Version;
import github.madmarty.madsonic.provider.MadsonicWidgetProvider;
import github.madmarty.madsonic.receiver.MediaButtonIntentReceiver;
import github.madmarty.madsonic.service.DownloadService;
import github.madmarty.madsonic.service.DownloadServiceImpl;
import github.madmarty.madsonic.service.MusicService;
import github.madmarty.madsonic.service.MusicServiceFactory;
import github.madmarty.madsonic.service.OfflineException;
import github.madmarty.madsonic.service.ServerTooOldException;
import org.apache.http.HttpEntity;
/**
* @author Sindre Mehus
* @version $Id$
*/
public final class Util {
private static final Logger LOG = new Logger(Util.class);
private static final DecimalFormat GIGA_BYTE_FORMAT = new DecimalFormat("0.00 GB");
private static final DecimalFormat MEGA_BYTE_FORMAT = new DecimalFormat("0.00 MB");
private static final DecimalFormat KILO_BYTE_FORMAT = new DecimalFormat("0 KB");
private static DecimalFormat GIGA_BYTE_LOCALIZED_FORMAT = null;
private static DecimalFormat MEGA_BYTE_LOCALIZED_FORMAT = null;
private static DecimalFormat KILO_BYTE_LOCALIZED_FORMAT = null;
private static DecimalFormat BYTE_LOCALIZED_FORMAT = null;
public static final String EVENT_META_CHANGED = "github.madmarty.madsonic.EVENT_META_CHANGED";
public static final String EVENT_PLAYSTATE_CHANGED = "github.madmarty.madsonic.EVENT_PLAYSTATE_CHANGED";
public static final String AVRCP_PLAYSTATE_CHANGED = "com.android.music.playstatechanged";
public static final String AVRCP_METADATA_CHANGED = "com.android.music.metachanged";
private static boolean hasFocus = false;
private static boolean pauseFocus = false;
private static boolean lowerFocus = false;
private static final Map<Integer, Version> SERVER_REST_VERSIONS = new ConcurrentHashMap<Integer, Version>();
// Used by hexEncode()
private static final char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
private final static Pair<Integer, Integer> NOTIFICATION_TEXT_COLORS = new Pair<Integer, Integer>();
private static Toast toast;
private Util() {
}
public static boolean isOffline(Context context) {
if (context == null)
return false;
else
return getActiveServer(context) == 0;
}
public static boolean isScreenLitOnDownload(Context context) {
SharedPreferences prefs = getPreferences(context);
return prefs.getBoolean(Constants.PREFERENCES_KEY_SCREEN_LIT_ON_DOWNLOAD, false);
}
public static RepeatMode getRepeatMode(Context context) {
SharedPreferences prefs = getPreferences(context);
return RepeatMode.valueOf(prefs.getString(Constants.PREFERENCES_KEY_REPEAT_MODE, RepeatMode.OFF.name()));
}
public static void setRepeatMode(Context context, RepeatMode repeatMode) {
SharedPreferences prefs = getPreferences(context);
SharedPreferences.Editor editor = prefs.edit();
editor.putString(Constants.PREFERENCES_KEY_REPEAT_MODE, repeatMode.name());
editor.commit();
}
public static boolean isScrobblingEnabled(Context context) {
if (isOffline(context)) {
return false;
}
SharedPreferences prefs = getPreferences(context);
return prefs.getBoolean(Constants.PREFERENCES_KEY_SCROBBLE, false);
}
public static void setActiveServer(Context context, int instance) {
SharedPreferences prefs = getPreferences(context);
SharedPreferences.Editor editor = prefs.edit();
editor.putInt(Constants.PREFERENCES_KEY_SERVER_INSTANCE, instance);
editor.commit();
}
public static int getActiveServer(Context context) {
SharedPreferences prefs = getPreferences(context);
return prefs.getInt(Constants.PREFERENCES_KEY_SERVER_INSTANCE, 1);
}
public static int getActiveServers(Context context) {
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context);
return settings.getInt(Constants.PREFERENCES_KEY_ACTIVE_SERVERS, 0);
}
public static boolean getServerEnabled(Context context, int instance) {
if (instance == 0) {
return true;
}
SharedPreferences prefs = getPreferences(context);
return prefs.getBoolean(Constants.PREFERENCES_KEY_SERVER_ENABLED + instance, true);
}
public static boolean isStreamProxyEnabled(Context context) {
SharedPreferences prefs = getPreferences(context);
return prefs.getBoolean(Constants.PREFERENCES_KEY_USE_STREAM_PROXY, true);
}
public static void removeInstanceName(Context context, int instance) {
SharedPreferences prefs = getPreferences(context);
SharedPreferences.Editor editor = prefs.edit();
editor.putString(Constants.PREFERENCES_KEY_SERVER + instance, null);
editor.putString(Constants.PREFERENCES_KEY_SERVER_NAME + instance, null);
editor.putString(Constants.PREFERENCES_KEY_SERVER_URL + instance, null);
editor.putString(Constants.PREFERENCES_KEY_USERNAME + instance, null);
editor.putString(Constants.PREFERENCES_KEY_PASSWORD + instance, null);
editor.putBoolean(Constants.PREFERENCES_KEY_SERVER_ENABLED + instance, true);
editor.commit();
}
public static void removeInstanceName(Context context, int instance, int activeInstance) {
SharedPreferences prefs = getPreferences(context);
SharedPreferences.Editor editor = prefs.edit();
int newInstance = instance + 1;
String server = prefs.getString(Constants.PREFERENCES_KEY_SERVER + newInstance, null);
String serverName = prefs.getString(Constants.PREFERENCES_KEY_SERVER_NAME + newInstance, null);
String serverUrl = prefs.getString(Constants.PREFERENCES_KEY_SERVER_URL + newInstance, null);
String userName = prefs.getString(Constants.PREFERENCES_KEY_USERNAME + newInstance, null);
String password = prefs.getString(Constants.PREFERENCES_KEY_PASSWORD + newInstance, null);
boolean serverEnabled = prefs.getBoolean(Constants.PREFERENCES_KEY_SERVER_ENABLED + newInstance, true);
editor.putString(Constants.PREFERENCES_KEY_SERVER + instance, server);
editor.putString(Constants.PREFERENCES_KEY_SERVER_NAME + instance, serverName);
editor.putString(Constants.PREFERENCES_KEY_SERVER_URL + instance, serverUrl);
editor.putString(Constants.PREFERENCES_KEY_USERNAME + instance, userName);
editor.putString(Constants.PREFERENCES_KEY_PASSWORD + instance, password);
editor.putBoolean(Constants.PREFERENCES_KEY_SERVER_ENABLED + instance, serverEnabled);
editor.putString(Constants.PREFERENCES_KEY_SERVER + newInstance, null);
editor.putString(Constants.PREFERENCES_KEY_SERVER_NAME + newInstance, null);
editor.putString(Constants.PREFERENCES_KEY_SERVER_URL + newInstance, null);
editor.putString(Constants.PREFERENCES_KEY_USERNAME + newInstance, null);
editor.putString(Constants.PREFERENCES_KEY_PASSWORD + newInstance, null);
editor.putBoolean(Constants.PREFERENCES_KEY_SERVER_ENABLED + newInstance, true);
editor.commit();
if (instance == activeInstance) {
Util.setActiveServer(context, 0);
}
if (newInstance == activeInstance) {
Util.setActiveServer(context, instance);
}
}
public static String getServerName(Context context) {
SharedPreferences prefs = getPreferences(context);
int instance = prefs.getInt(Constants.PREFERENCES_KEY_SERVER_INSTANCE, 1);
return prefs.getString(Constants.PREFERENCES_KEY_SERVER_NAME + instance, null);
}
// public static String getServerName(Context context, int instance) {
// SharedPreferences prefs = getPreferences(context);
// return prefs.getString(Constants.PREFERENCES_KEY_SERVER_NAME + instance, null);
// }
public static String getServerName(Context context, int instance) {
if (instance == 0) {
return context.getResources().getString(R.string.main_offline);
}
SharedPreferences prefs = getPreferences(context);
return prefs.getString(Constants.PREFERENCES_KEY_SERVER_NAME + instance, null);
}
public static String getUserName(Context context, int instance) {
if (instance == 0) {
return context.getResources().getString(R.string.main_offline);
}
SharedPreferences prefs = getPreferences(context);
return prefs.getString(Constants.PREFERENCES_KEY_USERNAME + instance, null);
}
// public static void setServerRestVersion(Context context, Version version) {
// SERVER_REST_VERSIONS.put(getActiveServer(context), version);
// }
//
// public static Version getServerRestVersion(Context context) {
// return SERVER_REST_VERSIONS.get(getActiveServer(context));
// }
public static void setServerRestVersion(Context context, Version version) {
int instance = getActiveServer(context);
Version current = SERVER_REST_VERSIONS.get(instance);
if(current != version) {
SERVER_REST_VERSIONS.put(instance, version);
SharedPreferences.Editor editor = getPreferences(context).edit();
editor.putString(Constants.PREFERENCES_KEY_SERVER_VERSION + instance, version.getVersion());
editor.commit();
}
}
public static Version getServerRestVersion(Context context) {
int instance = getActiveServer(context);
Version version = SERVER_REST_VERSIONS.get(instance);
if(version == null) {
SharedPreferences prefs = getPreferences(context);
String versionString = prefs.getString(Constants.PREFERENCES_KEY_SERVER_VERSION + instance, null);
if(versionString != null && versionString != "") {
version = new Version(versionString);
SERVER_REST_VERSIONS.put(instance, version);
}
}
return version;
}
public static void setSelectedMusicFolderId(Context context, String musicFolderId) {
int instance = getActiveServer(context);
SharedPreferences prefs = getPreferences(context);
SharedPreferences.Editor editor = prefs.edit();
editor.putString(Constants.PREFERENCES_KEY_MUSIC_FOLDER_ID + instance, musicFolderId);
editor.commit();
}
public static String getSelectedMusicFolderId(Context context) {
SharedPreferences prefs = getPreferences(context);
int instance = getActiveServer(context);
return prefs.getString(Constants.PREFERENCES_KEY_MUSIC_FOLDER_ID + instance, null);
}
public static String getTheme(Context context) {
SharedPreferences prefs = getPreferences(context);
return prefs.getString(Constants.PREFERENCES_KEY_THEME, "Madsonic Dark");
}
public static int getCoverSize(Context context) {
SharedPreferences prefs = getPreferences(context);
int coverSize = Integer.parseInt(prefs.getString(Constants.PREFERENCES_KEY_COVER_SIZE, "128"));
return coverSize;
}
public static int getMaxBitrate(Context context) {
ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = manager.getActiveNetworkInfo();
if (networkInfo == null) {
return 0;
}
boolean wifi = networkInfo.getType() == ConnectivityManager.TYPE_WIFI;
SharedPreferences prefs = getPreferences(context);
return Integer.parseInt(prefs.getString(wifi ? Constants.PREFERENCES_KEY_MAX_BITRATE_WIFI : Constants.PREFERENCES_KEY_MAX_BITRATE_MOBILE, "0"));
}
public static int getMaxVideoBitrate(Context context) {
ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = manager.getActiveNetworkInfo();
if (networkInfo == null) {
return 0;
}
boolean wifi = networkInfo.getType() == ConnectivityManager.TYPE_WIFI;
SharedPreferences prefs = getPreferences(context);
return Integer.parseInt(prefs.getString(wifi ? Constants.PREFERENCES_KEY_MAX_VIDEO_BITRATE_WIFI : Constants.PREFERENCES_KEY_MAX_VIDEO_BITRATE_MOBILE, "0"));
}
public static boolean shouldDisplayBitrateWithArtist(Context context) {
SharedPreferences prefs = getPreferences(context);
return prefs.getBoolean(Constants.PREFERENCES_KEY_DISPLAY_BITRATE_WITH_ARTIST, true);
}
public static int getDefaultVideoplayer(Context context) {
SharedPreferences prefs = getPreferences(context);
return Integer.parseInt(prefs.getString(Constants.PREFERENCES_KEY_DEFAULT_VIDEOPLAYER, "1"));
}
public static int getPreloadCount(Context context) {
SharedPreferences prefs = getPreferences(context);
int preloadCount = Integer.parseInt(prefs.getString(Constants.PREFERENCES_KEY_PRELOAD_COUNT, "-1"));
return preloadCount == -1 ? Integer.MAX_VALUE : preloadCount;
}
public static VideoPlayerType getVideoPlayerType(Context context) {
SharedPreferences prefs = getPreferences(context);
return VideoPlayerType.forKey(prefs.getString(Constants.PREFERENCES_KEY_VIDEO_PLAYER, VideoPlayerType.MX.getKey()));
}
public static int getCacheSizeMB(Context context) {
SharedPreferences prefs = getPreferences(context);
int cacheSize = Integer.parseInt(prefs.getString(Constants.PREFERENCES_KEY_CACHE_SIZE, "-1"));
return cacheSize == -1 ? Integer.MAX_VALUE : cacheSize;
}
public static String getRestUrl(Context context, String method) {
StringBuilder builder = new StringBuilder();
SharedPreferences prefs = getPreferences(context);
int instance = prefs.getInt(Constants.PREFERENCES_KEY_SERVER_INSTANCE, 1);
return getRestUrl(context, method, prefs, instance);
}
public static String getRestUrl(Context context, String method, int instance) {
SharedPreferences prefs = getPreferences(context);
return getRestUrl(context, method, prefs, instance);
}
public static String getRestUrl(Context context, String method, SharedPreferences prefs, int instance) {
StringBuilder builder = new StringBuilder();
String serverUrl = prefs.getString(Constants.PREFERENCES_KEY_SERVER_URL + instance, null);
String username = prefs.getString(Constants.PREFERENCES_KEY_USERNAME + instance, null);
String password = prefs.getString(Constants.PREFERENCES_KEY_PASSWORD + instance, null);
// Slightly obfuscate password
password = "enc:" + Util.utf8HexEncode(password);
builder.append(serverUrl);
if (builder.charAt(builder.length() - 1) != '/') {
builder.append("/");
}
builder.append("rest/").append(method).append(".view");
builder.append("?u=").append(username);
builder.append("&p=").append(password);
builder.append("&v=").append(Constants.REST_PROTOCOL_VERSION);
builder.append("&c=").append(Constants.REST_CLIENT_ID);
return builder.toString();
}
public static SharedPreferences getPreferences(Context context) {
return context.getSharedPreferences(Constants.PREFERENCES_FILE_NAME, 0);
}
public static String getContentType(HttpEntity entity) {
if (entity == null || entity.getContentType() == null) {
return null;
}
return entity.getContentType().getValue();
}
/**
* Get the contents of an <code>InputStream</code> as a <code>byte[]</code>.
* <p/>
* This method buffers the input internally, so there is no need to use a
* <code>BufferedInputStream</code>.
*
* @param input the <code>InputStream</code> to read from
* @return the requested byte array
* @throws NullPointerException if the input is null
* @throws IOException if an I/O error occurs
*/
public static byte[] toByteArray(InputStream input) throws IOException {
ByteArrayOutputStream output = new ByteArrayOutputStream();
copy(input, output);
return output.toByteArray();
}
public static long copy(InputStream input, OutputStream output)
throws IOException {
byte[] buffer = new byte[1024 * 4];
long count = 0;
int n;
while (-1 != (n = input.read(buffer))) {
output.write(buffer, 0, n);
count += n;
}
return count;
}
public static void atomicCopy(File from, File to) throws IOException {
FileInputStream in = null;
FileOutputStream out = null;
File tmp = null;
try {
tmp = new File(to.getPath() + ".tmp");
in = new FileInputStream(from);
out = new FileOutputStream(tmp);
in.getChannel().transferTo(0, from.length(), out.getChannel());
out.close();
if (!tmp.renameTo(to)) {
throw new IOException("Failed to rename " + tmp + " to " + to);
}
LOG.info("Copied " + from + " to " + to);
} catch (IOException x) {
close(out);
delete(to);
throw x;
} finally {
close(in);
close(out);
delete(tmp);
}
}
public static void renameFile(File from, File to) throws IOException {
if(from.renameTo(to)) {
LOG.info( "Renamed " + from + " to " + to);
} else {
atomicCopy(from, to);
}
}
public static void close(Closeable closeable) {
try {
if (closeable != null) {
closeable.close();
}
} catch (Throwable x) {
// Ignored
}
}
public static boolean delete(File file) {
if (file != null && file.exists()) {
if (!file.delete()) {
LOG.warn("Failed to delete file " + file);
return false;
}
LOG.info("Deleted file " + file);
}
return true;
}
public static boolean recursiveDelete(File dir) {
if (dir != null && dir.exists()) {
for(File file: dir.listFiles()) {
if(file.isDirectory()) {
if(!recursiveDelete(file)) {
return false;
}
} else if(file.exists()) {
if(!file.delete()) {
return false;
}
}
}
return dir.delete();
}
return false;
}
public static void toast(Context context, int messageId) {
toast(context, messageId, true);
}
public static void toast(Context context, int messageId, boolean shortDuration, Object... formatArgs) {
toast(context, context.getString(messageId, formatArgs), shortDuration);
}
public static void toast(Context context, String message) {
toast(context, message, true);
}
public static void toast(Context context, String message, boolean shortDuration) {
if (toast == null) {
toast = Toast.makeText(context, message, shortDuration ? Toast.LENGTH_SHORT : Toast.LENGTH_LONG);
toast.setGravity(Gravity.CENTER, 0, 0);
} else {
toast.setText(message);
toast.setDuration(shortDuration ? Toast.LENGTH_SHORT : Toast.LENGTH_LONG);
}
toast.show();
}
/**
* Converts a byte-count to a formatted string suitable for display to the user.
* For instance:
* <ul>
* <li><code>format(918)</code> returns <em>"918 B"</em>.</li>
* <li><code>format(98765)</code> returns <em>"96 KB"</em>.</li>
* <li><code>format(1238476)</code> returns <em>"1.2 MB"</em>.</li>
* </ul>
* This method assumes that 1 KB is 1024 bytes.
* To get a localized string, please use formatLocalizedBytes instead.
*
* @param byteCount The number of bytes.
* @return The formatted string.
*/
public static synchronized String formatBytes(long byteCount) {
// More than 1 GB?
if (byteCount >= 1024 * 1024 * 1024) {
NumberFormat gigaByteFormat = GIGA_BYTE_FORMAT;
return gigaByteFormat.format((double) byteCount / (1024 * 1024 * 1024));
}
// More than 1 MB?
if (byteCount >= 1024 * 1024) {
NumberFormat megaByteFormat = MEGA_BYTE_FORMAT;
return megaByteFormat.format((double) byteCount / (1024 * 1024));
}
// More than 1 KB?
if (byteCount >= 1024) {
NumberFormat kiloByteFormat = KILO_BYTE_FORMAT;
return kiloByteFormat.format((double) byteCount / 1024);
}
return byteCount + " B";
}
/**
* Converts a byte-count to a formatted string suitable for display to the user.
* For instance:
* <ul>
* <li><code>format(918)</code> returns <em>"918 B"</em>.</li>
* <li><code>format(98765)</code> returns <em>"96 KB"</em>.</li>
* <li><code>format(1238476)</code> returns <em>"1.2 MB"</em>.</li>
* </ul>
* This method assumes that 1 KB is 1024 bytes.
* This version of the method returns a localized string.
*
* @param byteCount The number of bytes.
* @return The formatted string.
*/
public static synchronized String formatLocalizedBytes(long byteCount, Context context) {
// More than 1 GB?
if (byteCount >= 1024 * 1024 * 1024) {
if (GIGA_BYTE_LOCALIZED_FORMAT == null) {
GIGA_BYTE_LOCALIZED_FORMAT = new DecimalFormat(context.getResources().getString(R.string.util_bytes_format_gigabyte));
}
return GIGA_BYTE_LOCALIZED_FORMAT.format((double) byteCount / (1024 * 1024 * 1024));
}
// More than 1 MB?
if (byteCount >= 1024 * 1024) {
if (MEGA_BYTE_LOCALIZED_FORMAT == null) {
MEGA_BYTE_LOCALIZED_FORMAT = new DecimalFormat(context.getResources().getString(R.string.util_bytes_format_megabyte));
}
return MEGA_BYTE_LOCALIZED_FORMAT.format((double) byteCount / (1024 * 1024));
}
// More than 1 KB?
if (byteCount >= 1024) {
if (KILO_BYTE_LOCALIZED_FORMAT == null) {
KILO_BYTE_LOCALIZED_FORMAT = new DecimalFormat(context.getResources().getString(R.string.util_bytes_format_kilobyte));
}
return KILO_BYTE_LOCALIZED_FORMAT.format((double) byteCount / 1024);
}
if (BYTE_LOCALIZED_FORMAT == null) {
BYTE_LOCALIZED_FORMAT = new DecimalFormat(context.getResources().getString(R.string.util_bytes_format_byte));
}
return BYTE_LOCALIZED_FORMAT.format((double) byteCount);
}
public static String formatDuration(Integer seconds) {
if (seconds == null) {
return null;
}
int hours = seconds / 3600;
int minutes = (seconds / 60) % 60;
int secs = seconds % 60;
StringBuilder builder = new StringBuilder(7);
if(hours > 0) {
builder.append(hours).append(":");
if(minutes < 10) {
builder.append("0");
}
}
builder.append(minutes).append(":");
if (secs < 10) {
builder.append("0");
}
builder.append(secs);
return builder.toString();
}
public static boolean equals(Object object1, Object object2) {
if (object1 == object2) {
return true;
}
if (object1 == null || object2 == null) {
return false;
}
return object1.equals(object2);
}
/**
* Encodes the given string by using the hexadecimal representation of its UTF-8 bytes.
*
* @param s The string to encode.
* @return The encoded string.
*/
public static String utf8HexEncode(String s) {
if (s == null) {
return null;
}
byte[] utf8;
try {
utf8 = s.getBytes(Constants.UTF_8);
} catch (UnsupportedEncodingException x) {
throw new RuntimeException(x);
}
return hexEncode(utf8);
}
/**
* Converts an array of bytes into an array of characters representing the hexadecimal values of each byte in order.
* The returned array will be double the length of the passed array, as it takes two characters to represent any
* given byte.
*
* @param data Bytes to convert to hexadecimal characters.
* @return A string containing hexadecimal characters.
*/
public static String hexEncode(byte[] data) {
int length = data.length;
char[] out = new char[length << 1];
// two characters form the hex value.
for (int i = 0, j = 0; i < length; i++) {
out[j++] = HEX_DIGITS[(0xF0 & data[i]) >>> 4];
out[j++] = HEX_DIGITS[0x0F & data[i]];
}
return new String(out);
}
/**
* Calculates the MD5 digest and returns the value as a 32 character hex string.
*
* @param s Data to digest.
* @return MD5 digest as a hex string.
*/
public static String md5Hex(String s) {
if (s == null) {
return null;
}
try {
MessageDigest md5 = MessageDigest.getInstance("MD5");
return hexEncode(md5.digest(s.getBytes(Constants.UTF_8)));
} catch (Exception x) {
throw new RuntimeException(x.getMessage(), x);
}
}
public static String decrypt(String s) {
if (s == null) {
return null;
}
if (!s.startsWith("enc:")) {
return s;
}
try {
//return utf8HexDecode(s.substring(4));
return hexToString(s.substring(4));
} catch (Exception e) {
return s;
}
}
public static String hexToString(final String str) {
return new String(new BigInteger(str, 16).toByteArray());
}
// public static String utf8HexDecode(String s) throws Exception {
// if (s == null) {
// return null;
// }
// return new String(Hex.decodeHex(s.toCharArray()), ENCODING_UTF8);
// }
public static boolean isNetworkConnected(Context context) {
ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = manager.getActiveNetworkInfo();
boolean connected = networkInfo != null && networkInfo.isConnected();
boolean wifiConnected = connected && networkInfo.getType() == ConnectivityManager.TYPE_WIFI;
boolean wifiRequired = isWifiRequiredForDownload(context);
return connected && (!wifiRequired || wifiConnected);
}
public static boolean isExternalStoragePresent() {
return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());
}
private static boolean isWifiRequiredForDownload(Context context) {
SharedPreferences prefs = getPreferences(context);
return prefs.getBoolean(Constants.PREFERENCES_KEY_WIFI_REQUIRED_FOR_DOWNLOAD, false);
}
public static void info(Context context, int titleId, int messageId) {
showDialog(context, android.R.drawable.ic_dialog_info, titleId, messageId);
}
public static void info(Context context, int titleId, String message) {
showDialog(context, android.R.drawable.ic_dialog_info, titleId, message);
}
private static void showDialog(Context context, int icon, int titleId, int messageId) {
new AlertDialog.Builder(context)
.setIcon(icon)
.setTitle(titleId)
.setMessage(messageId)
.setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int i) {
dialog.dismiss();
}
})
.show();
}
private static void showDialog(Context context, int icon, int titleId, String message) {
new AlertDialog.Builder(context)
.setIcon(icon)
.setTitle(titleId)
.setMessage(message)
.setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int i) {
dialog.dismiss();
}
})
.show();
}
private static void setupViews(RemoteViews rv, Context context, MusicDirectory.Entry song, boolean playing){
// Use the same text for the ticker and the expanded notification
String title = song.getTitle();
String arist = song.getArtist();
String album = song.getAlbum();
// Set the album art.
try {
int size = context.getResources().getDrawable(R.drawable.unknown_album).getIntrinsicHeight();
Bitmap bitmap = FileUtil.getAlbumArtBitmap(context, song, size);
if (bitmap == null) {
// set default album art
rv.setImageViewResource(R.id.notification_image, R.drawable.unknown_album);
} else {
rv.setImageViewBitmap(R.id.notification_image, bitmap);
}
} catch (Exception x) {
LOG.warn( "Failed to get notification cover art", x);
rv.setImageViewResource(R.id.notification_image, R.drawable.unknown_album);
}
rv.setImageViewResource(R.id.control_starred, song.isStarred() ? android.R.drawable.btn_star_big_on : android.R.drawable.btn_star_big_off);
// set the text for the notifications
rv.setTextViewText(R.id.notification_title, title);
rv.setTextViewText(R.id.notification_artist, arist);
rv.setTextViewText(R.id.notification_album, album);
Pair<Integer, Integer> colors = getNotificationTextColors(context);
if (colors.getFirst() != null) {
rv.setTextColor(R.id.notification_title, colors.getFirst());
}
if (colors.getSecond() != null) {
rv.setTextColor(R.id.notification_artist, colors.getSecond());
}
if(!playing) {
rv.setImageViewResource(R.id.control_pause, R.drawable.notification_play);
rv.setImageViewResource(R.id.control_previous, R.drawable.notification_stop);
}
// Create actions for media buttons
PendingIntent pendingIntent;
if(playing) {
Intent prevIntent = new Intent("KEYCODE_MEDIA_PREVIOUS");
prevIntent.setComponent(new ComponentName(context, DownloadServiceImpl.class));
prevIntent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_PREVIOUS));
pendingIntent = PendingIntent.getService(context, 0, prevIntent, 0);
rv.setOnClickPendingIntent(R.id.control_previous, pendingIntent);
} else {
Intent prevIntent = new Intent("KEYCODE_MEDIA_STOP");
prevIntent.setComponent(new ComponentName(context, DownloadServiceImpl.class));
prevIntent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_STOP));
pendingIntent = PendingIntent.getService(context, 0, prevIntent, 0);
rv.setOnClickPendingIntent(R.id.control_previous, pendingIntent);
}
Intent starredIntent = new Intent("KEYCODE_MEDIA_STARRED");
starredIntent.setComponent(new ComponentName(context, DownloadServiceImpl.class));
starredIntent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_STAR));
pendingIntent = PendingIntent.getService(context, 0, starredIntent, 0);
rv.setOnClickPendingIntent(R.id.control_starred, pendingIntent);
Intent pauseIntent = new Intent("KEYCODE_MEDIA_PLAY_PAUSE");
pauseIntent.setComponent(new ComponentName(context, DownloadServiceImpl.class));
pauseIntent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE));
pendingIntent = PendingIntent.getService(context, 0, pauseIntent, 0);
rv.setOnClickPendingIntent(R.id.control_pause, pendingIntent);
Intent nextIntent = new Intent("KEYCODE_MEDIA_NEXT");
nextIntent.setComponent(new ComponentName(context, DownloadServiceImpl.class));
nextIntent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_NEXT));
pendingIntent = PendingIntent.getService(context, 0, nextIntent, 0);
rv.setOnClickPendingIntent(R.id.control_next, pendingIntent);
}
private static boolean useSimpleNotification() {
return Build.VERSION.SDK_INT < 11;
}
private static Notification createSimpleNotification(Context context, MusicDirectory.Entry song) {
Bitmap albumArt;
try {
albumArt = FileUtil.getAlbumArtBitmap(context, song, (int) Util.convertDpToPixel(64.0F, context));
if (albumArt == null) {
albumArt = Util.decodeBitmap(context, R.drawable.unknown_album);
}
} catch (Exception x) {
LOG.warn("Failed to get notification cover art", x);
albumArt = Util.decodeBitmap(context, R.drawable.unknown_album);
}
Intent notificationIntent = new Intent(context, DownloadActivity.class);
return new NotificationCompat.Builder(context).setOngoing(true)
.setSmallIcon(R.drawable.stat_notify_playing)
.setContentTitle(song.getTitle())
.setContentText(song.getArtist())
.setContentIntent(PendingIntent.getActivity(context, 0, notificationIntent, 0))
.setLargeIcon(albumArt)
.build();
}
private static Notification createCustomNotification(Context context, MusicDirectory.Entry song, boolean playing) {
Bitmap albumArt;
// try {
// albumArt = FileUtil.getUnscaledAlbumArtBitmap(context, song);
// if (albumArt == null) {
// albumArt = Util.decodeBitmap(context, R.drawable.unknown_album_large);
// }
// } catch (Exception x) {
// LOG.warn("Failed to get notification cover art", x);
// albumArt = Util.decodeBitmap(context, R.drawable.unknown_album_large);
// }
//
// RemoteViews contentView = new RemoteViews(context.getPackageName(), R.layout.notification);
// contentView.setTextViewText(R.id.notification_title, song.getTitle());
// contentView.setTextViewText(R.id.notification_artist, song.getArtist());
// contentView.setImageViewBitmap(R.id.notification_image, albumArt);
// contentView.setImageViewResource(R.id.notification_playpause, playing ? R.drawable.media_pause : R.drawable.media_start);
//
// Intent intent = new Intent("1");
// intent.setComponent(new ComponentName(context, DownloadServiceImpl.class));
// intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE));
// contentView.setOnClickPendingIntent(R.id.notification_playpause, PendingIntent.getService(context, 0, intent, 0));
//
// intent = new Intent("2");
// intent.setComponent(new ComponentName(context, DownloadServiceImpl.class));
// intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_NEXT));
// contentView.setOnClickPendingIntent(R.id.notification_next, PendingIntent.getService(context, 0, intent, 0));
//
// intent = new Intent("4");
// intent.setComponent(new ComponentName(context, DownloadServiceImpl.class));
// intent.putExtra(Constants.INTENT_EXTRA_NAME_HIDE_NOTIFICATION, true);
// contentView.setOnClickPendingIntent(R.id.notification_close, PendingIntent.getService(context, 0, intent, 0));
Intent notificationIntent = new Intent(context, DownloadActivity.class);
Notification notification = new NotificationCompat.Builder(context)
.setOngoing(true)
.setSmallIcon(R.drawable.stat_notify_playing)
// .setContent(contentView)
.setContentIntent(PendingIntent.getActivity(context, 0, notificationIntent, 0))
.build();
if (Build.VERSION.SDK_INT >= 16) {
// notification.bigContentView = createBigContentView(context, song, albumArt, playing);
}
return notification;
}
public static void showPlayingNotification(final Context context, final DownloadServiceImpl downloadService, Handler handler, MusicDirectory.Entry song) {
// Set the icon, scrolling text and timestamp
final Notification notification = new Notification(R.drawable.stat_notify, song.getTitle(), System.currentTimeMillis());
notification.flags |= Notification.FLAG_NO_CLEAR | Notification.FLAG_ONGOING_EVENT;
boolean playing = downloadService.getPlayerState() == PlayerState.STARTED;
if (Build.VERSION.SDK_INT>= Build.VERSION_CODES.JELLY_BEAN){
RemoteViews expandedContentView = new RemoteViews(context.getPackageName(), R.layout.notification_expanded);
setupViews(expandedContentView,context,song, playing);
notification.bigContentView = expandedContentView;
}
RemoteViews smallContentView = new RemoteViews(context.getPackageName(), R.layout.notification);
setupViews(smallContentView, context, song, playing);
notification.contentView = smallContentView;
Intent notificationIntent = new Intent(context, DownloadActivity.class);
notification.contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
handler.post(new Runnable() {
@Override
public void run() {
downloadService.startForeground(Constants.NOTIFICATION_ID_PLAYING, notification);
}
});
// Update widget
MadsonicWidgetProvider.notifyInstances(context, downloadService, true);
}
public static void updateNotification(final Context context, final DownloadServiceImpl downloadService,
Handler handler, MusicDirectory.Entry song, boolean playing) {
// On older platforms, show a notification without buttons.
if (useSimpleNotification()) {
updateSimpleNotification(context, downloadService, handler, song, playing);
} else {
updateCustomNotification(context, downloadService, handler, song, playing);
}
// Update widget
MadsonicWidgetProvider.notifyInstances(context, downloadService, playing);
}
private static void updateSimpleNotification(Context context, final DownloadServiceImpl downloadService, Handler handler,
MusicDirectory.Entry song, boolean playing) {
if (song == null || !playing) {
hidePlayingNotification(context, downloadService, handler);
} else {
final Notification notification = createSimpleNotification(context, song);
// Send the notification and put the service in the foreground.
handler.post(new Runnable() {
@Override
public void run() {
downloadService.startForeground(Constants.NOTIFICATION_ID_PLAYING, notification);
}
});
}
}
private static void updateCustomNotification(Context context, final DownloadServiceImpl downloadService,
Handler handler, MusicDirectory.Entry song, boolean playing) {
if (song == null) {
hidePlayingNotification(context, downloadService, handler);
// } else if (!isNotificationHiddenByUser(context)) {
final Notification notification = createCustomNotification(context, song, playing);
// Send the notification and put the service in the foreground.
handler.post(new Runnable() {
@Override
public void run() {
downloadService.startForeground(Constants.NOTIFICATION_ID_PLAYING, notification);
}
});
}
}
public static void hidePlayingNotification(final Context context, final DownloadServiceImpl downloadService, Handler handler) {
// Remove notification and remove the service from the foreground
handler.post(new Runnable() {
@Override
public void run() {
downloadService.stopForeground(true);
}
});
// Update widget
MadsonicWidgetProvider.notifyInstances(context, downloadService, false);
}
public static boolean isPackageInstalled(Context context, String packageName) {
PackageManager pm = context.getPackageManager();
List<ApplicationInfo> packages = pm.getInstalledApplications(0);
for (ApplicationInfo packageInfo : packages) {
if (packageInfo.packageName.equals(packageName)) {
return true;
}
}
return false;
}
public static void sleepQuietly(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException x) {
LOG.warn( "Interrupted from sleep.", x);
}
}
public static void startActivityWithoutTransition(Activity currentActivity, Class<? extends Activity> newActivitiy) {
startActivityWithoutTransition(currentActivity, new Intent(currentActivity, newActivitiy));
}
public static void startActivityWithoutTransition(Activity currentActivity, Intent intent) {
currentActivity.startActivity(intent);
disablePendingTransition(currentActivity);
}
public static void disablePendingTransition(Activity activity) {
// Activity.overridePendingTransition() was introduced in Android 2.0. Use reflection to maintain
// compatibility with 1.5.
try {
Method method = Activity.class.getMethod("overridePendingTransition", int.class, int.class);
method.invoke(activity, 0, 0);
} catch (Throwable x) {
// Ignored
}
}
@SuppressWarnings("deprecation")
public static Drawable createDrawableFromBitmap(Context context, Bitmap bitmap) {
// BitmapDrawable(Resources, Bitmap) was introduced in Android 1.6. Use reflection to maintain
// compatibility with 1.5.
try {
Constructor<BitmapDrawable> constructor = BitmapDrawable.class.getConstructor(Resources.class, Bitmap.class);
return constructor.newInstance(context.getResources(), bitmap);
} catch (Throwable x) {
return new BitmapDrawable(bitmap);
}
}
public static void registerMediaButtonEventReceiver(Context context) {
// Only do it if enabled in the settings.
SharedPreferences prefs = getPreferences(context);
boolean enabled = prefs.getBoolean(Constants.PREFERENCES_KEY_MEDIA_BUTTONS, true);
if (enabled) {
// AudioManager.registerMediaButtonEventReceiver() was introduced in Android 2.2.
// Use reflection to maintain compatibility with 1.5.
try {
AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
ComponentName componentName = new ComponentName(context.getPackageName(), MediaButtonIntentReceiver.class.getName());
Method method = AudioManager.class.getMethod("registerMediaButtonEventReceiver", ComponentName.class);
method.invoke(audioManager, componentName);
} catch (Throwable x) {
// Ignored.
}
}
}
public static void unregisterMediaButtonEventReceiver(Context context) {
// AudioManager.unregisterMediaButtonEventReceiver() was introduced in Android 2.2.
// Use reflection to maintain compatibility with 1.5.
try {
AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
ComponentName componentName = new ComponentName(context.getPackageName(), MediaButtonIntentReceiver.class.getName());
Method method = AudioManager.class.getMethod("unregisterMediaButtonEventReceiver", ComponentName.class);
method.invoke(audioManager, componentName);
} catch (Throwable x) {
// Ignored.
}
}
@TargetApi(8)
public static void requestAudioFocus(final Context context) {
if (Build.VERSION.SDK_INT >= 8 && !hasFocus) {
final AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
hasFocus = true;
audioManager.requestAudioFocus(new OnAudioFocusChangeListener() {
public void onAudioFocusChange(int focusChange) {
DownloadServiceImpl downloadService = (DownloadServiceImpl)context;
if((focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT || focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) && !downloadService.isJukeboxEnabled()) {
if(downloadService.getPlayerState() == PlayerState.STARTED) {
SharedPreferences prefs = getPreferences(context);
int lossPref = Integer.parseInt(prefs.getString(Constants.PREFERENCES_KEY_AUDIO_FOCUS, "1"));
if(lossPref == 2 || (lossPref == 1 && focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK)) {
lowerFocus = true;
downloadService.setVolume(0.1f);
} else if(lossPref == 0 || (lossPref == 1 && focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT)) {
pauseFocus = true;
downloadService.pause();
}
}
} else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
if(pauseFocus) {
pauseFocus = false;
downloadService.start();
} else if(lowerFocus) {
lowerFocus = false;
downloadService.setVolume(1.0f);
}
} else if(focusChange == AudioManager.AUDIOFOCUS_LOSS && !downloadService.isJukeboxEnabled()) {
hasFocus = false;
downloadService.pause();
audioManager.abandonAudioFocus(this);
}
}
}, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
}
}
public static MusicDirectory getSongsFromSearchResult(SearchResult searchResult) {
MusicDirectory musicDirectory = new MusicDirectory();
for (Entry entry : searchResult.getSongs()) {
musicDirectory.addChild(entry);
}
return musicDirectory;
}
/**
* <p>Broadcasts the given song info as the new song being played.</p>
*/
public static void broadcastNewTrackInfo(Context context, MusicDirectory.Entry song) {
DownloadService downloadService = (DownloadServiceImpl)context;
Intent intent = new Intent(EVENT_META_CHANGED);
Intent avrcpIntent = new Intent(AVRCP_METADATA_CHANGED);
if (song != null) {
intent.putExtra("title", song.getTitle());
intent.putExtra("artist", song.getArtist());
intent.putExtra("album", song.getAlbum());
File albumArtFile = FileUtil.getAlbumArtFile(context, song);
intent.putExtra("coverart", albumArtFile.getAbsolutePath());
avrcpIntent.putExtra("playing", true);
avrcpIntent.putExtra("track", song.getTitle());
avrcpIntent.putExtra("artist", song.getArtist());
avrcpIntent.putExtra("album", song.getAlbum());
avrcpIntent.putExtra("ListSize",(long) downloadService.getSongs().size());
avrcpIntent.putExtra("id", (long) downloadService.getCurrentPlayingIndex()+1);
avrcpIntent.putExtra("duration", (long) downloadService.getPlayerDuration());
avrcpIntent.putExtra("position", (long) downloadService.getPlayerPosition());
avrcpIntent.putExtra("coverart", albumArtFile.getAbsolutePath());
} else {
intent.putExtra("title", "");
intent.putExtra("artist", "");
intent.putExtra("album", "");
intent.putExtra("coverart", "");
avrcpIntent.putExtra("playing", false);
avrcpIntent.putExtra("track", "");
avrcpIntent.putExtra("artist", "");
avrcpIntent.putExtra("album", "");
avrcpIntent.putExtra("ListSize",(long)0);
avrcpIntent.putExtra("id", (long) 0);
avrcpIntent.putExtra("duration", (long )0);
avrcpIntent.putExtra("position", (long) 0);
avrcpIntent.putExtra("coverart", "");
}
context.sendBroadcast(intent);
context.sendBroadcast(avrcpIntent);
}
/**
* <p>Broadcasts the given player state as the one being set.</p>
*/
public static void broadcastPlaybackStatusChange(Context context, PlayerState state) {
Intent intent = new Intent(EVENT_PLAYSTATE_CHANGED);
Intent avrcpIntent = new Intent(AVRCP_PLAYSTATE_CHANGED);
switch (state) {
case STARTED:
intent.putExtra("state", "play");
avrcpIntent.putExtra("playing", true);
break;
case STOPPED:
intent.putExtra("state", "stop");
avrcpIntent.putExtra("playing", false);
break;
case PAUSED:
intent.putExtra("state", "pause");
avrcpIntent.putExtra("playing", false);
break;
case COMPLETED:
intent.putExtra("state", "complete");
avrcpIntent.putExtra("playing", false);
break;
default:
return; // No need to broadcast.
}
context.sendBroadcast(intent);
context.sendBroadcast(avrcpIntent);
}
/**
* Resolves the default text color for notifications.
*
* Based on http://stackoverflow.com/questions/4867338/custom-notification-layouts-and-text-colors/7320604#7320604
*/
@SuppressWarnings("deprecation")
private static Pair<Integer, Integer> getNotificationTextColors(Context context) {
if (NOTIFICATION_TEXT_COLORS.getFirst() == null && NOTIFICATION_TEXT_COLORS.getSecond() == null) {
try {
Notification notification = new Notification();
String title = "title";
String content = "content";
notification.setLatestEventInfo(context, title, content, null);
LinearLayout group = new LinearLayout(context);
ViewGroup event = (ViewGroup) notification.contentView.apply(context, group);
findNotificationTextColors(event, title, content);
group.removeAllViews();
} catch (Exception x) {
LOG.warn( "Failed to resolve notification text colors.", x);
}
}
return NOTIFICATION_TEXT_COLORS;
}
private static void findNotificationTextColors(ViewGroup group, String title, String content) {
for (int i = 0; i < group.getChildCount(); i++) {
if (group.getChildAt(i) instanceof TextView) {
TextView textView = (TextView) group.getChildAt(i);
String text = textView.getText().toString();
if (title.equals(text)) {
NOTIFICATION_TEXT_COLORS.setFirst(textView.getTextColors().getDefaultColor());
}
else if (content.equals(text)) {
NOTIFICATION_TEXT_COLORS.setSecond(textView.getTextColors().getDefaultColor());
}
}
else if (group.getChildAt(i) instanceof ViewGroup)
findNotificationTextColors((ViewGroup) group.getChildAt(i), title, content);
}
}
public static void changeLanguage(Context context) {
Resources res = context.getResources();
DisplayMetrics dm = res.getDisplayMetrics();
android.content.res.Configuration conf = res.getConfiguration();
SharedPreferences prefs = getPreferences(context);
String appLanguage = prefs.getString(Constants.PREFERENCES_KEY_LANGUAGE, "us");
if ("auto".equalsIgnoreCase(appLanguage)) {
conf.locale = new Locale("en");
res.updateConfiguration(conf, dm);
} else {
conf.locale = new Locale(appLanguage);
res.updateConfiguration(conf, dm);
}
}
public static int getDefaultAlbums(Context context) {
SharedPreferences prefs = getPreferences(context);
return Integer.parseInt(prefs.getString(Constants.PREFERENCES_KEY_DEFAULT_ALBUMS, "5"));
}
public static int getMaxAlbums(Context context) {
SharedPreferences prefs = getPreferences(context);
return Integer.parseInt(prefs.getString(Constants.PREFERENCES_KEY_MAX_ALBUMS, "20"));
}
public static int getDefaultSongs(Context context) {
SharedPreferences prefs = getPreferences(context);
return Integer.parseInt(prefs.getString(Constants.PREFERENCES_KEY_DEFAULT_SONGS, "10"));
}
public static int getMaxSongs(Context context) {
SharedPreferences prefs = getPreferences(context);
return Integer.parseInt(prefs.getString(Constants.PREFERENCES_KEY_MAX_SONGS, "20"));
}
public static int getMaxArtists(Context context) {
SharedPreferences prefs = getPreferences(context);
return Integer.parseInt(prefs.getString(Constants.PREFERENCES_KEY_MAX_ARTISTS, "20"));
}
public static int getDefaultArtists(Context context) {
SharedPreferences prefs = getPreferences(context);
return Integer.parseInt(prefs.getString(Constants.PREFERENCES_KEY_DEFAULT_ARTISTS, "3"));
}
public static int getNetworkTimeout(Context context) {
SharedPreferences prefs = getPreferences(context);
return Integer.parseInt(prefs.getString(Constants.PREFERENCES_KEY_NETWORK_TIMEOUT, "15000"));
}
public static int getBufferLength(Context context) {
SharedPreferences prefs = getPreferences(context);
return Integer.parseInt(prefs.getString(Constants.PREFERENCES_KEY_BUFFER_LENGTH, "5"));
}
public static boolean getGaplessPlaybackPreference(Context context) {
SharedPreferences prefs = getPreferences(context);
return prefs.getBoolean(Constants.PREFERENCES_KEY_GAPLESS_PLAYBACK, true);
}
public static boolean isNullOrWhiteSpace(String string) {
return string == null || string.isEmpty() || string.trim().isEmpty();
}
public static int getDirectoryCacheTime(Context context) {
SharedPreferences preferences = getPreferences(context);
return Integer.parseInt(preferences.getString(Constants.PREFERENCES_KEY_DIRECTORY_CACHE_TIME, "300"));
}
public static int getChatRefreshInterval(Context context) {
SharedPreferences prefs = getPreferences(context);
return Integer.parseInt(prefs.getString(Constants.PREFERENCES_KEY_CHAT_REFRESH_INTERVAL, "5000"));
}
public static WifiManager.WifiLock createWifiLock(Context context, String tag) {
WifiManager wm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
int lockType = WifiManager.WIFI_MODE_FULL;
if (Build.VERSION.SDK_INT >= 12) {
lockType = 3;
}
return wm.createWifiLock(lockType, tag);
}
/**
* This method converts dp unit to equivalent pixels, depending on device density.
*
* @param dp A value in dp (density independent pixels) unit. Which we need to convert into pixels
* @param context Context to get resources and device specific display metrics
* @return A float value to represent px equivalent to dp depending on device density
*/
public static float convertDpToPixel(float dp, Context context){
Resources resources = context.getResources();
DisplayMetrics metrics = resources.getDisplayMetrics();
return dp * (metrics.densityDpi / (float) DisplayMetrics.DENSITY_MEDIUM);
}
/**
* This method converts device specific pixels to density independent pixels.
*
* @param px A value in px (pixels) unit. Which we need to convert into db
* @param context Context to get resources and device specific display metrics
* @return A float value to represent dp equivalent to px value
*/
public static float convertPixelsToDp(float px, Context context){
Resources resources = context.getResources();
DisplayMetrics metrics = resources.getDisplayMetrics();
return px / (metrics.densityDpi / (float) DisplayMetrics.DENSITY_MEDIUM);
}
public static Bitmap decodeBitmap(Context context, int resourceId) {
return BitmapFactory.decodeResource(context.getResources(), resourceId);
}
public static boolean isServerCompatibleTo(Context context, String version) {
Version serverVersion = getServerRestVersion(context);
Version requiredVersion = new Version(version);
return serverVersion == null || serverVersion.compareTo(requiredVersion) >= 0;
}
public static void confirmDialog(Context context, int action, String subject, DialogInterface.OnClickListener onClick) {
Util.confirmDialog(context, context.getResources().getString(action).toLowerCase(), subject, onClick);
}
public static void confirmDialog(Context context, String action, String subject, DialogInterface.OnClickListener onClick) {
new AlertDialog.Builder(context)
.setIcon(android.R.drawable.ic_dialog_alert)
.setTitle(R.string.common_confirm)
.setMessage(context.getResources().getString(R.string.common_confirm_message, action, subject))
.setPositiveButton(R.string.common_ok, onClick)
.setNegativeButton(R.string.common_cancel, null)
.show();
}
}