/******************************************************************************
* Copyright (C) 2012, 2013, 2014, 2015, 2016
* Younghyung Cho. <yhcting77@gmail.com>
* All rights reserved.
*
* This file is part of NetMBuddy
*
* This program is licensed under the FreeBSD license
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation
* are those of the authors and should not be interpreted as representing
* official policies, either expressed or implied, of the FreeBSD Project.
*****************************************************************************/
package free.yhc.netmbuddy.utils;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import android.app.Activity;
import android.app.ActivityManager;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Rect;
import android.net.Uri;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.Window;
import free.yhc.abaselib.AppEnv;
import free.yhc.baselib.Logger;
import free.yhc.baselib.net.NetConn;
import free.yhc.baselib.net.NetConnHttp;
import free.yhc.abaselib.util.AUtil;
import free.yhc.baselib.util.FileUtil;
import free.yhc.abaselib.util.UxUtil;
import free.yhc.netmbuddy.R;
import free.yhc.netmbuddy.YTMPActivity;
import free.yhc.netmbuddy.core.PolicyConstant;
import free.yhc.netmbuddy.core.RTState;
public class Util extends free.yhc.baselib.util.Util {
private static final boolean DBG = Logger.DBG_DEFAULT;
private static final Logger P = Logger.create(free.yhc.netmbuddy.utils.Util.class, Logger.LOGLV_DEFAULT);
@SuppressWarnings("unused")
private static final String TAG = "[NetMBuddy]";
// Value SHOULD match xml preference value for title tts.
private static final int TITLE_TTS_HEAD = 0x02; // tts at the beginning
private static final int TITLE_TTS_TAIL = 0x01; // tts at the end
// This is only for debugging.
private static boolean sInitialized = false;
private static SharedPreferences sPrefs = null;
private static TimeElemComparator sTimeElemComparator = new TimeElemComparator();
private static final String[] sDateFormats = new String[] {
// To support W3CDTF
"yyyy-MM-d'T'HH:mm:ss.SSSZ",
"yyyy-MM-d'T'HH:mm:ss.SSS'Z'",
"yyyy-MM-d'T'HH:mm:ssZ",
"yyyy-MM-d'T'HH:mm:ss'Z'",
};
public enum PrefLevel {
LOW,
NORMAL,
HIGH
}
public enum PrefQuality {
LOW (R.string.low),
MIDLOW (R.string.midlow),
NORMAL (R.string.normal),
HIGH (R.string.high),
VERYHIGH(R.string.veryhigh);
private int text;
PrefQuality(int aText) {
text = aText;
}
public int
getText() {
return text;
}
@Nullable
public static PrefQuality
getMatchingQuality(int text) {
for (PrefQuality q : PrefQuality.values()) {
if (q.getText() == text)
return q;
}
return null;
}
}
public enum PrefTitleSimilarityThreshold {
VERYLOW (PolicyConstant.SIMILARITY_THRESHOLD_VERYLOW),
LOW (PolicyConstant.SIMILARITY_THRESHOLD_LOW),
NORMAL (PolicyConstant.SIMILARITY_THRESHOLD_NORMAL),
HIGH (PolicyConstant.SIMILARITY_THRESHOLD_HIGH),
VERYHIGH(PolicyConstant.SIMILARITY_THRESHOLD_VERYHIGH);
private float v;
PrefTitleSimilarityThreshold(float aV) {
v = aV;
}
public float
getValue() {
return v;
}
}
private static class TimeElem {
public Object v;
public long time;
public
TimeElem(Object aV, long aTime) {
v = aV;
time = aTime;
}
}
private static class TimeElemComparator implements Comparator<TimeElem> {
@Override
public int
compare(TimeElem a0, TimeElem a1) {
if (a0.time < a1.time)
return -1;
else if (a0.time > a1.time)
return 1;
else
return 0;
}
}
// ========================================================================
//
// Initialization
//
// ========================================================================
public static void
init(Context aAppContext) {
P.bug(!sInitialized);
sInitialized = true;
// This is called first for module initialization.
// So, ANY DEPENDENCY to other module is NOT allowed
sPrefs = PreferenceManager.getDefaultSharedPreferences(AppEnv.getAppContext());
}
public static void
initPostEssentialPermissions() throws IOException {
//noinspection ResultOfMethodCallIgnored
new File(PolicyConstant.APPDATA_DIR).mkdirs();
//noinspection ResultOfMethodCallIgnored
new File(PolicyConstant.APPDATA_VIDDIR).mkdirs();
// Clear/Create cache directory!
File cacheF = new File(PolicyConstant.APPDATA_CACHEDIR);
FileUtil.removeFileRecursive(cacheF);
//noinspection ResultOfMethodCallIgnored
cacheF.mkdirs();
}
// ========================================================================
//
// Fundamentals
//
// ========================================================================
// ========================================================================
//
//
//
// ========================================================================
/**
* Is is valid string?
* Valid means "Not NULL and Not empty".
*/
public static boolean
isValidValue(CharSequence v) {
return !(null == v || v.length() <= 0);
}
public static String
getCurrentTopActivity() {
ActivityManager am = (ActivityManager)AppEnv.getAppContext().getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> tasks = am.getRunningTasks(1);
ActivityManager.RunningTaskInfo ar = tasks.get(0);
return ar.topActivity.getClassName();
}
public static boolean
isAppForeground() {
return getCurrentTopActivity().startsWith(AppEnv.getAppContext().getPackageName() + ".");
}
public static void
resumeApp() {
Intent intent = new Intent(AppEnv.getAppContext(), YTMPActivity.class);
intent.setAction(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
AppEnv.getAppContext().startActivity(intent);
}
// ------------------------------------------------------------------------
//
//
//
// ------------------------------------------------------------------------
// ------------------------------------------------------------------------
//
// Date
//
// ------------------------------------------------------------------------
public static String
removeLeadingTrailingWhiteSpace(String s) {
s = s.replaceFirst("^\\s+", "");
return s.replaceFirst("\\s+$", "");
}
// ------------------------------------------------------------------------
//
// Accessing preference
//
// ------------------------------------------------------------------------
private static String
getStringPreference(String key, String defvalue) {
String value = (String)RTState.get().getOverridingPreference(key);
if (null == value)
value = sPrefs.getString(key, defvalue);
return value;
}
@SuppressWarnings("unused")
private static int
getIntPreference(String key, int defvalue) {
Integer value = (Integer)RTState.get().getOverridingPreference(key);
if (null == value)
value = sPrefs.getInt(key, defvalue);
return value;
}
private static boolean
getBooleanPreference(String key, boolean defvalue) {
Boolean value = (Boolean)RTState.get().getOverridingPreference(key);
if (null == value)
value = sPrefs.getBoolean(key, defvalue);
return value;
}
public static SharedPreferences
getSharedPreference() {
return sPrefs;
}
public static boolean
isPrefSuffle() {
return getBooleanPreference(AUtil.getResString(R.string.csshuffle), false);
}
public static boolean
isPrefRepeat() {
return getBooleanPreference(AUtil.getResString(R.string.csrepeat), false);
}
@NonNull
public static PrefQuality
getPrefQuality() {
String v = getStringPreference(AUtil.getResString(R.string.csquality),
AUtil.getResString(R.string.csNORMAL));
for (PrefQuality q : PrefQuality.values()) {
if (q.name().equals(v))
return q;
}
P.bug(false);
return PrefQuality.LOW;
}
public static float
getPrefTitleSimilarityThreshold() {
String v = getStringPreference(AUtil.getResString(R.string.cstitle_similarity_threshold),
AUtil.getResString(R.string.csNORMAL));
for (PrefTitleSimilarityThreshold q : PrefTitleSimilarityThreshold.values()) {
if (q.name().equals(v))
return q.getValue();
}
P.bug(false);
return PolicyConstant.SIMILARITY_THRESHOLD_NORMAL;
}
@SuppressWarnings("unused")
public static PrefLevel
getPrefMemConsumption() {
// See preference.xml for meaning of each number value.
String lv = sPrefs.getString(AUtil.getResString(R.string.csmem_consumption),
AUtil.getResString(R.string.csNORMAL));
if (AUtil.getResString(R.string.csLOW).equals(lv))
return PrefLevel.LOW;
else if (AUtil.getResString(R.string.csNORMAL).equals(lv))
return PrefLevel.NORMAL;
else if (AUtil.getResString(R.string.csHIGH).equals(lv))
return PrefLevel.HIGH;
else {
P.bug(false);
return PrefLevel.NORMAL;
}
}
public static boolean
isPrefLockScreen() {
return getBooleanPreference(AUtil.getResString(R.string.cslockscreen), false);
}
public static boolean
isPrefStopOnBack() {
return getBooleanPreference(AUtil.getResString(R.string.csstop_on_back), true);
}
public static boolean
isPrefErrReport() {
return getBooleanPreference(AUtil.getResString(R.string.cserr_report), true);
}
private static boolean
isPrefUseWifiOnly() {
return getBooleanPreference(AUtil.getResString(R.string.csuse_wifi_only), false);
}
public static int
getPrefTtsValue() {
int value = 0;
try {
value = Integer.parseInt(sPrefs.getString(AUtil.getResString(R.string.cstitle_tts), "0"));
} catch (NumberFormatException ignored) { }
return value;
}
public static boolean
isPrefTtsEnabled() {
return 0 != getPrefTtsValue();
}
public static boolean
isPrefHeadTts() {
return (0 != (TITLE_TTS_HEAD & getPrefTtsValue()));
}
public static boolean
isPrefTailTts() {
return (0 != (TITLE_TTS_TAIL & getPrefTtsValue()));
}
// ------------------------------------------------------------------------
//
//
//
// ------------------------------------------------------------------------
public static float
max(float f0, float f1) {
return (f0 < f1)? f1: f0;
}
// ------------------------------------------------------------------------
//
// Misc
//
// ------------------------------------------------------------------------
@SuppressWarnings("unused")
public static String
secsToTimeText(int secs) {
int h = secs / 60 / 60;
secs -= h * 60 * 60;
int m = secs / 60;
secs -= m * 60;
return String.format(Locale.getDefault(), "%02d:%02d:%02d", h, m, secs);
}
public static String
secsToMinSecText(int secs) {
int m = secs / 60;
secs -= m * 60;
return String.format(Locale.getDefault(), "%02d:%02d", m, secs);
}
public static String
millisToHourMinText(long millies) {
int s = (int)(millies / 1000);
int m = s / 60;
int h = m / 60;
m -= h * 60;
return String.format(Locale.getDefault(), "%02d:%02d", h, m);
}
public static void
copy(OutputStream os, InputStream is) throws IOException, InterruptedException {
byte buf[]=new byte[1024 * 16];
int len;
while((len = is.read(buf)) > 0) {
if (Thread.currentThread().isInterrupted())
throw new InterruptedException();
os.write(buf, 0, len);
}
}
public static <K,V> K
findKey(HashMap<K, V> map, V value) {
for (K key : map.keySet()) {
if (map.get(key).equals(value))
return key;
}
return null;
}
public static Object[]
getSortedKeyOfTimeMap (HashMap<?, Long> timeMap) {
TimeElem[] te = new TimeElem[timeMap.size()];
Object[] vs = timeMap.keySet().toArray();
for (int i = 0; i < vs.length; i++)
te[i] = new TimeElem(vs[i], timeMap.get(vs[i]));
Arrays.sort(te, sTimeElemComparator);
Object[] sorted = new Object[vs.length];
for (int i = 0; i < sorted.length; i++)
sorted[i] = te[i].v;
return sorted;
}
// ------------------------------------------------------------------------
//
// Other android specifics.
//
// ------------------------------------------------------------------------
public static boolean
isNetworkAvailable() {
return NetConn.isNetConnected(isPrefUseWifiOnly()? NetConn.TYPE_WIFI: NetConn.TYPE_ANY);
}
public static NetConnHttp
createNetConnHttp(URL url, String uastring) throws IOException {
NetConnHttp.Builder bldr = NetConnHttp.Builder.newBuilder(url);
if (isPrefUseWifiOnly())
bldr.setNetType(NetConn.TYPE_WIFI);
if (null != uastring)
bldr.setUastring(uastring);
return bldr.create();
}
public static NetConn
createNetConn(URL url) throws IOException {
NetConn.Builder bldr = NetConn.Builder.newBuilder(url);
if (isPrefUseWifiOnly())
bldr.setNetType(NetConn.TYPE_WIFI);
return bldr.create();
}
@SuppressWarnings("unused")
public static boolean
copyAssetFile(String dest, String assetFile) {
try {
InputStream is = AppEnv.getAppContext().getAssets().open(assetFile);
FileOutputStream os = new FileOutputStream(new File(dest));
copy(os, is);
is.close();
os.close();
return true;
} catch (InterruptedException e) {
return false;
} catch (IOException e) {
return false;
}
}
public static void
sendMail(Context context,
String receiver,
String subject,
String text,
File attachment) {
if (!free.yhc.netmbuddy.utils.Util.isNetworkAvailable())
return;
Intent intent = new Intent(Intent.ACTION_SEND);
if (null != receiver)
intent.putExtra(Intent.EXTRA_EMAIL, new String[] { receiver });
intent.putExtra(Intent.EXTRA_TEXT, text);
intent.putExtra(Intent.EXTRA_SUBJECT, subject);
if (null != attachment)
intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(attachment));
intent.setType("message/rfc822");
try {
context.startActivity(intent);
} catch (ActivityNotFoundException e) {
UxUtil.showTextToast(R.string.msg_fail_find_app);
}
}
/**
* Only available when status bar is showing.
*/
public static int
getStatusBarHeight(Activity activity) {
Rect rect= new Rect();
Window window= activity.getWindow();
window.getDecorView().getWindowVisibleDisplayFrame(rect);
// Below is for future reference.
// int StatusBarHeight = rect.top;
// int contentViewTop = window.findViewById(Window.ID_ANDROID_CONTENT).getTop();
// int TitleBarHeight= contentViewTop - StatusBarHeight;
return rect.top;
}
@NonNull
public static Rect
getVisibleFrame(Activity activity) {
Rect rect= new Rect();
Window window= activity.getWindow();
window.getDecorView().getWindowVisibleDisplayFrame(rect);
return rect;
}
}