`
zcwfeng
  • 浏览: 106568 次
  • 性别: Icon_minigender_1
  • 来自: 吉林
社区版块
存档分类
最新评论

android 离线下载

 
阅读更多

==========================离线下载

import java.io.BufferedInputStream;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Stack;
import java.util.Timer;
import java.util.TimerTask;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;


import org.json.JSONException;
import org.json.JSONObject;


import com.rytong.tools.crypto.AESCipher;
import com.rytong.tools.crypto.Base64;
import com.rytong.tools.crypto.HMac;
import com.rytong.tools.httpconnect.HttpManager;
import com.rytong.tools.utils.Utils;


import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.AlertDialog.Builder;
import android.content.DialogInterface;
import android.os.Looper;
import android.util.DisplayMetrics;


public class OffStoreDownload {
private final String PLUGRESOURCES = "plug_in_resources.db";
private final String OFFLINERESOURCES = "offline_resources.db";
private Activity activity_;
// 是否必须更新(-1:不更新,0:不强制更新,1:强制更新)
private String mustupate_;
// 离线资源数据库
public static OffStoreDB offLineDB_;
// 插件数据库
public static OffStoreDB plugDB_;

static public String FILEROOT;

final static public String PLUGROOT = "plug-in-resources/";
final static public String OFFLINEROOT = "offline-resources/";
final static public String WRITEROOT = "write/";
// 需要更新资源列表
private HashMap<String, String> resourceMap_;
// 列表path和rev(SHA1的hash)
private HashMap<String, HashMap<String, String>> serverMap_;
private HashMap<String, Boolean> alreadyDownload_;
private String serverString_;
// 离线更新接口
public final String RESOURCE_UPDATE = "/ota/resource_update?";
private int downloadNum_;


public OffStoreDownload(Activity activity) {
activity_ = activity;
alreadyDownload_ = new HashMap<String, Boolean>();
downloadNum_ = 1;// 重复下载一次即可。
offLineDB_ = new OffStoreDB(activity, OFFLINERESOURCES);
plugDB_ = new OffStoreDB(activity, PLUGRESOURCES);
}


// 步骤1:发送请求:平台类型、屏幕分辨率、server.desc(不存在则为空)
public void downloadOfflineResource() {
// 手机平台
final String platform = Utils.getConfigStringFormAsset(activity_, "offstoreplatform");
// 分辨率
DisplayMetrics dm = new DisplayMetrics();
activity_.getWindowManager().getDefaultDisplay().getMetrics(dm);
final String screenResolution = String.valueOf(dm.widthPixels) + "*" + String.valueOf(dm.heightPixels);
// 本地离线文件client.desc(不为空则发送)
final String client_desc = (String) offLineDB_.find("client.desc");
Timer timer_ = new Timer();
timer_.schedule(new TimerTask() {
@Override
public void run() {
HttpManager hm = new HttpManager(activity_);
String uri = Utils.getConfigStringFormAsset(activity_, "SERVER_URI").concat(RESOURCE_UPDATE);// http://192.168.85.69:4002/ota/resource_update?
StringBuffer buf = new StringBuffer();
buf.append("desc=");
if (client_desc != null)
buf.append(client_desc).append("&");
else
buf.append("&");
buf.append("platform=").append(platform).append("&");
buf.append("resolution=").append(screenResolution);
String body = buf.toString();
Object server_update = hm.sendPostRequest(uri, body, HttpManager.MIME_JSON, null);
// 步骤2:读取返回的download.desc和server.desc。
parseResponse(server_update);
}
}, 0);
}


public void saveToDb(OffStoreDB db, String key, Object value) {
db.insert(key, value);
}


// 解析返回来的数据
protected void parseResponse(Object serverUpdate) {
if (null == serverUpdate)
return;
if (serverUpdate instanceof String)
parseJSON((String) serverUpdate);
}


// 先判断是否需要强制更新,如果不是强制更新,则提醒用户。
private void parseJSON(String serverResponse) {
try {
// {"mustupdate":0,"server":{"yybk.zip":{"rev":"0b08d0c498e0eb5e2d19abc6dda695cc7f462473","path":"android/480-320/zip","desc":{"html/showCard.html":"0afd92a6b7fa6070a3610ffad94d24c0137538d1","imgs/back_03.png":"91e81ea8d58fcca77f4e43699e3cc8186691cdb2","imgs/card1.png":"f4598e2ea5d5fee387cb906506a424e1e842aac7","imgs/card2.png":"c42659dd3ab85894685ea7b10bcd2755b6d7b2cc","imgs/card3.png":"debe586a42d9b3536574bcd1daaaafb67332e99a","imgs/photo1.png":"14fbab85d86ce08593b67153a86daa8085fec61f","imgs/title_02.png":"63f7b712014402807f35d37b34acfc557228e7d2","js/jquery-1.7.1.js":"62922be0191a2cc4d13ef3abe4a62d1ebc17492d"}}},"download":{"yybk.zip":"http://192.168.65.82:4004/ebank/resources/android/480-320/zip/yybk.zip"}};
// {"mustupdate":0,"server":{"colorful.png":{"rev":"7915a251510c265826a1ee14c5a7c1ac31459890","path":"android/320*480/png"},"background_cao.png":{"rev":"da39a3ee5e6b4b0d3255bfef95601890afd80709","path":"android/320*480/png"}},"download":{"background_cao.png":"http://192.168.63.68:4002/ebank/resources/android/320*480/png/background_cao.png","colorful.png":"http://192.168.63.68:4002/ebank/resources/android/320*480/png/colorful.png"}}
Utils.printOutToConsole("offstore data: " + serverResponse);
final JSONObject obj = new JSONObject(serverResponse);
// 是否必须更新
mustupate_ = obj.getString("mustupdate");
if (null == mustupate_)
return;
if (mustupate_.equalsIgnoreCase("0")) {
final Builder ad = new AlertDialog.Builder(activity_);
ad.setTitle("提示").setMessage("您有新的离线资源需要下载,是否更新?").setCancelable(false)
.setNegativeButton("确定", new DialogInterface.OnClickListener() {


public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
parseJSONIndeed(obj);
if (checkAllDownload()) {
// 下载10:下载完毕后存储server.desc文件。
saveToDb(offLineDB_, "client.desc", serverString_);
return;
}
downloadResourceByPath();// 根据路径下载每一个resource
}


}).setPositiveButton("取消", new DialogInterface.OnClickListener() {


public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
}


});
if (!activity_.isFinishing()) {
activity_.runOnUiThread(new Runnable() {


@Override
public void run() {
// TODO Auto-generated method stub
ad.show();
}


});
}


} else {
parseJSONIndeed(obj);
if (checkAllDownload()) {
// 下载10:下载完毕后存储server.desc文件。
saveToDb(offLineDB_, "client.desc", serverString_);
return;
}
downloadResourceByPath();// 根据路径下载每一个resource
}


} catch (JSONException e) {
Utils.printException(e);
}
}


// 解析JSON---步骤3:解析download.desc。
private void parseJSONIndeed(JSONObject obj) {
// TODO Auto-generated method stub
// download.desc
try {
resourceMap_ = new HashMap<String, String>();
serverMap_ = new HashMap<String, HashMap<String, String>>();
JSONObject downObject;


downObject = obj.getJSONObject("download");


Iterator itDown = downObject.keys();
String key = "";
String value = "";
while (itDown.hasNext()) {
key = itDown.next().toString();
value = downObject.getString(key);
// 未下载时,更新标志为false;更新后修改标志位
alreadyDownload_.put(key, false);
resourceMap_.put(key, value);
}


// server.desc
JSONObject serverObject = obj.getJSONObject("server");
serverString_ = serverObject.toString();
Iterator itServer = serverObject.keys();
key = "";
JSONObject jsonValue;
String path;
String rev;
while (itServer.hasNext()) {
key = itServer.next().toString();
jsonValue = serverObject.getJSONObject(key);
HashMap<String, String> params = new HashMap<String, String>();
path = jsonValue.getString("path");
rev = jsonValue.getString("rev");
params.put("path", path);
params.put("rev", rev);
serverMap_.put(key, params);
}
} catch (JSONException e) {
// TODO Auto-generated catch block
Utils.printException(e);
}
}


// 步骤5:根据download.desc下载列表建立任务队列task-list。
public void downloadResourceByPath() {
try {
String fileName = null, filePath = null, shaFile = null, serverFileName = null, serverPath = null, serverRev = null;
byte[] fileString = null;
if (resourceMap_ == null)
return;


Iterator it = resourceMap_.keySet().iterator();
HashMap<String, String> params;
while (it.hasNext()) {
fileName = it.next().toString();
filePath = resourceMap_.get(fileName);
if (checkDownload(fileName)) {
// 已经下载过,返回
return;
} else {
// 下载每个文件
fileString = downloadPerResource(filePath);
File file = Utils.getFileFromBytes(fileString, fileName);
if (Utils.getMIMEType(file).equalsIgnoreCase("zip")) {
// 如果数据是压缩的则应进行解压操作
unZip(new ByteArrayInputStream(fileString));
// fileString = Utils.gunzip(fileString);
}
file = null;
// 计算文件SHA1值
if (fileString != null) {
byte[] temp = HMac.SHA1(fileString);
shaFile = HMac.byteArrayToHexString(temp);
}
}
// 查找第二个Map中含有第一个Map的key
if (serverMap_.containsKey(fileName)) {
params = serverMap_.get(fileName);
serverPath = params.get("path");
serverRev = params.get("rev");
}
// 步骤6:每一个资源文件下载完毕后计算资源文件的SHA1值,并与server.desc记录的SHA1值进行比较。(递归)
comparedRedownload(fileName, shaFile, filePath, fileString, serverRev);
}
} catch (Exception e) {
// TODO Auto-generated catch block
Utils.printException(e);
}
}


private void unZip(InputStream input) {
// TODO Auto-generated method stub
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(input));
try {
ZipEntry ze;
while ((ze = zis.getNextEntry()) != null) {
ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
byte[] buffer = new byte[1024];
int count;
while ((count = zis.read(buffer)) != -1) {
baos.write(buffer, 0, count);
}
String filename = ze.getName();
byte[] bytes = baos.toByteArray();
// do something with 'filename' and 'bytes'...
saveToDb(plugDB_, filename, bytes);
}
} catch (IOException e) {
// TODO Auto-generated catch block
Utils.printException(e);
} finally {
try {
if (null != zis)
zis.close();
} catch (IOException e) {
// TODO Auto-generated catch block
Utils.printException(e);
}
}


}


/**
* @param fileName
* 客户端文件名
* @param shaFile
* 客户端计算出的SHA1
* @param filePath
* 客户端下载文件的路径
* @param fileString
* 客户端下载文件后的字节数组
* @param serverFileName
* 服务器端文件名
* @param serverRev
* 服务器端SHA1
*/
private void comparedRedownload(String fileName, String shaFile, String filePath, byte[] fileString,
String serverRev) {
try {
boolean noModify = comparedSHA1(fileName, shaFile, serverRev);
if (noModify) {
// 步骤7:验证资源文件的正确性后,以name为key存储资源文件。
// 下载完的文件保存到数据库


offLineDB_.deleteToDB(fileName);
if (fileName.contains(".png"))
saveToDb(offLineDB_, fileName, fileString);
else
saveToDb(offLineDB_, fileName, new String(fileString, "UTF-8"));


// 步骤8:更新download.desc的下载状态标记,标记为已下载。
// 保存到数据库后修改"已下载"的标志位
alreadyDownload_.put(fileName, true);
} else {
if (downloadNum_-- > 0) {
// 重新下载每个文件
fileString = downloadPerResource(filePath);
File file = Utils.getFileFromBytes(fileString, fileName);
if (Utils.getMIMEType(file).equalsIgnoreCase("zip")) {
// 如果数据是压缩的则应进行解压操作
fileString = Utils.gunzip(fileString);
}
file = null;
// 重新计算文件SHA1值
byte[] disg = HMac.SHA1(fileString);
if (disg != null) {
shaFile = disg.toString();
}
comparedRedownload(fileName, shaFile, filePath, fileString, serverRev);
}
}
} catch (UnsupportedEncodingException e) {
Utils.printException(e);
} catch (IOException e) {
// TODO Auto-generated catch block
Utils.printException(e);
} catch (Exception e) {
// TODO Auto-generated catch block
Utils.printException(e);
}
}


// 判断文件名为fileName的文件是否下载过
private boolean checkDownload(String fileName) {
if (alreadyDownload_ != null) {
return alreadyDownload_.get(fileName);
}
return false;
}


// 判断所有的文件是否下载完
private boolean checkAllDownload() {
if (alreadyDownload_ != null) {
for (Map.Entry<String, Boolean> entry : alreadyDownload_.entrySet()) {
boolean entryDownload = entry.getValue();
// 如果有值为false,即为没有下载完,所有的都为true,才为全部下载完成
if (!entryDownload)
return false;
}
// 全部下载完成
return true;
}
return false;
}


// 比较下栽文件的SHA1和server.desc
private boolean comparedSHA1(String fileName, String shaFile, String serverSHA1) {
if (fileName != null && shaFile != null & serverSHA1 != null) {
if (shaFile.equalsIgnoreCase(serverSHA1)) {
return true;
}
}
return false;
}


// 下载文件列表中的每一个文件
private byte[] downloadPerResource(String filePath) {
ByteArrayOutputStream fileBuffer = new ByteArrayOutputStream(1024);
byte[] fileBytes = null;
try {
HttpManager hm = new HttpManager(activity_);
hm.read(filePath, fileBuffer, null);
fileBytes = fileBuffer.toByteArray();
} catch (Exception e) {
Utils.printException(e);
} catch (OutOfMemoryError oe) {
Utils.printOutToConsole(oe);
} finally {
if (null != fileBuffer)
try {
fileBuffer.close();
} catch (IOException e) {
// TODO Auto-generated catch block
Utils.printException(e);
}
fileBuffer = null;
}
return fileBytes;
}


public boolean getFirstLogin() {
File file = new File(activity_.getFilesDir(), offLineDB_.DATABASE_NAME);
return file.exists();
}


/**
* 不联网情况下个别页面读取本地数据库XML
*
* @param itemValue
* @param currentView_
* @return
*/
public Object readOfflineResource(OffStoreDB db, String itemValue) {
return db.find(itemValue);
}


public static void setRootPath() {
FILEROOT = Utils.getActivity().getFilesDir().getPath().concat("/");
}


}


===============================================================================

//数据库操作


import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;


public class OffStoreDB extends SQLiteOpenHelper {


public static String DATABASE_NAME = "emp.db";
private static int DATABASE_VERSION = 1;
private static String TABLE_NAME = "emp_table";
private static String COLUMN_ID = "_id";
private static String COLUMN_NAME = "name";
private static String COLUMN_VALUE = "value";


public OffStoreDB(Context context, String name) {
super(context, name, null, DATABASE_VERSION);
}


@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("create table ".concat(TABLE_NAME).concat("(").concat(COLUMN_ID)
.concat(" integer primary key autoincrement,").concat(COLUMN_NAME).concat(" varchar(20),")
.concat(COLUMN_VALUE).concat(" varchar(100))"));
}


@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS ".concat(TABLE_NAME));
onCreate(db);
}


public long insert(String column_name, Object column_value) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues cv = new ContentValues();
cv.put(COLUMN_NAME, column_name);
if (column_value instanceof String)
cv.put(COLUMN_VALUE, (String) column_value);
else if (column_value instanceof byte[])
cv.put(COLUMN_VALUE, (byte[]) column_value);
long row = db.insert(TABLE_NAME, null, cv);
return row;
}


public Object find(String name) {
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery("select value from emp_table where name = ?", new String[] { name });
// select value from emp_table where name = "fwzx.xml";
if (cursor.moveToNext()) {
Object value = null;
try {
// 如果是图片将会被保存为字节数组形式
if (name.contains(".png"))
value = cursor.getBlob(cursor.getColumnIndex(COLUMN_VALUE));
else
value = cursor.getString(cursor.getColumnIndex(COLUMN_VALUE));
cursor.close();
} catch (Exception e) {
Utils.printException(e);
}
return value;
} else {
cursor.close();
return null;
}
}


public int deleteToDB(String fileName) {
SQLiteDatabase db = this.getWritableDatabase();
// ContentValues cv = new ContentValues();
// cv.put(COLUMN_NAME, fileName);
return db.delete(TABLE_NAME, COLUMN_NAME + "=?", new String[] { fileName });
}
}


-----------------------------------------------utils

//#define Android2.2
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.StreamCorruptedException;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Vector;


import java.util.UUID;


import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.json.JSONArray;
import org.json.JSONObject;


import com.rytong.tools.clienthello.ClientHello;
import com.rytong.tools.crypto.AESCipher;
import com.rytong.tools.crypto.HMac;
import com.rytong.tools.crypto.MD5;
import com.rytong.tools.crypto.RSACipher;
import com.rytong.tools.httpconnect.HttpManager;
import com.rytong.tools.offstore.OffStoreDownload;
import com.rytong.tools.ui.Component;
import com.rytong.tools.ui.LPLayout;


import android.R.color;
import android.R.integer;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.os.Build;
import android.telephony.CellLocation;
import android.telephony.TelephonyManager;
// #ifdef Android2.2
import android.telephony.cdma.CdmaCellLocation;
// #endif
import android.telephony.gsm.GsmCellLocation;
import android.text.TextPaint;
import android.util.DisplayMetrics;
import android.view.View;


/**
* Utility class.
*/
public final class Utils {
private static int BRHEIGHT;
private static Activity activity_;
// 是否打印标志
private static boolean isPrintMessage_;
// 字体缩放参数,如果手机分辨率和密度同比增长,则该参数?,表示不需缩放,如果不匹配,则需校正该参数设?
public static float SCALEDFONT;
// 基准屏幕的宽,该值应和服务端定义xml的基准屏幕保持?????
public static int BenchmarkresolutionW_;
// 基准屏幕的高,该值应和服务端定义xml的基????幕保持一?
public static int BenchmarkresolutionH_;
/**
* Used for gzip. Re. rfc1951.
*/
static int gIndex = 0;
static int bitByte = 0;
static int bitIndex = 0;
private final static int MAX_BITS = 16;
private final static int[] EXTRA_L_BITS = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4,
5, 5, 5, 5, 0 };
private final static int[] EXTRA_L_VALUES = { 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51,
59, 67, 83, 99, 115, 131, 163, 195, 227, 258 };
private final static int[] EXTRA_D_BITS = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10,
10, 11, 11, 12, 12, 13, 13 };
private final static int[] EXTRA_D_VALUES = { 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385,
513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 };
private final static int[] DYNAMIC_L_ORDER = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };


// 界面X方向参考缩放参?此参数为控件宽或者字体大小的参考??
public static float SCALEDATEX;
// 界面Y方向参考缩放参?此参数为控件高的参考??
public static float SCALEDATEY;
/** Default alpha value used to draw menu panels and status bars. */
public final static int DEFAULT_TRANSPARENCY = 0xa0000000;
final static int OK_KEY = -5;
final static int LEFT_SOFTKEY = -6;
final static int RIGHT_SOFTKEY = -7;


// if it is sony ericsson, SONY_ERICSSON is true.
public final static boolean SONY_ERICSSON = false;
// 日志名称
public static final String LOGNAME = "LPC";
/**
* Used as indices in text parser's return result of a line break in a string.
*/
public final static int LBI_BREAK = 0; // Break position (this char is in current
// line)
public final static int LBI_NEXT = 1; // Next char position to resume scanning (to
// skip tags)
public final static int LBI_TYPE = 2; // Line break type: newline, paragraph, ...,
// defined below.
public final static int LBI_START = 3; // Starting position of this line.
public final static int LBI_SIZE = 4; // Number of linebreak indices.


/**
* Types of line breaks.
*/
final static int LB_NEWLINE = 0;
final static int LB_PARAGRAPH = 1;
final static int LB_SKIP = 2; // Skip characters within [LBI_BREAK,
// LBI_NEXT)
final static int LB_HYPHEN = 3;


/**
* The number of alpha transparency levels。will be reset by numAlphaLevels() in LPMid.java. The minimum
* numAlphaLevel_ is 2, which indicates only support for full transparency and full opacity.
*/
final static int numAlphaLevel_ = 256;


final static int BLUE = 0xFF0000FF;
final static int WHITE = 0xFFFFFFFF;
final static int BLACK = 0xFF000000;
final static int GREY = 0xFF808080;
final static int SELECTED_LINK_COLOR = 0xFF808080;
public final static int TABBARBACKGROUNDCOLOR = 0xFF294B78;


public final static char MATCH = '\"';


/** True if the user selects item Map */
public static boolean toMapView_;


final static String SPLIT_CHARACTERS = " ,.";


// 调用系统相机的请求码
public final static int CAMERA_REQUEST_CODE = 1001;


// 解读并存储assets文件夹下的Config.txt文件信息
private static HashMap<String, String> configHm_;


// 连点事件一时间间隔
public static int jat_lag = 0;


/**
* @return
*/
public final static byte[] getClientGMTUnixTime() {
// get local time.4 bytes.
Calendar cal = Calendar.getInstance();
Date date = cal.getTime();
int hours = date.getHours();
byte[] clientGmtUnixTime = new byte[4];
clientGmtUnixTime[0] = (byte) ((hours & 0x0000FF00) >> 8);
clientGmtUnixTime[1] = (byte) ((hours & 0x000000FF));
int minutes = date.getMinutes();
clientGmtUnixTime[2] = (byte) ((minutes & 0x0000FF00) >> 8);
clientGmtUnixTime[3] = (byte) ((minutes & 0x000000FF));
return clientGmtUnixTime;
}


// /**
// * 从资源图片里面获取指定文件名的图片,如果没有就返回空
// *
// * @param 指定的要查找的文件名
// * @param 界面对象
// * @return
// */
// public final final static Bitmap getBitmapFromDrawable(Activity bv, String bitmapName) {
// bitmapName = bitmapName.trim();
// if (bitmapName.endsWith(".png")) {
// // 服务端传送过来的图片名称有可能带?png后缀,先去掉后缀再进行相关操作比?
// bitmapName = bitmapName.substring(0, bitmapName.lastIndexOf(".png"));
// }
// // 利用反射机制获取对象域名
// Object obj = null;
// String varName = null;
// Field[] fields = R.drawable.class.getDeclaredFields();
// int size = fields.length;
// for (int i = 0, len = size; i < len; i++) {
// // 对于每个属性,获取属性名
// varName = fields[i].getName();
// if (varName.equalsIgnoreCase(bitmapName)) {
// try {
// // 获取原来的访问控制权?
// boolean accessFlag = fields[i].isAccessible();
// // 修改访问控制权限
// fields[i].setAccessible(true);
// // 获取在对象f中属性fields[i]对应的对象中的变?
// obj = fields[i].get(varName);
// // ????访问控制权限
// fields[i].setAccessible(accessFlag);
// int id = Integer.parseInt(obj.toString());
// Bitmap bm = getBitmap(id, bv);
// return bm;
// } catch (IllegalArgumentException ex) {
// printException(ex);
// } catch (IllegalAccessException ex) {
// printException(ex);
// }
// }
// }
// return null;
// }
/**
* 发送端?
*
* @param phoneNum
* @param content
*/
public final static void sendSms(int phoneNum, String content) {
Intent intent = new Intent();
// 系统默认的action,用来打开默认的短信界?
intent.setAction(Intent.ACTION_SENDTO);
// 需要发短息的号?
intent.setData(Uri.parse("smsto:" + phoneNum));
intent.putExtra("sms_body", content);
activity_.startActivity(intent);
}


/**
* 获取资源图片
*
* @param context
* @param resourcesName
* @return
*/
public final static Bitmap getBitmapFromResources(Context context, String resourcesName) {
Bitmap bitmap = null;
if (resourcesName == null)
return bitmap;


Object img = null;
// 先补?png后缀名从sql中取出对应的图片
resourcesName = getPNGName(resourcesName);
img = OffStoreDownload.plugDB_.find(resourcesName);
if (null != img && img instanceof byte[]) {
byte[] temp = (byte[]) img;
bitmap = BitmapFactory.decodeByteArray(temp, 0, temp.length);
return bitmap;
}


img = OffStoreDownload.offLineDB_.find(resourcesName);
if (null != img && img instanceof byte[]) {
byte[] temp = (byte[]) img;
bitmap = BitmapFactory.decodeByteArray(temp, 0, temp.length);
return bitmap;
}
// 如果sql中没有存储对应的图片,则将后缀去掉,在资源文件里面搜索
if (resourcesName.endsWith(".png")) {
resourcesName = resourcesName.substring(0, resourcesName.lastIndexOf(".png"));
}
resourcesName = resourcesName.toLowerCase();
int resourcesId = getResourcesId(context, resourcesName, "drawable");
if (resourcesId != 0) {
bitmap = getBitmap(resourcesId, (Activity) context);
}


return bitmap;
}


/**
* 获取资源id
*
* @param context
* @param resourcesName
* @param resourcesType
* @param packageName
* @return
*/
public final static int getResourcesId(Context context, String resourcesName, String resourcesType) {
int resourcesId = 0;
resourcesId = context.getResources().getIdentifier(resourcesName, resourcesType, context.getPackageName());
return resourcesId;
}


/**
* 获取项目Config中的app名称,用于联网后台区别报?
*
* @param activity
*/
public final static void getAppName(Activity activity) {
HttpManager.APPNAME = getConfigStringFormAsset(activity, "app");
}


public final static void getPlatform(Activity activity) {
HttpManager.OPLATFORM = getConfigStringFormAsset(activity, "oPlatform");
}


public final static String getClientType(Activity activity) {
return getConfigStringFormAsset(activity, "clientType");
}


/**
* 判断字符串是否以.png结尾,如果不是则加上该后缀
*/
public final static String getPNGName(String name) {
name = name.trim();
if (!name.endsWith(".png")) {
if (name.indexOf(".") != -1)
name = name.substring(0, name.indexOf("."));
name = name.concat(".png");
}
return name;
}


public final static Bitmap getBitmap(int rdoing, Activity bv) {
// TODO Auto-generated method stub
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inPreferredConfig = Bitmap.Config.RGB_565;
opt.inPurgeable = true;
opt.inInputShareable = true;
InputStream is = bv.getResources().openRawResource(rdoing);


Bitmap img = BitmapFactory.decodeStream(is, null, opt);
try {
is.close();
} catch (IOException e) {
// TODO Auto-generated catch block
Utils.printException(e);
}
return img;
}


public final static int getColorValue(String value) {
String colorstr = "";
try {
colorstr = getValidColorString(value);


if (colorstr.length() > 6) {
int color = Integer.parseInt(colorstr, 16);
color |= 0x00000000;
return color;
} else {
int color = Integer.parseInt(colorstr, 16);
color |= 0xFF000000;
return color;
}
} catch (Exception e) {
// TODO Auto-generated catch block
Utils.printException(e);
return 0xFFFFFFFF;
}


}


/**
* The valid color string is a 6 bit hex number. e.g., FFFFFF.
*
* @param srcColorstr
* @return
*/
public final static String getValidColorString(final String srcColorstr) throws Exception {
String colorstr = srcColorstr;
if (colorstr.startsWith("#")) {
colorstr = colorstr.substring(1);
}
return colorstr;
}


// 将字符串数组中的内???转换成????????方便字符数组检?
public final static String getArrayString(String[] sa) {
if (null == sa)
return "";
return Arrays.toString(sa);
}


final static boolean isLeftSoftKey(int key) {
return (key == LEFT_SOFTKEY);
}


final static boolean isRightSoftKey(int key) {
// Motorola some phones's right key is -22, and other is 22.
// return (key == RIGHT_SOFTKEY || key == -RIGHT_SOFTKEY);
return (key == RIGHT_SOFTKEY);
}


final static int getLeftSoftKey() {
return LEFT_SOFTKEY;
}


final static int getRightSoftKey() {
return RIGHT_SOFTKEY;
}


/**
*
* 把字节数组保存为一个文?
*
*/
public final static File getFileFromBytes(byte[] b, String outputFile) {


String pathString = activity_.getFilesDir().getPath().concat("/");
BufferedOutputStream stream = null;


File file = null;


try {


file = new File(pathString.concat(outputFile));
file.createNewFile();
FileOutputStream fstream = new FileOutputStream(file);


stream = new BufferedOutputStream(fstream);


stream.write(b);


} catch (Exception e) {


printException(e);


} finally {


if (stream != null) {


try {


stream.close();


} catch (IOException e1) {


printException(e1);


}


}


}


return file;


}


/**
* 根据文件后缀名返回文件类?
*
* @param fileTemp
* @return
*/
public final static String getMIMEType(File fileTemp) {
// TODO Auto-generated method stub
String type = "";
String fName = fileTemp.getName();
String end = fName.substring(fName.lastIndexOf(".") + 1, fName.length()).toLowerCase();
if (end.equals("m4a") || end.equals("mp3") || end.equals("mid") || end.equals("xmf") || end.equals("ogg")
|| end.equals("wav")) {
type = "audio";
} else if (end.equals("3gp") || end.equals("mp4")) {
type = "video";
} else if (end.equals("jpg") || end.equals("gif") || end.equals("png") || end.equals("jpeg")
|| end.equals("bmp")) {
type = "image";
} else if (end.equals("apk")) {
type = "application/vnd.android.package-archive";
} else if (end.equals("zip")) {
type = "zip";
} else if (end.equals("apk")) {


} else {
type += "/*";
}
return type;
}


/**
* Graphics.drawRegion() has a bug in 4.2.1 and we have to use a replacement function.
*/
public final static void drawRegion(Canvas g, Bitmap img, int srcX, int srcY, int width, int height, int dstX,
int dstY) {
g.drawBitmap(img, new Rect(srcX, srcY, srcX + width, srcY + height), new Rect(dstX, dstY, dstX + width, dstY
+ height), new Paint());
}


public final static int fixTransparentPixel(int pixel) {
// We don't use semitransparent pixel if the phone only support for full
// transparency and full opacity.
if (numAlphaLevel_ > 2 && (pixel & 0xff000000) != 0)
return (pixel & 0x00ffffff) + DEFAULT_TRANSPARENCY;
else
return pixel;
}


/**
* Given an image, assign transparency value to its non-background pixels (background pixels are pixels that are
* completely transparent).
*
* @param transparency
* 255 == totally opaque.
*/
public final static Bitmap fixTransparentImage(Bitmap img) throws Exception {
if (null == img)
return null;
int width = img.getWidth();
int height = img.getHeight();
int sz = width * height;
int[] rgb = new int[sz];
// Params: (rgb, offset, scanlength, x, y, width, height)
// rgbData[offset + (a - x) + (b - y) * scanlength] = P(a, b);
img.getPixels(rgb, 0, width, 0, 0, width, height);
for (int i = 0; i < sz; ++i) {
rgb[i] = fixTransparentPixel(rgb[i]);
}
img = Bitmap.createBitmap(rgb, width, height, Bitmap.Config.RGB_565);
return img;
}


/*
* Check if the image is over 4kB or not.
*
* @param name the full name with a path of an image file.
*
* @return
*/
// private final final static final boolean isImgBelow4KB(String name) {
// boolean isNotOver = ConfigManager.IMAGE_TRANSPARENCY;
// try {
// int imgSize = 0;
// InputStream is = null;
// is = new Object().getClass().getResourceAsStream(name);
// imgSize = is.available();
// if (imgSize < 1024 * 4){
// isNotOver = true;
// }
// } catch (Exception e) {
// printOutToConsole("LPUtils.isImgOver4KB(): " + e.toString());
// }
// return isNotOver;
// }


public final static String abbrevString(String title, Paint font, int maxWidth) {
if (title == null)
return "";
if (font.measureText(title) > maxWidth) {
int pos = nextLinePosition(title.toCharArray(), 0, font, maxWidth,
font.getTextWidths(ELLIPSIS, 0, ELLIPSIS.length, new float[ELLIPSIS.length]));
if (pos == -1)
return title;
else
return title.substring(0, pos) + "...";
} else
return title;
}


final static String appendDots(String src, Paint font, int maxWidth) {
if (src == null || font == null || maxWidth < 0) {
return null;
}
String dest = null;
dest = src + "...";
while (font.measureText(dest) > maxWidth) {
dest = src.substring(0, src.length() - 2) + "...";
}
return dest;
}


private final static char ELLIPSIS[] = { '.', '.', '.' };


public final static int getEllipsisWidth(Paint f) {
return f.getTextWidths(ELLIPSIS, 0, ELLIPSIS.length, new float[ELLIPSIS.length]);
}


/**
* Is this character whitespace?
*/
public final static boolean isWhitespace(char ch) {
return (ch == ' ' || ch == '\r' || ch == '\n' || ch == '\t');
}


/**
* Case insensitive string match
*
* @param ignoreCase
* if true, ignore case
* @param s1
* @param s2
*/
public final static boolean stringMatch(boolean ignoreCase, String s1, String s2) {
int cmplen = Math.max(s1.length(), s2.length());
if ((s1 == null) || (s2 == null)) {
return false;
}
return s1.regionMatches(true, 0, s2, 0, cmplen);
}


/**
* Given a starting position in a string, return the next position that this string should be split if it cannot fit
* within the given width. If it does not fit, we will include an ellipsis at the end to indicate broken line. If it
* does fit, we return -1.
*/
public final static int nextLinePosition(char[] str, int pos, Paint f, int maxWidth, int ellWidth) {
int strWidth = 0;
while (pos < str.length) {
if (str[pos] == '\n') {
return pos;
}
strWidth += f.measureText(String.valueOf(str[pos]));
if (strWidth + ellWidth > maxWidth) {
// If the rest of string can fit instead of the ellipsis, put it
// there.
// int tmp = f.getTextWidths(str, pos + 1, str.length - pos - 1,
// new float[str.length - pos - 1]);
int tmp = (int) f.measureText(str, pos + 1, str.length - pos - 1);
if (strWidth + tmp <= maxWidth) {
return -1;
} else {
return pos;
}
}
++pos;
}
return -1;
}


/**
* Starting from pos in str, find the longest string that fits in maxLineWidth. If doesn't fit, break the line by
* hyphenation or at a line break point.
*
* If newLine is true, we are starting from a new line and should get rid of initial white spaces.
*
* Returns the position of the next character to be scanned in str after this line break.
*/
public final static int nextLineLayout(char[] str, int pos, Paint f, int maxLineWidth, int hyphenWidth,
int[] linebreak, boolean newLine) {
int strWidth = 0;
int startPos = pos;
int lastBreakPoint = pos;


// Filter out initial white spaces at start of a line.
if (newLine) {
while (pos < str.length && (str[pos] == ' ' || str[pos] == '\t'))
++pos;
}


linebreak[LBI_START] = pos;
while (pos < str.length) {
boolean punct = false;
switch (str[pos]) {
// NOTE: don't recognize CR because in XML, only <br> or <p> should
// matter.
case '\n':
// Insert a newline.
linebreak[LBI_BREAK] = pos - 1;
linebreak[LBI_NEXT] = pos + 1;
linebreak[LBI_TYPE] = LB_SKIP;
return pos + 1;
case '<': {
// Look ahead to see if we have a <p>, <br>, <p/>, <br/>, </p>,
// </br>, <b> <tr> <td>
// XXX We ignore complex cases, such as newlines are inserted
// into tags.
// NOTE: the 32 limit is an arbitrary one
int endPos = pos;
while (endPos < (str.length - 1) && endPos - pos < 8) {
++endPos;
if (str[endPos] == '>') {
int pp1 = pos + 1;
int pp2 = pos + 2;
int pp3 = pos + 3;
char ch_pp1 = Character.toLowerCase(str[pp1]);
if (ch_pp1 == 'p' && (pp2 == endPos || str[pp2] == '/' || str[pp2] == ' ')) {
linebreak[LBI_BREAK] = pos - 1;
linebreak[LBI_NEXT] = endPos + 1;
linebreak[LBI_TYPE] = LB_PARAGRAPH; // Paragraph
return endPos + 1;
} else if (ch_pp1 == 'b'
&& (pp2 == endPos || (Character.toLowerCase(str[pp2]) == 'r' && (pp3 == endPos
|| str[pp3] == '/' || str[pp3] == ' ')))) {
linebreak[LBI_BREAK] = pos - 1;
linebreak[LBI_NEXT] = endPos + 1;
// Only add newline if this is a br.
linebreak[LBI_TYPE] = (pp2 == endPos) ? LB_SKIP : LB_NEWLINE;
return endPos + 1;
} else if (ch_pp1 == '/' || ch_pp1 == 'i' || ch_pp1 == 'e' || ch_pp1 == 's' || ch_pp1 == 'c'
|| ch_pp1 == 't' || ch_pp1 == 'h') {


// Ignore <em>, <strong>, <center>
// Ignore all kinds of end tags.
linebreak[LBI_BREAK] = pos - 1;
linebreak[LBI_NEXT] = endPos + 1;
linebreak[LBI_TYPE] = LB_SKIP;
return endPos + 1;
}
}
}
// XXX FIXME: Ignore <a href=...> and <font ...>, <a target...>,
// <a title...>, <a rel...> here. We will capture the hyper link
// and tie it to the link body later.
char ch_pp1 = Character.toLowerCase(str[pos + 1]);
if (str.length - pos >= 5 && (ch_pp1 == 'a' || ch_pp1 == 'f')) {
if (ch_pp1 == 'a') {
// Skip spaces between a and href
endPos = pos + 2;
while (endPos < str.length && str[endPos] == ' ')
++endPos;
} else {
endPos = pos + 1;
}
if (str.length - endPos > 3) {
ch_pp1 = Character.toLowerCase(str[endPos]);
char ch_pp2 = Character.toLowerCase(str[endPos + 1]);
char ch_pp3 = Character.toLowerCase(str[endPos + 2]);
char ch_pp4 = Character.toLowerCase(str[endPos + 3]);
if ((ch_pp1 == 'h' && ch_pp2 == 'r' && ch_pp3 == 'e' && ch_pp4 == 'f')
|| (ch_pp1 == 'f' && ch_pp2 == 'o' && ch_pp3 == 'n' && ch_pp4 == 't')
|| (ch_pp1 == 't' && ch_pp2 == 'a' && ch_pp3 == 'r' && ch_pp4 == 'g')
|| (ch_pp1 == 't' && ch_pp2 == 'i' && ch_pp3 == 't' && ch_pp4 == 'l')
|| (ch_pp1 == 'r' && ch_pp2 == 'e' && ch_pp3 == 'l')) {
// Ignore everything, including newline, till next
// '>'
while (endPos < str.length && str[endPos] != '>')
++endPos;
}
}
linebreak[LBI_BREAK] = pos - 1;
if (endPos + 1 < str.length)
linebreak[LBI_NEXT] = endPos + 1;
else
linebreak[LBI_NEXT] = str.length - 1;
linebreak[LBI_TYPE] = LB_SKIP;
return endPos + 1;
}
// XXX FIXME: Ignore <p class=...> & <img src=...>,<span ...>
// <lp...> , </lp:...>, <table > <div>here. We will capture the
// hyper link
// and tie it to the link body later.
if (str.length - pos >= 8
&& (ch_pp1 == 'p' || ch_pp1 == 'i' || ch_pp1 == 'l' || ch_pp1 == 's' || ch_pp1 == 't' || ch_pp1 == 'd')
|| ch_pp1 == '/') {
endPos = pos + 2;
// Ignore everything, including newline, till next '>'
while (endPos < str.length && str[endPos] != '>')
++endPos;


linebreak[LBI_BREAK] = pos - 1;
linebreak[LBI_NEXT] = endPos + 1;
linebreak[LBI_TYPE] = LB_SKIP;
return endPos + 1;
}


// For tags that we do not recognize, fall through.
}
case ' ':
case '\t':
lastBreakPoint = pos;
// fall through
default:
// Check one more character to see if it fits current string. If
// not,
// try to break at the last line break point. If that is too far
// away,
// add a hyphen at this place.
strWidth += f.measureText(String.valueOf(str[pos]));
if (strWidth >= maxLineWidth) {
// This was meant for hyphenation. When we insert a newline,
// can do that right at the starting point.
if (lastBreakPoint == startPos) {
lastBreakPoint = (pos == startPos) ? pos : (pos - 1);
}
linebreak[LBI_BREAK] = lastBreakPoint - 1;
linebreak[LBI_NEXT] = lastBreakPoint;
linebreak[LBI_TYPE] = LB_NEWLINE;
return lastBreakPoint;
}
}
++pos;
}
return -1;
}


/**
* Starting from pos in str, find the longest string that fits in maxLineWidth.
*
* Don't need to check
* <p>
* , <br>
* ,
* <p/>
* , <br/>
* ,
* </p>
* , </br>, <b>
* <tr>
* <td>again. They should be parsed by HTML.
*/
public final static int getLineEndIndex(char[] chars, int pos, Paint f, int LineWidth, int[] linebreak,
boolean newLine, boolean isTrimHeadBlank, boolean isBreakWord) {
if (chars == null || f == null)
return -1;
int strWidth = 0;
int startPos = pos;
int lastBreakPoint = pos;
// Filter out initial white spaces at start of a line.
if (newLine) {
if (isTrimHeadBlank) {
while (pos < chars.length && (chars[pos] == ' ' || chars[pos] == '\t'))
++pos;
} else {
while (pos < chars.length && chars[pos] == '\t')
++pos;
}
}
linebreak[LBI_START] = pos;
while (pos < chars.length) {
switch (chars[pos]) {
// NOTE: don't recognize CR because in XML, only <br> or <p> should
// matter.
case '\n':
chars[pos] = ' ';
return pos;
case ' ':
case '.':
case '/':
case '\t':
lastBreakPoint = pos + 1;
default:
// Check one more character to see if it fits current string. If
// not,
// try to break at the last line break point.
strWidth += f.measureText(String.valueOf(chars[pos]));
if (strWidth > LineWidth) {
if (isBreakWord) {
return pos - 1;
} else {
// It is possible that a word's width bigger than line
// width.
if (lastBreakPoint == startPos && pos > startPos && newLine) {
return pos - 1;
} else {
return lastBreakPoint;
}
}
}
}
++pos;
}
return chars.length;
}


public final static boolean isPunct(char ch) {
switch (ch) {
case '.':
case ',':
case '?':
case '!':
case '\'':
case '"':
case ':':
case ';':
case '-':
return true;
}
return false;
}


public final static String escapeHTML(String str) {
if (str == null)
return null;
StringBuffer sb = new StringBuffer();
int num = str.length();
for (int i = 0; i < num; i++) {
char ch = str.charAt(i);
switch (ch) {
case '<':
sb.append("&lt;");
break;
case '>':
sb.append("&gt;");
break;
case '&':
sb.append("&amp;");
break;
case '"':
sb.append("&quot;");
break;
case ' ':
sb.append("&nbsp;");
break;
default:
sb.append(ch);
break;
}
}
return sb.toString();
}


/**
* Unescape a HTML string by filtering out &...; sequences, including &#<numbers>;. We do not consider the case
* where one sequence is broken into multiple lines.
*/
public final static String unescapeHTML(String str) {
char[] src = str.toCharArray();
char[] dest = new char[src.length];
boolean foundAmber = false;
int escapeIdx = -1;
int dstIdx = 0;
int j;
int ch;


for (int i = 0; i < src.length; i++) {
switch (src[i]) {
case '&':
// we should not miss the case &aaa&.
while (escapeIdx > 0 && escapeIdx < i) {
dest[dstIdx++] = src[escapeIdx++];
}
escapeIdx = i;
break;
case ';':
if (escapeIdx >= 0) {
if (src[escapeIdx + 1] == '#') {
ch = 0;
for (j = escapeIdx + 2; j < i; ++j) {
if (src[j] < '0' || src[j] > '9') {
ch = -1;
break;
} else {
ch *= 10;
ch += src[j] - '0';
}
}
} else {
int pp1 = escapeIdx + 1;
int pp2 = escapeIdx + 2;
int pp3 = escapeIdx + 3;
int pp4 = escapeIdx + 4;
int pp5 = escapeIdx + 5;
if (src[pp1] == 'q' && src[pp2] == 'u' && src[pp3] == 'o' && src[pp4] == 't' && pp5 == i)
ch = '"';
else if (src[pp1] == 'a' && src[pp2] == 'm' && src[pp3] == 'p' && pp4 == i)
ch = '&';
else if (src[pp1] == 'l' && src[pp2] == 't' && pp3 == i)
ch = '<';
else if (src[pp1] == 'g' && src[pp2] == 't' && pp3 == i)
ch = '>';
else if (src[pp1] == 'n' && src[pp2] == 'b' && src[pp3] == 's' && src[pp4] == 'p' && pp5 == i)
ch = ' ';
else
ch = -1;
if (ch != -1) {
dest[dstIdx++] = (char) ch;
escapeIdx = -1;
break;
}
}
} else
ch = -1;


// Replace the Html Special Characters likes &#<numbers>.
if (ch >= 0) {
switch (ch) {
case 123:
ch = '{';
break;
case 125:
ch = '}';
break;
case 133:
for (int k = 0; k < 3; k++)
dest[dstIdx++] = '.';
ch = -1;
break;
case 146:
ch = '\'';
break;
case 147:
case 148:
ch = '"';
break;
case 151:
ch = '-';
break;
default:
ch = ' ';
break;
}
if (ch != -1)
dest[dstIdx++] = (char) ch;
} else {
// If current charactor is only a characters ";" ,
// not a Html Special Characters, we copy it in dest.
if (escapeIdx < 0)
dest[dstIdx++] = src[i];
else {
for (j = escapeIdx; j <= i; ++j)
dest[dstIdx++] = src[j];
}
}
escapeIdx = -1;
break;
default:
if (escapeIdx < 0)
dest[dstIdx++] = src[i];
else if (escapeIdx > 0 && ((i - escapeIdx) > 5)) {
for (int k = escapeIdx; k <= i; k++) {
dest[dstIdx++] = src[k];
}
escapeIdx = -1;
}
break;
}
}


return String.valueOf(dest, 0, dstIdx);
}


/**
* non-ASCII characters are encoded as: first using the UTF-8 algorithm to encode to a sequence of 2 or 3 bytes,
* then each of these bytes is encoded as "%xx".
*/
public final static String escapeURIComponent(String str) {
printOutToConsole("escapeURIComponent " + str);
if (str == null)
return null;
StringBuffer sbuf = new StringBuffer();
int ch;
int len = str.length();
for (int i = 0; i < len; i++) {
ch = str.charAt(i);
if ('A' <= ch && ch <= 'Z') {
sbuf.append((char) ch);
} else if ('a' <= ch && ch <= 'z') {
sbuf.append((char) ch);
} else if ('0' <= ch && ch <= '9') {
sbuf.append((char) ch);
} else if (ch == '-' || ch == '_' || ch == '.' || ch == '!' || ch == '~' || ch == '*' || ch == '\''
|| ch == '(' || ch == ')') {
sbuf.append((char) ch);
} else if (ch < 0x0F) {
sbuf.append('%');
sbuf.append('0');
sbuf.append(Integer.toHexString(ch));
} else if (ch < 0x7F) {
sbuf.append('%');
sbuf.append(Integer.toHexString(ch));
} else if (ch <= 0x07FF) { // non-ASCII characters and value <=
// 0x7FF
sbuf.append('%');
sbuf.append(Integer.toHexString(0xc0 | (ch >> 6)));
sbuf.append('%');
sbuf.append(Integer.toHexString(0x80 | (ch & 0x3F)));
} else { // non-ASCII characters and value <= 0xFFFF
sbuf.append('%');
sbuf.append(Integer.toHexString(0xe0 | (ch >> 12)));
sbuf.append('%');
sbuf.append(Integer.toHexString(0x80 | ((ch >> 6) & 0x3F)));
sbuf.append('%');
sbuf.append(Integer.toHexString(0x80 | (ch & 0x3F)));
}
}
return sbuf.toString();
}


public final static String unescapeURIComponent(String url) {
if (url == null)
return null;
StringBuffer sbuf = new StringBuffer();
int len = url.length();
int ch;
int b;
int total = 0;
int more = -1;
int hb;
int lb;
for (int i = 0; i < len; i++) {
switch (ch = url.charAt(i)) {
case '%':
ch = url.charAt(++i);
hb = (Character.isDigit((char) ch) ? ch - '0' : 10 + Character.toLowerCase((char) ch) - 'a') & 0xF;
ch = url.charAt(++i);
lb = (Character.isDigit((char) ch) ? ch - '0' : 10 + Character.toLowerCase((char) ch) - 'a') & 0xF;
b = (hb << 4) | lb;
break;
default:
b = ch;
}
// Decode byte b as UTF-8, sumb collects incomplete chars
if ((b & 0xc0) == 0x80) {
total = (total << 6) | (b & 0x3f);
if (--more == 0)
sbuf.append((char) total);
} else if ((b & 0x80) == 0x00) {
sbuf.append((char) b);
} else if ((b & 0xe0) == 0xc0) {
total = b & 0x1f;
more = 1;
} else if ((b & 0xf0) == 0xe0) {
total = b & 0x0f;
more = 2;
} else if ((b & 0xf8) == 0xf0) {
total = b & 0x07;
more = 3;
} else if ((b & 0xfc) == 0xf8) {
total = b & 0x03;
more = 4;
} else {
total = b & 0x01;
more = 5;
}
}
return sbuf.toString();
}


/**
* Convert a string of double number to an integer, assuming the number is a coordinate.
*/
public final static int strCoordToInt(String strDouble) {
char[] src = strDouble.toCharArray();
StringBuffer dst = new StringBuffer();
int digitsAfterDot = 0;
boolean dotFound = false;
for (int i = 0; i < src.length && digitsAfterDot < 6; i++) {
if (src[i] != '.') {
dst.append(src[i]);
if (dotFound) {
++digitsAfterDot;
}
} else {
dotFound = true;
}
}
// multiply by 1000000
for (int i = digitsAfterDot; i < 6; i++) {
dst.append('0');
}
return Integer.parseInt(dst.toString());
}


/**
* Convert an integer coordinate into a float string.
*/
public final static String intToFloatCoord(int coord) {
StringBuffer buf = new StringBuffer();
buf.append(coord);
buf.insert(buf.length() - 6, '.');
return buf.toString();
}


/**
* Parse a ISO8601 date string and return it in a calendar object. Return UTC time.
*/
public final static long parseISO8601(String text) throws Exception {
printOutToConsole(text);


// Example date string: 2006-11-29T15:30:00.000-08:00
int idx = text.indexOf('T');
if (idx == -1) {
// Invalid date
throw new IOException("错误的数据格?");
}
String date = text.substring(0, idx);
int idx2 = text.indexOf('-', ++idx);
String time;
if (idx2 == -1) {
time = text.substring(idx);
} else {
time = text.substring(idx, idx2);
}


idx = date.indexOf('-');
int year = Integer.parseInt(date.substring(0, idx));
idx2 = date.indexOf('-', ++idx);
int month = Integer.parseInt(date.substring(idx, idx2));
int day = Integer.parseInt(date.substring(++idx2));


idx = time.indexOf(':');
int hour = Integer.parseInt(time.substring(0, idx));
idx2 = time.indexOf(':', ++idx);
int min = Integer.parseInt(time.substring(idx, idx2));
// The separater between seconds and time offset field can be 'Z' for
// standard time,
// or +/- for time zone offset.
int idx3 = time.indexOf('+', ++idx2);
String zoneString = null;
int zoneOffset = 0; // time zone offset, in seconds
if (idx3 == -1) {
idx3 = time.indexOf('-', idx2);
} else {
zoneString = time.substring(idx3 + 1);
zoneOffset = 1;
}
if (idx3 == -1) {
idx3 = time.indexOf('Z', idx2);
} else {
zoneString = time.substring(idx3 + 1);
zoneOffset = -1;
}
if (idx3 == -1) {
idx3 = time.length();
} else if (zoneString != null) {
int idx4 = zoneString.indexOf(':', 0);
if (idx4 != -1) {
int zoneHour;
int zoneMin;
try {
zoneHour = Integer.parseInt(zoneString.substring(0, idx4));
zoneMin = Integer.parseInt(zoneString.substring(idx4 + 1));
zoneOffset *= zoneHour * 3600 + zoneMin * 60;
} catch (Exception ignored) {
zoneOffset = 0;
}
}
}
int sec = 0;
if (idx3 > idx2) {
// Filter out sub-second component
int idx4 = time.indexOf('.', idx2);
if (idx4 != -1)
idx3 = idx4;
sec = Integer.parseInt(time.substring(idx2, idx3));
}


// Make a calendar time assuming that is UTC, then we'll make time zone
// adjustment from UTC seconds.
Calendar updatedDate = Calendar.getInstance();
updatedDate.set(Calendar.YEAR, year);
updatedDate.set(Calendar.MONTH, month - 1); // NOTE: month starts from
// 0??
updatedDate.set(Calendar.DAY_OF_MONTH, day); // Day start from 1??
updatedDate.set(Calendar.HOUR_OF_DAY, hour);
updatedDate.set(Calendar.MINUTE, min);
updatedDate.set(Calendar.SECOND, sec);
updatedDate.set(Calendar.MILLISECOND, 0);
printOutToConsole("date: " + year + "-" + month + "-" + day + " " + hour + ":" + min + ":" + sec + " time "
+ updatedDate.getTime());
printOutToConsole("timezone offset " + zoneOffset);
return updatedDate.getTime().getTime() + zoneOffset * 1000;
}


/**
* Displays a UTC time (in milliseconds) as MM/DD-HH:MM
*/
public final static void formatTimeString(long utc, StringBuffer str) {
Calendar cal = Calendar.getInstance();
cal.setTime(new Date(utc));
str.append(cal.get(Calendar.MONTH) + 1); // NOTE: month starts from 0
str.append("/");
str.append(cal.get(Calendar.DAY_OF_MONTH));
str.append("-");
str.append(cal.get(Calendar.HOUR_OF_DAY));
str.append(":");
str.append(cal.get(Calendar.MINUTE));
}


/**
* Displays a UTC time in milliseconds as YYYY/MM/DD
*/
public final static void formatDateString(long utc, StringBuffer str) {
Calendar cal = Calendar.getInstance();
cal.setTime(new Date(utc));
str.append(cal.get(Calendar.YEAR));
str.append("/");
str.append(cal.get(Calendar.MONTH) + 1); // NOTE: month starts from 0
str.append("/");
str.append(cal.get(Calendar.DAY_OF_MONTH));
}


/**
* Display a UTC time as format hh:mm am/pm
*/
public final static void fromatTimeAmPm(long utc, StringBuffer str) {
Calendar cal = Calendar.getInstance();
cal.setTime(new Date(utc));
int hour = cal.get(Calendar.HOUR);
int minu = cal.get(Calendar.MINUTE);
if (hour < 10)
str.append("0");
str.append(hour);
str.append(":");
if (minu < 10)
str.append("0");
str.append(minu);
if (cal.get(Calendar.AM_PM) == 0)
str.append(" AM");
else
str.append(" PM");
}


/**
* Parse simple state response XMLs from server and retrieve attributes from it. Used by UserManager, PoiRepository
* (add/remove POI), etc.
*/
public final static String getXMLResponseAttribute(String reply, String attr, int startIndex, char matchCh) {
int start = reply.indexOf(attr, startIndex);
if (start < 0)
return null;
start += attr.length();
int end = reply.indexOf(matchCh, start);
if (end > start) {
String s = reply.substring(start, end);
return s;
}
return null;
}


/**
* Check the email address whether is valid.
*/
public final static boolean checkEmail(String emailAdd) {
int length = emailAdd.length();
int temp1 = emailAdd.indexOf("@");
int temp2 = emailAdd.indexOf(".");


// temp1 > 1 means in this email address contains an “@?and there is a
// user’s name before it.
// temp2 != -1 means in this email address contains an "."
// (length - temp1 > 3) means after “@?contains at least one letter
// except ??
// (length - temp2 > 1) means "." is not the last letter
if (temp1 > 1 && temp2 != -1 && (length - temp1 > 3) && (length - temp2 > 1)) {
return true;
} else
return false;
}


/*
* A Java implementation of the Secure Hash Algorithm, SHA-1, as defined in FIPS PUB 180-1 Copyright (C) Sam Ruby
* 2004 All rights reserved
*
* Based on code Copyright (C) Paul Johnston 2000 - 2002. See http://pajhome.org.uk/site/legal.html for details.
*
* Converted to Java by Russell Beattie 2004 Base64 logic and inlining by Sam Ruby 2004 Bug fix correcting single
* bit error in base64 code by John Wilson
*
* BSD License
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following
* disclaimer. 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.
*
* Neither the name of the author nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* 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.
*/


// /*
// * Bitwise rotate a 32-bit number to the left
// */
// private final final static int rol(int num, int cnt) {
// return (num << cnt) | (num >>> (32 - cnt));
// }
/*
* Take a string and return the base64 representation of its SHA-1.
*/
public final static String sha1(String str) throws Exception {


// Convert a string to a sequence of 16-word blocks, stored as an array.
// Append padding bits and the length, as described in the SHA1 standard


byte[] x = str.getBytes("UTF-8");
int[] blks = new int[(((x.length + 8) >> 6) + 1) * 16];
int i;


for (i = 0; i < x.length; i++) {
blks[i >> 2] |= x[i] << (24 - (i % 4) * 8);
}


blks[i >> 2] |= 0x80 << (24 - (i % 4) * 8);
blks[blks.length - 1] = x.length * 8;


// calculate 160 bit SHA1 hash of the sequence of blocks


int[] w = new int[80];


int a = 1732584193;
int b = -271733879;
int c = -1732584194;
int d = 271733878;
int e = -1009589776;
int num;


for (i = 0; i < blks.length; i += 16) {
int olda = a;
int oldb = b;
int oldc = c;
int oldd = d;
int olde = e;


for (int j = 0; j < 80; j++) {
if (j < 16) {
w[j] = blks[i + j];
} else {
num = w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16];
w[j] = ((num << 1) | (num >>> (32 - 1)));
}
int t = ((a << 5) | (a >>> (32 - 5)))
+ e
+ w[j]
+ ((j < 20) ? 1518500249 + ((b & c) | ((~b) & d)) : (j < 40) ? 1859775393 + (b ^ c ^ d)
: (j < 60) ? -1894007588 + ((b & c) | (b & d) | (c & d)) : -899497514 + (b ^ c ^ d));
e = d;
d = c;
c = ((b << 30) | (b >>> (32 - 30))); // rol(b, 30);
b = a;
a = t;
}


a = a + olda;
b = b + oldb;
c = c + oldc;
d = d + oldd;
e = e + olde;
}


// Convert 160 bit hash to base64
int[] words = { a, b, c, d, e, 0 };
byte[] base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".getBytes();
byte[] result = new byte[28];
for (i = 0; i < 27; i++) {
int start = i * 6;
int word = start >> 5;
int offset = start & 0x1f;


if (offset <= 26) {
result[i] = base64[(words[word] >> (26 - offset)) & 0x3F];
} else if (offset == 28) {
result[i] = base64[(((words[word] & 0x0F) << 2) | ((words[word + 1] >> 30) & 0x03)) & 0x3F];
} else {
result[i] = base64[(((words[word] & 0x03) << 4) | ((words[word + 1] >> 28) & 0x0F)) & 0x3F];
}
}
result[27] = '=';


return new String(result);
}


public final static Bitmap bilinearResample(Bitmap oriImg, int newWidth, int newHeight) {
return bilinearResample(oriImg, newWidth, newHeight, WHITE);
}


/**
* Function for scale an image from a large to a smaller size, then return a new image with new size predefined.
*/
public final static Bitmap bilinearResample(Bitmap oriImg, int newWidth, int newHeight, int bgColor) {
int oldW = oriImg.getWidth();
int oldH = oriImg.getHeight();


int[] ori_rgb = new int[oldW * oldH];
int[] des_rgb = new int[newWidth * newHeight];


oriImg.getPixels(ori_rgb, 0, oldW, 0, 0, oldW, oldH);


int newIndex = 0;
// draw each pixel in the new image
for (int i = 1; i <= newHeight; i++) {
// generate the y calculation variables
int interplY = (i - 1) * oldH / newHeight;
int calcY = (i - 1) * oldH % newHeight;


for (int j = 1; j <= newWidth; j++) {
// generate the x calculation variables
int interplX = (j - 1) * oldW / newWidth;
int calcX = (j - 1) * oldW % newWidth;


int theColour1 = ori_rgb[(interplX) + (interplY) * oldW];
int theColour2 = ori_rgb[(interplX + 1) + (interplY) * oldW];
int theColour3 = ori_rgb[(interplX) + (interplY + 1) * oldW];
int theColour4 = ori_rgb[(interplX + 1) + (interplY + 1) * oldW];


// calculate the new colour
int alpha1 = (theColour1 >> 24 & 0xFF) * (newHeight - calcY) / newHeight + (theColour3 >> 24 & 0xFF)
* calcY / newHeight;
int alpha2 = (theColour2 >> 24 & 0xFF) * (newHeight - calcY) / newHeight + (theColour4 >> 24 & 0xFF)
* calcY / newHeight;
int newAlpha = isOutofColor(alpha1 * (newWidth - calcX) / newWidth + alpha2 * calcX / newWidth);
int newColor1r = (theColour1 >> 16 & 0xFF) * (newHeight - calcY) / newHeight
+ (theColour3 >> 16 & 0xFF) * calcY / newHeight;
int newColor2r = (theColour2 >> 16 & 0xFF) * (newHeight - calcY) / newHeight
+ (theColour4 >> 16 & 0xFF) * calcY / newHeight;
int newColorr = isOutofColor(newColor1r * (newWidth - calcX) / newWidth + newColor2r * calcX / newWidth);
int newColor1g = (theColour1 >> 8 & 0xFF) * (newHeight - calcY) / newHeight + (theColour3 >> 8 & 0xFF)
* calcY / newHeight;
int newColor2g = (theColour2 >> 8 & 0xFF) * (newHeight - calcY) / newHeight + (theColour4 >> 8 & 0xFF)
* calcY / newHeight;
int newColorg = isOutofColor(newColor1g * (newWidth - calcX) / newWidth + newColor2g * calcX / newWidth);
int newColor1b = (theColour1 & 0xFF) * (newHeight - calcY) / newHeight + (theColour3 & 0xFF) * calcY
/ newHeight;
int newColor2b = (theColour2 & 0xFF) * (newHeight - calcY) / newHeight + (theColour4 & 0xFF) * calcY
/ newHeight;
int newColorb = isOutofColor(newColor1b * (newWidth - calcX) / newWidth + newColor2b * calcX / newWidth);
int newColor = ((newAlpha & 0xFF) << 24) | ((newColorr & 0xFF) << 16) | ((newColorg & 0xFF) << 8)
| (newColorb & 0xFF);


// Set this pixel into the new image
des_rgb[newIndex++] = newColor;
}
}


Bitmap desImage = null;
desImage = Bitmap.createBitmap(des_rgb, newWidth, newHeight, Bitmap.Config.RGB_565);
// 缩放图片
desImage = Bitmap.createScaledBitmap(desImage, newWidth, newHeight, true);
if (desImage == null)
desImage = oriImg;
return desImage;
}


// it's used by the function bilinearResample().
final static int isOutofColor(int color) {
if (color < 0)
color = 0;
if (color > 255)
color = 255;
return color;
}


/**
* If we are on low memory or the photo can not be loaded, we will show a red cross in the photo frame.
*/
final static void createImageLoadFail(Canvas canvas) {
Paint paint = new Paint();
paint.setTypeface(Typeface.DEFAULT);
int wh = (int) (4 * paint.getTextSize());
canvas.drawRGB(0, 0, 0);
canvas.drawRect(new Rect(0, 0, wh - 1, wh - 1), new Paint());
canvas.drawRGB(255, 0, 0);
int xStart = wh / 2 - 3;
int yStart = wh / 2 - 3;


canvas.drawLine(xStart, yStart, xStart + 6, yStart + 6, paint);
canvas.drawLine(xStart, yStart + 1, xStart + 6, yStart + 7, paint);
canvas.drawLine(xStart + 6, yStart, xStart, yStart + 6, paint);
canvas.drawLine(xStart + 6, yStart + 1, xStart, yStart + 7, paint);
}


final static boolean isInComponent(int x, int y, View c) {
if (c == null)
return false;
if (x < c.getLeft() || x > c.getLeft() + c.getWidth() || y < c.getTop() || y > c.getTop() + c.getHeight())
return false;
else
return true;
}


/**
* Divide the given string to paragraphs with the given font and width.
*
* @param strSource
* the source string
* @param font
* the font
* @param width
* the width of each line.
* @return the String array
*/
public final static String[] getParagraph(final String strSource, final Paint font, final int width) {
String[] strs = null;
if (strSource == null || font == null || width <= 0) {
return strs;
} else if (strSource.equals("")) {
strs = new String[] { "" };
return strs;
}
Vector<String> vector = new Vector<String>();
try {
String temp = strSource;
int i, j;
boolean isOver;
while (!temp.equals("")) {
isOver = false;
i = temp.indexOf("\n");
if (i == -1) {
i = temp.length();
isOver = font.measureText(temp) > width;
}
if (i > 0 && font.measureText(temp.substring(0, i)) > width) {
isOver = true;
}
if (isOver) {
// gets the critical point
while (font.measureText(temp.substring(0, i)) > width) {
i = i - 1;
}
}
vector.addElement(temp.substring(0, i));
if (i == temp.length()) {
temp = "";
} else {
if (temp.charAt(i) == '\n') {
temp = temp.substring(i + 1);
} else {
temp = temp.substring(i);
}
}
}
if (vector.size() > 0) {
strs = new String[vector.size()];
vector.copyInto(strs);
}
} catch (Exception e) {


printOutToConsole("getSubsection:" + e);
}
return strs;
}


/**
* Divide the given string to paragraphs with the given font and width.
*
* @param strSource
* the source string
* @param font
* the font
* @param width
* the width of each line.
* @return the String array
*/
public final static String[] getParagraph(final String strSource, final Paint font, final int width,
final String splitChars) {
String[] strs = null;
if (strSource == null || font == null || width <= 0) {
return strs;
} else if (strSource.equals("")) {
strs = new String[] { "" };
return strs;
}
Vector vector = new Vector(2);
try {
String temp = strSource;
int i, j;
boolean isOver;
while (!temp.equals("")) {
isOver = false;
i = temp.indexOf("\n");
if (i == -1) {
i = temp.length();
isOver = font.measureText(temp) > width;
}
if (i > 0 && font.measureText(temp.substring(0, i)) > width) {
isOver = true;
}
if (isOver) {
// gets the critical point
while (font.measureText(temp.substring(0, i)) > width) {
i = i - 1;
}
if (!splitChars.equals("")) {
j = i; // restore the last index of this line for maybe
// there is a long word over a line.
while (splitChars.indexOf(temp.charAt(i - 1)) == -1) {
i--;
if (i == 0) {
i = j; // crash a word, if it is needed.
break;
}
}
}
}
vector.addElement(temp.substring(0, i));
if (i == temp.length()) {
temp = "";
} else {
if (temp.charAt(i) == '\n') {
temp = temp.substring(i + 1);
} else {
temp = temp.substring(i);
}
}
}
if (vector.size() > 0) {
strs = new String[vector.size()];
vector.copyInto(strs);
}
} catch (Exception e) {


printOutToConsole("getSubsection:" + e);
}
return strs;
}


/**
* @param src
* source image.
* @param desW
* expected width
* @param desH
* expected height
* @param isBackgroundTrans
* makes the background transparent
* @param isTrans
* makes the image transparent
* @return Image
*/
// public final final static final Image scaleImage(Image src, int desW, int desH,
// boolean isBackgroundTrans, boolean isTrans) {
// Image desImg = null;
// try {
// int srcW = src.getWidth(); // source image width
// int srcH = src.getHeight(); // source image height
// int[] srcBuf = new int[srcW * srcH]; // source image pixel
// src.getRGB(srcBuf, 0, srcW, 0, 0, srcW, srcH);
// // compute interpolation table
// int[] tabY = new int[desH];
// int[] tabX = new int[desW];
// int sb = 0;
// int db = 0;
// int tems = 0;
// int temd = 0;
// int distance = srcH > desH ? srcH : desH;
// for (int i = 0; i <= distance; i++) { /* vertical direction */
// tabY[db] = sb;
// tems += srcH;
// temd += desH;
// if (tems > distance) {
// tems -= distance;
// sb++;
// }
// if (temd > distance) {
// temd -= distance;
// db++;
// }
// }
// sb = 0;
// db = 0;
// tems = 0;
// temd = 0;
// distance = srcW > desW ? srcW : desW;
// for (int i = 0; i <= distance; i++) { /* horizontal direction */
// tabX[db] = (short) sb;
// tems += srcW;
// temd += desW;
// if (tems > distance) {
// tems -= distance;
// sb++;
// }
// if (temd > distance) {
// temd -= distance;
// db++;
// }
// }
// // formation enlarge and shorten buffer pixel
// int[] desBuf = new int[desW * desH];
// int dx = 0;
// int dy = 0;
// int sy = 0;
// int oldy = -1;
// for (int i = 0; i < desH; i++) {
// if (oldy == tabY[i]) {
// System.arraycopy(desBuf, dy - desW, desBuf, dy, desW);
// } else {
// dx = 0;
// for (int j = 0; j < desW; j++) {
// desBuf[dy + dx] = srcBuf[sy + tabX[j]];
// dx++;
// }
// sy += (tabY[i] - oldy) * srcW;
// }
// oldy = tabY[i];
// dy += desW;
// }
// if (isTrans) {
// // int a= 100;//set the transparence of pixel 100
// for (int i = 0; i < desBuf.length; i++) {
// if (desBuf[i] == 0x00FFFFFF)
// continue;
// int alpha = ((desBuf[i] & 0xff000000) >>> 24) == 0 ? 0 : 100;
// desBuf[i] = ((alpha + 1) << 24) | (desBuf[i] & 0x00FFFFFF);
// }
// }
// if (isBackgroundTrans) {
// desImg = Image.createRGBImage(desBuf, desW, desH, true);
// } else {
// desImg = Image.createRGBImage(desBuf, desW, desH, false);
// }
// } catch (Exception ex) {
// LPUtils.printException(ex);
// desImg = null;
// }
// return desImg;
// }


/**
* @param strSrc
* @param strSepr
* @return
*/
public final static String[] string2Array(String strSrc, String strSepr) {
String[] astr = null;
try {
Vector vec = new Vector(5, 1);
str2Arr(strSrc, strSepr, vec);
vec.trimToSize();
astr = new String[vec.size()];
vec.copyInto(astr);
vec.removeAllElements();
} catch (Exception ex) {
}
return astr;
}


public final static void setPrint(Activity activity) {
if (getConfigStringFormAsset(activity, "isprintMessage").equalsIgnoreCase("true")) {
isPrintMessage_ = true;
}
setActivity(activity);
}


public final static void setActivity(Activity activity) {
// TODO Auto-generated method stub
activity_ = activity;
}


public final static Activity getActivity() {
return activity_;
}


private final static void str2Arr(String strSrc, String strSepr, Vector vec) throws Exception {
if (strSrc.indexOf(strSepr) == -1) {
vec.addElement(strSrc);
} else {
vec.addElement(strSrc.substring(0, strSrc.indexOf(strSepr)));
strSrc = strSrc.substring(strSrc.indexOf(strSepr) + strSepr.length());
str2Arr(strSrc, strSepr, vec);
}
}


// 将传入的字符串中的特殊字符予以替换,保证解析顺利进行或使已替换的字符串还?
public final static String insteadOfSpecillCharacter(String str, boolean isReplace) {
if ((null == str) || (str.equalsIgnoreCase("")))
return str;
String strTemp = str;
// 特殊字符?
String[] A = { "&" };
// 需要替换的字符
String[] substitute;
// 替换后的字符?
String[] B = { "***###" };
// 替换后的字符
String[] beReplaced;


if (isReplace) {
// 替换特殊字符串,方便解析
substitute = A;
beReplaced = B;
} else {
// 将特殊字符还?
substitute = B;
beReplaced = A;
}
int length = substitute.length;
for (int i = 0; i < length; i++) {
strTemp = strTemp.replace(substitute[i], beReplaced[i]);
}
return strTemp;
}


// 设置与是否获得焦?
// final final static public void setFocus(boolean isFocus, int keyCode, View view) {
// if (view instanceof LPTable) {
// LPTable temp = (LPTable) view;
// // temp.setFocus(isFocus, keyCode);
// } else {
// if (isFocus) {
// view.requestFocus();
// } else {
// view.clearFocus();
// }
// }
//
// }


/**
* @param obj
*/
public final static void printOutToConsole(Object obj) {
if (isPrintMessage_) {
if (obj instanceof String) {
printOutToConsole((String) obj);
} else if (obj instanceof byte[]) {
printOutToConsole((byte[]) obj);
} else {
System.out.println(obj);
}
}
}


/**
* @param s
*/
public final static void printOutToConsole(String s) {
if (isPrintMessage_) {
int length = s.length();
int offset = 3000;
if (length > offset) {// 解决报文过长,打印不全的问题?
int n = 0;
for (int i = 0; i < length; i += offset) {
n += offset;
if (n > length)
n = length;
System.err.println("Debug = " + s.substring(i, n));
}
} else {
System.err.println("Debug = " + s);
}
}
}


/**
* @param byts
*/
public final static void printOutToConsole(byte[] byts) {
if (isPrintMessage_) {
if (byts == null) {
return;
}
for (int i = 0; i < byts.length; i++) {
System.out.print("[" + i + "]" + " : \t");
System.out.println(byts[i]);
}
}
}


public final static void LogD(String tag, String msg) {
if (isPrintMessage_) {
android.util.Log.d(tag, msg);
}
}


public final static void printException(Exception e) {
if (isPrintMessage_) {
e.printStackTrace();
}
}


/**
* 检测服务端发过来的接口前面是否带有/,如果没有则自动加?提高程序健壮?
*
* @param url
* @return
*/
public final static String checkUrl(Object url) {
// TODO Auto-generated method stub
String tempString = url.toString().trim();
if (!tempString.startsWith("/"))
tempString = "/".concat(tempString);
return tempString;
}


/**
* Network Byte Order
*
* @param byts
* @param offset
* @return
*/
public final static int byteArrayToIntInNBO(byte[] byts, int offset) {
int intValue = 0;
for (int i = 0; i < 4; i++) {
int shift = (4 - 1 - i) * 8;
intValue += (byts[i + offset] & 0x000000FF) << shift;
}
return intValue;
}


/**
* Network Byte Order
*
* @param intValue
* @return
*/
public final static byte[] intToByteArrayInNBO(int intValue) {
byte[] byt = new byte[4];
for (int i = 0; i < 4; i++) {
byt[i] = (byte) (intValue >>> (24 - i * 8));
}
return byt;
}


/**
* @param firstBytes
* @param lastBytes
* @return
*/
public final static byte[] jogBytes(byte[]... byts) throws Exception {
if (byts.length == 0) {
return null;
}
ByteArrayOutputStream out = new ByteArrayOutputStream();
for (byte[] byt : byts) {
if (byt == null) {
continue;
}
out.write(byt);
}
try {
out.flush();
} catch (Exception e) {
printException(e);
}
byte[] result = out.toByteArray();
try {
out.close();
} catch (Exception e) {
printException(e);
}
out = null;
return result;
}


public final static String getStringFormAsset(Activity activity, String str) {
BufferedReader in = null;
try {
in = new BufferedReader(new InputStreamReader(activity.getAssets().open(str)), 8 * 1024);
String line;
StringBuilder buffer = new StringBuilder();
while ((line = in.readLine()) != null)
buffer.append(line).append('\n');
return buffer.toString();
} catch (IOException e) {
Utils.printException(e);
return "";
} finally {
if (in != null) {
try {
in.close();
in = null;
} catch (IOException e) {
// TODO Auto-generated catch block
printException(e);
}
}
}
}


/**
* 修正日期值的传输,将?”予以去除,月份日期小于10,则前面予以?
*
* @param value
* @return
*/
public final static String adjustDate(String value) {
// TODO Auto-generated method stub
if (value.contains("-")) {
String valueTemp = value;
String year = valueTemp.substring(0, valueTemp.indexOf("-"));
String month = valueTemp.substring(valueTemp.indexOf("-") + 1, valueTemp.lastIndexOf("-"));
String day = valueTemp.substring(valueTemp.lastIndexOf("-") + 1);
if (Integer.parseInt(month) < 10 && month.length() < 2)
month = "0".concat(month);
if (Integer.parseInt(day) < 10 && day.length() < 2)
day = "0".concat(day);
return year.concat(month).concat(day).replace("-", "");
}
return value;
}


/**
* 解读assets文件夹下的Config.txt文件信息
*
* @param activity
* @param tag
* 需要在该文件里面查找的key
* @return 文件中key对应的value
*/
public final static String getConfigStringFormAsset(Activity activity, String tag) {
if (configHm_ == null) {
initConfigStringFormAsset(activity);
}
String value = configHm_.get(tag);
return value == null ? "" : value;
}


/**
* 解读assets文件夹下的Config.txt文件信息
*
* @param activity
* @param tag
* 需要在该文件里面查找的key
* @return 文件中key对应的value
*/
private final static void initConfigStringFormAsset(Activity activity) {
//  只读取一次Config文件
if (null == activity)
return;
configHm_ = new HashMap<String, String>();
BufferedReader in = null;
try {
in = new BufferedReader(new InputStreamReader(activity.getAssets().open("Config.txt")), 1024);
String line;
String key;
String value;
while ((line = in.readLine()) != null) {
int index = line.indexOf(" ");
if (index != -1) {
key = line.substring(0, index);
value = line.substring(index).trim();// 去掉前面的空?
configHm_.put(key, value);
}
}


String str_lag = configHm_.get("jat_lag");
jat_lag = Integer.parseInt(str_lag);
} catch (Exception e) {
} finally {
if (in != null) {
try {
in.close();
in = null;
} catch (Exception e) {
// TODO Auto-generated catch block
printException(e);
}
}
}
}


public final static int getScaledValueX(float num) {
// TODO Auto-generated method stub
float numtemp = SCALEDATEX * num;
return (int) numtemp;
}


public final static int getFontSize(int size) {
size = (int) (size * SCALEDFONT);
return size;
}


public final static int getScaledValueY(float num) {
// TODO Auto-generated method stub
float numtemp = SCALEDATEY * num;
return (int) numtemp;
}


/**
*
* @param wRate
* 参照宽度
* @param hRate
*/
private final static void setScaledParams(float wRate, float hRate) {
// TODO Auto-generated method stub
SCALEDATEX = wRate;
SCALEDATEY = hRate;
}


// 计算界面宽高
public final static void calculateScreenSize(Activity activity) {
// 从Config配置文档中读取服务端xml的基准分辨率,该分辨率应时刻与服务端定义的模板标准分辨率一?
BenchmarkresolutionW_ = Integer.parseInt(getConfigStringFormAsset(activity, "BenchmarkresolutionW"));
BenchmarkresolutionH_ = Integer.parseInt(getConfigStringFormAsset(activity, "BenchmarkresolutionH"));


DisplayMetrics dm = new DisplayMetrics();
activity.getWindowManager().getDefaultDisplay().getMetrics(dm);
Component.SCREENWIDTH = dm.widthPixels;
// 该值为暂定值无实际意义,该值会在BaseView的onWindowFocusChanged方法中从新计算得?
// Component.SCREENHEIGHT = dm.heightPixels;
final float w = BenchmarkresolutionW_;
final float h = BenchmarkresolutionH_;
float wRate = dm.widthPixels / w;
float hRate = dm.heightPixels / h;
setScaledParams(wRate, hRate);
setBrHeight();
setMarginAndGap();
SCALEDFONT = 1;
int dw = dm.widthPixels;
int dh = dm.heightPixels;
float ds = dm.scaledDensity;


if (dw <= 240 && dh <= 320) {
if (ds != 0.75f) {
SCALEDFONT = 0.75f / ds;
}
} else if (dw <= 320 && dh <= 500) {
if (ds != 1f) {
SCALEDFONT = 1f / ds;
}
} else if (dw <= 480 && dh <= 900) {
if (ds != 1.5f) {
SCALEDFONT = 1.5f / ds;
}
} else if (dw <= 600) {
if (ds != 2f) {
SCALEDFONT = 2f / ds;
}
}
}


private static void setMarginAndGap() {
// TODO Auto-generated method stub
String tempString = getConfigStringFormAsset(getActivity(), "verticalMarginOfB");
if (null == tempString || tempString.equals(""))
tempString = "0";
LPLayout.VMB = getScaledValueY(Integer.parseInt(tempString));
printOutToConsole("Config设置的body框架纵向边距经过缩放后为:" + LPLayout.VMB);


tempString = getConfigStringFormAsset(getActivity(), "horizontalMarginOfB");
if (null == tempString || tempString.equals(""))
tempString = "0";
LPLayout.HMB = getScaledValueX(Integer.parseInt(tempString));
printOutToConsole("Config设置body框架水平边距经过缩放后为:" + LPLayout.HMB);


tempString = getConfigStringFormAsset(getActivity(), "verticalGapOfB");
if (null == tempString || tempString.equals(""))
tempString = "0";
LPLayout.VGB = getScaledValueY(Integer.parseInt(tempString));
printOutToConsole("Config设置的body框架子元素纵向间距经过缩放后为:" + LPLayout.VGB);


tempString = getConfigStringFormAsset(getActivity(), "horizontalGapOfB");
if (null == tempString || tempString.equals(""))
tempString = "0";
LPLayout.HGB = getScaledValueX(Integer.parseInt(tempString));
printOutToConsole("Config设置的body框架子元素横向间距经过缩放后为:" + LPLayout.HGB);


tempString = getConfigStringFormAsset(getActivity(), "verticalMarginOfF");
if (null == tempString || tempString.equals(""))
tempString = "0";
LPLayout.VMF = getScaledValueY(Integer.parseInt(tempString));
printOutToConsole("Config设置的form框架纵向边距经过缩放后为:" + LPLayout.VMF);


tempString = getConfigStringFormAsset(getActivity(), "horizontalMarginOfF");
if (null == tempString || tempString.equals(""))
tempString = "0";
LPLayout.HMF = getScaledValueX(Integer.parseInt(tempString));
printOutToConsole("Config设置的form框架水平边距经过缩放后为:" + LPLayout.HMF);


tempString = getConfigStringFormAsset(getActivity(), "verticalGapOfF");
if (null == tempString || tempString.equals(""))
tempString = "0";
LPLayout.VGF = getScaledValueY(Integer.parseInt(tempString));
printOutToConsole("Config设置的form框架子元素纵向间距经过缩放后为:" + LPLayout.VGF);


tempString = getConfigStringFormAsset(getActivity(), "horizontalGapOfF");
if (null == tempString || tempString.equals(""))
tempString = "0";
LPLayout.HGF = getScaledValueX(Integer.parseInt(tempString));
printOutToConsole("Config设置的form框架子元素横向间距经过缩放后为:" + LPLayout.HGF);


tempString = getConfigStringFormAsset(getActivity(), "verticalMarginOfD");
if (null == tempString || tempString.equals(""))
tempString = "0";
LPLayout.VMD = getScaledValueY(Integer.parseInt(tempString));
printOutToConsole("Config设置的div框架纵向边距经过缩放后为:" + LPLayout.VMD);


tempString = getConfigStringFormAsset(getActivity(), "horizontalMarginOfD");
if (null == tempString || tempString.equals(""))
tempString = "0";
LPLayout.HMD = getScaledValueX(Integer.parseInt(tempString));
printOutToConsole("Config设置的div框架水平边距经过缩放后为:" + LPLayout.HMD);


tempString = getConfigStringFormAsset(getActivity(), "verticalGapOfD");
if (null == tempString || tempString.equals(""))
tempString = "0";
LPLayout.VGD = getScaledValueY(Integer.parseInt(tempString));
printOutToConsole("Config设置的div框架子元素纵向间距经过缩放后为:" + LPLayout.VGD);


tempString = getConfigStringFormAsset(getActivity(), "horizontalGapOfD");
if (null == tempString || tempString.equals(""))
tempString = "0";
LPLayout.HGD = getScaledValueX(Integer.parseInt(tempString));
printOutToConsole("Config设置的div框架子元素横向间距经过缩放后为:" + LPLayout.HGD);


tempString = getConfigStringFormAsset(getActivity(), "verticalMarginOfT");
if (null == tempString || tempString.equals(""))
tempString = "0";
LPLayout.VMT = getScaledValueY(Integer.parseInt(tempString));
printOutToConsole("Config设置的td框架纵向边距经过缩放后为:" + LPLayout.VMT);


tempString = getConfigStringFormAsset(getActivity(), "horizontalMarginOfT");
if (null == tempString || tempString.equals(""))
tempString = "0";
LPLayout.HMT = getScaledValueX(Integer.parseInt(tempString));
printOutToConsole("Config设置的td框架水平边距经过缩放后为:" + LPLayout.HMT);


tempString = getConfigStringFormAsset(getActivity(), "verticalGapOfT");
if (null == tempString || tempString.equals(""))
tempString = "0";
LPLayout.VGT = getScaledValueY(Integer.parseInt(tempString));
printOutToConsole("Config设置的td框架子元素纵向间距经过缩放后为:" + LPLayout.VGT);


tempString = getConfigStringFormAsset(getActivity(), "horizontalGapOfT");
if (null == tempString || tempString.equals(""))
tempString = "0";
LPLayout.HGT = getScaledValueX(Integer.parseInt(tempString));
printOutToConsole("Config设置的td框架子元素横向间距经过缩放后为:" + LPLayout.HGT);
}


public static void setBrHeight() {
// TODO Auto-generated method stub
String tempString = getConfigStringFormAsset(getActivity(), "brHeight");
if (null == tempString || tempString.equals(""))
tempString = "0";
BRHEIGHT = getScaledValueY(Integer.parseInt(tempString));
printOutToConsole("Config设置的br节点高度经过缩放后为:" + BRHEIGHT);
}


public static int getBrHeight() {
return BRHEIGHT;
}


/**
* 获取手机的model型号
*
* @return
*/
public final static String getPhoneModel() {
String temp = android.os.Build.MODEL;
temp = temp.replace(" ", "").replace("-", "_").trim();
return temp;
}


public final static String getPhoneTarget() {
String temp = android.os.Build.DEVICE;
temp = temp.replace(" ", "").replace("-", "_").trim();
return temp;


}


public final static String getClientID() {
String temp = android.os.Build.ID;
temp = temp.replace(" ", "").replace("-", "_").trim();
return temp;
}


/**
* 获取界面分辨率并且组合成?
*
* @param activity
* @return
*/
public final static String getResolution(Activity activity) {
DisplayMetrics dm = new DisplayMetrics();
activity.getWindowManager().getDefaultDisplay().getMetrics(dm);
String w = String.valueOf(dm.widthPixels);
String h = String.valueOf(dm.heightPixels);
return w.concat("*").concat(h);
}


public final static Typeface getTypeFace(String string) {
Typeface tface = null;
try {
if (string.equalsIgnoreCase("bold")) {
tface = Typeface.defaultFromStyle(Typeface.BOLD);
} else if (string.equalsIgnoreCase("normal")) {
tface = Typeface.defaultFromStyle(Typeface.NORMAL);
} else {
tface = null;
}
} catch (Exception e) {
tface = null;
}
return tface;
}


/**
* 设置字体是否粗体
* */
private final static boolean getFontType(String string) {
if (string.equalsIgnoreCase("bold")) {
return true;
} else {
return false;
}
}


/** * 图片去色,返回灰度图片 * @param bmpOriginal 传入的图?* @return 去色后的图片 */
public final static Bitmap getGrayBitmap(Bitmap bmpOriginal) {
if (null == bmpOriginal)
return null;
int width, height;
height = bmpOriginal.getHeight();
width = bmpOriginal.getWidth();
Bitmap bmpGrayscale = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(bmpGrayscale);
Paint paint = new Paint();
ColorMatrix cm = new ColorMatrix();
cm.setSaturation(0);
ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
paint.setColorFilter(f);
c.drawBitmap(bmpOriginal, 0, 0, paint);
return bmpGrayscale;
}


/**
* @param activity
* @param fileName
* @param data
*/
public final static void updateFile(Activity activity, String fileName, byte[] data) {
try {
FileOutputStream fos = activity.openFileOutput(fileName, Activity.MODE_PRIVATE);
fos.write(new byte[] {}); // clear file.
fos.write(data);
fos.flush();
fos.close();
} catch (FileNotFoundException e) {
Utils.printException(e);
} catch (IOException e) {
Utils.printException(e);
} catch (Exception e) {
Utils.printException(e);
}


}


/**
* @param activity
* @param fullPathName
* @return
*/
public final static byte[] readFile(Activity activity, String fullPathName) {
byte[] buffer = null;
FileInputStream fis = null;
try {
File file = new File(fullPathName);
if (file.exists()) {
fis = activity.openFileInput(fullPathName);
int len = fis.available();
buffer = new byte[len];
fis.read(buffer);
fis.close();
}
} catch (FileNotFoundException e) {
printException(e);
} catch (IOException e) {
printException(e);
} catch (Exception e) {
printException(e);
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
}
}
}
return buffer;
}


public final static String getVersionName(Activity activity) {
try {
PackageManager pm = activity.getPackageManager();


PackageInfo pi;


pi = pm.getPackageInfo(activity.getPackageName(), PackageManager.GET_ACTIVITIES);
return pi.versionName;
} catch (NameNotFoundException e) {
// TODO Auto-generated catch block
Utils.printException(e);
return "1.0";
}


}


/**
* User-Agent string we use in all of our HTTP transactions. XXX DO NOTE CHANGE THIS!!
*/
public final static String makeUserAgent(String version) {
StringBuffer buf = new StringBuffer("LightPole/");
buf.append(version);
buf.append("/");
buf.append("android1.5");
return buf.toString();
}


// Get a code from data.
private final static int getCode(byte data[], int tree[]) {
int node = tree[0];
while (node >= 0) {
if (bitIndex == 0)
bitByte = (data[gIndex++] & 0xFF);
node = (((bitByte & (1 << bitIndex)) == 0) ? tree[node >> 16] : tree[node & 0xFFFF]);
bitIndex = (bitIndex + 1) & 0x7;
}
return (node & 0xFFFF);
}


/**
* 判断报文是否存在xml?如果没有则手动加?
*
* @param xml
* @return
*/
public final static String addXmlHead(String xml) {
if (xml.indexOf("<?xml") == -1) {
xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>".concat(xml);
}
return xml;
}


// get num bits from data. the num should not bigger than 32.
private final static int getBits(byte[] data, int num) {
int result = 0;
int i = 0;
if (bitIndex != 0) {
i = 8 - bitIndex;
result = bitByte >> bitIndex;
}
while (i < num) {
bitByte = data[gIndex++] & 0xFF;
result |= (bitByte << i);
i += 8;
}
bitIndex = (bitIndex + num) & 0x7;// calculate (bitIndex + num)%8
result &= (0xffffffff >>> (32 - num));
return result;
}


// It's used to decompress gzip data. Re. rfc1951 and rfc 1952.
public final static byte[] gunzip(byte[] gzipData) throws IOException {
// Check if the data is gzip format and if it is used "deflate"
// compression method.
if (gzipData[0] != 31 || gzipData[1] != -117)
throw new IOException("压缩数据格式错误!");
if (gzipData[2] != 8)
throw new IOException("压缩数据方法错误!");


// Skip the gzip data header.
byte flg = gzipData[3];
gIndex = 10;
bitIndex = 0;
bitByte = 0;
if ((flg & 4) != 0)
gIndex += getBits(gzipData, 16);
if ((flg & 8) != 0)
while (gzipData[gIndex++] != 0)
;
if ((flg & 16) != 0)
while (gzipData[gIndex++] != 0)
;
if ((flg & 2) != 0)
gIndex += 2;


int temp = gIndex;
gIndex = gzipData.length - 4;
// The size of the original input data
int size = getBits(gzipData, 16) | (getBits(gzipData, 16) << 16);
byte[] unzipData = new byte[size];
gIndex = temp;


int unzipIndex = 0;
bitIndex = 0;
bitByte = 0;
int lastBlock = 0; // 0 indicates have more block when 1 indicates it is
// the last block.
int type = 0;// 0 indicates uncompress data, 1 indicates use final final static
// Huffman, 2 indicates use dynamic Huffman.
while (lastBlock == 0) {
lastBlock = getBits(gzipData, 1);
type = getBits(gzipData, 2);
if (type == 0) {
// uncompress data
bitIndex = 0;
int length = getBits(gzipData, 16);
gIndex += 2;
System.arraycopy(gzipData, gIndex, unzipData, unzipIndex, length);
gIndex += length;
unzipIndex += length;
} else {
byte[] lBits;
byte[] dBits;
if (type == 1) {
// use final final static huffman.
lBits = new byte[288];// The lTree node numbers 286, the
// last two nodes is use for full
// tree.
for (int i = 0; i < 288; i++) {
if (i < 144 || i > 279) {
lBits[i] = 8;
} else if (i < 256) {
lBits[i] = 9;
} else {
lBits[i] = 7;
}
}
dBits = new byte[32];// The dTree node numbers 30, the last
// two nodes is use for full tree.
for (int i = 0; i < dBits.length; i++) {
dBits[i] = 5;
}
} else if (type == 2) {
// use dynamic huffman.
int hlit = getBits(gzipData, 5) + 257;
int hdist = getBits(gzipData, 5) + 1;
int hclen = getBits(gzipData, 4) + 4;
byte[] bltreeBits = new byte[19];// The blTree node numbers
// 19.
for (int i = 0; i < hclen; i++)
bltreeBits[DYNAMIC_L_ORDER[i]] = (byte) getBits(gzipData, 3);
int[] blTree = huffmanTree(bltreeBits);
lBits = decompressCode(gzipData, blTree, hlit);
dBits = decompressCode(gzipData, blTree, hdist);
} else {
throw new IOException("不能正确解压数据.");
}


int[] lTree = huffmanTree(lBits);// The literal/length tree.
int[] dTree = huffmanTree(dBits);// The distance tree.
int code = 0;
while ((code = getCode(gzipData, lTree)) != 256) {// code=256
// indicates
// the end
// of this
// block.
if (code < 256) {// literal byte
unzipData[unzipIndex++] = (byte) code;
} else {// length/distance pairs
code -= 257;
int length = EXTRA_L_VALUES[code];
if (EXTRA_L_BITS[code] > 0)
length += getBits(gzipData, EXTRA_L_BITS[code]);
code = getCode(gzipData, dTree);
int distance = EXTRA_D_VALUES[code];
if (EXTRA_D_BITS[code] > 0)
distance += getBits(gzipData, EXTRA_D_BITS[code]);
while (distance < length) {
System.arraycopy(unzipData, unzipIndex - distance, unzipData, unzipIndex, distance);
unzipIndex += distance;
length -= distance;
}
System.arraycopy(unzipData, unzipIndex - distance, unzipData, unzipIndex, length);
unzipIndex += length;
}
}
}
}
return unzipData;
}


// Get a huffman tree.
private final static int[] huffmanTree(byte bits[]) {
int bl_count[] = new int[MAX_BITS + 1];
for (int i = 0; i < bits.length; i++) {
bl_count[bits[i]]++;
}
int code = 0;
bl_count[0] = 0;
int next_code[] = new int[MAX_BITS + 1];
// Count the number of codes for each code length.
for (int i = 1; i <= MAX_BITS; i++) {
code = (code + bl_count[i - 1]) << 1;
next_code[i] = code;
}
int tree[] = new int[((bits.length - 1) << 1) + MAX_BITS];
int treeInsert = 1;
for (int i = 0; i < bits.length; i++) {
int len = bits[i];
if (len != 0) {
code = next_code[len]++;
int node = 0;
for (int bit = len - 1; bit >= 0; bit--) {
int value = code & (1 << bit);
if (value == 0) {
int left = tree[node] >> 16;
if (left == 0) {
tree[node] |= (treeInsert << 16);
node = treeInsert++;
} else
node = left;
} else {
int right = tree[node] & 0xFFFF;
if (right == 0) {
tree[node] |= treeInsert;
node = treeInsert++;
} else
node = right;
}
}
tree[node] = 0x80000000 | i;
}
}
return tree;
}


// Decompress the literal/length code and the distance code.
private final static byte[] decompressCode(byte data[], int blTree[], int count) {
int code = 0;
byte previousCode = 0;
int times = 0; // The number of the previous code's length need to
// repeat.
byte treeBits[] = new byte[count];
int index = 0;
while (index < count) {
code = getCode(data, blTree);
if (code == 16) {
times = getBits(data, 2) + 3;
} else if (code == 17) {
times = getBits(data, 3) + 3;
previousCode = 0;
} else if (code == 18) {
times = getBits(data, 7) + 11;
previousCode = 0;
} else {
times = 0;
previousCode = (byte) code;
treeBits[index++] = (byte) code;
}
for (int i = 0; i < times; i++) {
treeBits[index++] = previousCode;
}
}
return treeBits;
}


public final static String getVersion() {
// 获取手机操作系统版本?
return android.os.Build.VERSION.RELEASE;
}


public final static String getModel() {
// 获取手机型号
return android.os.Build.MODEL;
}


public final static String getName() {
// 获取用户姓???
return android.os.Build.USER;
}


public final static String getDeviceName() {
return android.os.Build.DEVICE;
}


public final static String getPlayform() {
// 当前系统平台
return "Android";
}


public final static String getUUID() {
final TelephonyManager tm = (TelephonyManager) activity_.getBaseContext().getSystemService(
Context.TELEPHONY_SERVICE);
final String tmDevice, tmSerial, tmPhone, androidId;
tmDevice = "" + tm.getDeviceId();
tmSerial = "" + tm.getSimSerialNumber();
androidId = ""
+ android.provider.Settings.Secure.getString(activity_.getContentResolver(),
android.provider.Settings.Secure.ANDROID_ID);
UUID deviceUuid = new UUID(androidId.hashCode(), ((long) tmDevice.hashCode() << 32) | tmSerial.hashCode());
return deviceUuid.toString();
}


public final static String connectType(Activity bv) {
// TODO Auto-generated method stub
try {
Context context = bv.getApplicationContext();
ConnectivityManager connectivity = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);


NetworkInfo ni = connectivity.getActiveNetworkInfo();


if ((null != ni) && ni.isAvailable()) {
return ni.getTypeName();
}
} catch (Exception e) {
Utils.printException(e);
return getConfigStringFormAsset(getActivity(), "httpError");
}
return getConfigStringFormAsset(getActivity(), "httpError");


}


private final static String getLocationByNet(Activity bv) {
// TODO Auto-generated method stub
double LATITUDE = 0;
double LONGITUDE = 0;
int timeoutConnection = 3000;
int timeoutSocket = 5000;
TelephonyManager mTelNet = (TelephonyManager) bv.getSystemService(Context.TELEPHONY_SERVICE);
String operator = mTelNet.getNetworkOperator();
CellLocation cl = mTelNet.getCellLocation();
// #ifdef Android2.2
if (cl instanceof CdmaCellLocation) {
CdmaCellLocation location = (CdmaCellLocation) cl;
LATITUDE = (double) location.getBaseStationLatitude() / 14400;// 14400?*90/1296000
LONGITUDE = (double) location.getBaseStationLongitude() / 14400;


} else if (null != operator && !operator.equals("")) {
// #else
// @ if (null != operator && !operator.equals("")) {
// #endif
String mcc = operator.substring(0, 3);
String mnc = operator.substring(3);


if (cl instanceof GsmCellLocation) {
GsmCellLocation location = (GsmCellLocation) cl;
if (null != location) {
int cid = location.getCid();
int lac = location.getLac();
HttpParams httpParameters = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);
HttpClient httpclient = new DefaultHttpClient(httpParameters);
HttpPost post = new HttpPost("http://www.google.com/loc/json");
try {
JSONObject holder = new JSONObject();
holder.put("version", "1.1.0");
holder.put("host", "maps.google.com");
holder.put("address_language", "zh_CN");
holder.put("request_address", true);
JSONObject tower = new JSONObject();
tower.put("mobile_country_code", mcc);
tower.put("mobile_network_code", mnc);
tower.put("cell_id", cid);
tower.put("location_area_code", lac);
JSONArray towerarray = new JSONArray();
towerarray.put(tower);
holder.put("cell_towers", towerarray);
StringEntity query = new StringEntity(holder.toString());
post.setEntity(query);
HttpResponse response = httpclient.execute(post);
HttpEntity entity = response.getEntity();
BufferedReader buffReader = new BufferedReader(new InputStreamReader(entity.getContent()));
StringBuffer strBuff = new StringBuffer();
String result = null;
while ((result = buffReader.readLine()) != null) {
strBuff.append(result);
}
JSONObject json = new JSONObject(strBuff.toString());
JSONObject subjosn = new JSONObject(json.getString("location"));
LATITUDE = Double.parseDouble(subjosn.getString("latitude"));
LONGITUDE = Double.parseDouble(subjosn.getString("longitude"));
} catch (Exception e) {
// LPUtils.printException(e);
Utils.printException(e);
}
}
}
}


return (String.valueOf(LATITUDE)).concat(",").concat(String.valueOf(LONGITUDE));
}


/**
* 查看android手机是否被刷过机.linux系统下root权限可以使用su命令,android本身也是小型的linux系统
*
* @param command
* "id" 或其他的 su命令
*/
public final static boolean runRootCommand(String command) {


Process process = null;
DataOutputStream os = null;
try {
process = Runtime.getRuntime().exec("su");
os = new DataOutputStream(process.getOutputStream());
os.writeBytes(command + "\n");
os.writeBytes("exit\n");
os.flush();
process.waitFor();
} catch (Exception e) {
printException(e);
return false;
} finally {
try {
if (os != null) {
os.close();
}
process.destroy();
} catch (Exception e) {
// nothing
}
}
return true;
}


/**
* * 保存对象到文?* * @param obj * @param fileName * @throws Exception
*
* @param publicKey
*/
public static void saveFile(Activity activity, Object obj, String fileName) {
ObjectOutputStream output;
try {
output = new ObjectOutputStream(activity.openFileOutput(fileName, Context.MODE_PRIVATE));


output.writeObject(obj);
output.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
printException(e);
} catch (IOException e) {
// TODO Auto-generated catch block
printException(e);
}
}


/**
* 读取Config的文本默认颜色设置,如果没有,默认为黑色
*
* @param activity
*/
public static void readTextClolr(Activity activity) {
String colortemp = getConfigStringFormAsset(activity, "textColor");
Component.TEXTCOLOR = Color.BLACK;
if (null != colortemp && !colortemp.equals("")) {
if (colortemp.equalsIgnoreCase("black"))
Component.TEXTCOLOR = Color.BLACK;
else if (colortemp.equalsIgnoreCase("BLUE"))
Component.TEXTCOLOR = Color.BLUE;
else if (colortemp.equalsIgnoreCase("CYAN"))
Component.TEXTCOLOR = Color.CYAN;
else if (colortemp.equalsIgnoreCase("dkgray"))
Component.TEXTCOLOR = Color.DKGRAY;
else if (colortemp.equalsIgnoreCase("white"))
Component.TEXTCOLOR = Color.WHITE;
else if (colortemp.equalsIgnoreCase("gray"))
Component.TEXTCOLOR = Color.GRAY;
else if (colortemp.equalsIgnoreCase("green"))
Component.TEXTCOLOR = Color.GREEN;
else if (colortemp.equalsIgnoreCase("ltgray"))
Component.TEXTCOLOR = Color.LTGRAY;
else if (colortemp.equalsIgnoreCase("magenta"))
Component.TEXTCOLOR = Color.MAGENTA;
else if (colortemp.equalsIgnoreCase("red"))
Component.TEXTCOLOR = Color.RED;
else if (colortemp.equalsIgnoreCase("transparent"))
Component.TEXTCOLOR = Color.TRANSPARENT;
else if (colortemp.equalsIgnoreCase("yellow"))
Component.TEXTCOLOR = Color.YELLOW;
}
}


/** * 从文件读取object * * @param fileName * @return * @throws Exception */
public static Object readFromFile(Activity activity, String fileName) {
ObjectInputStream input;
try {
input = new ObjectInputStream(activity.openFileInput(fileName));
Object obj = input.readObject();
input.close();
return obj;
} catch (StreamCorruptedException e) {
// TODO Auto-generated catch block
printException(e);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
printException(e);
} catch (IOException e) {
// TODO Auto-generated catch block
printException(e);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
printException(e);
}
return null;
}


public static void saveFile(String name, byte[] buffer) {
if (null == name || name.equals(""))
return;
name = OffStoreDownload.FILEROOT.concat(name);


if (name.endsWith("/")) {
createPath(name);
} else {
createFile(name, buffer);
}
}


/**
* @param activity
* @param fullPathName
* @return
*/
public final static byte[] readFile(String fullPathName) {
byte[] buffer = null;
try {
File file = new File(fullPathName);
FileInputStream fis = new FileInputStream(file);
int len = fis.available();
buffer = new byte[len];
fis.read(buffer);
fis.close();
buffer = AESCipher.decrypt(buffer, AESCipher.customerKey_, AESCipher.customerIv_);
} catch (FileNotFoundException e) {
printException(e);
} catch (IOException e) {
printException(e);
} catch (Exception e) {
printException(e);
}
return buffer;
}


private static void createFile(String path, byte[] buffer) {
// TODO Auto-generated method stub
File file = null;
FileOutputStream fstream = null;
try {
file = new File(path);
if (!file.exists()) {
file.createNewFile();
fstream = new FileOutputStream(file);
buffer = AESCipher.encrypt(buffer, AESCipher.customerKey_, AESCipher.customerIv_);
fstream.write(buffer);
}
} catch (Exception e) {


printException(e);


} finally {


if (fstream != null) {


try {
fstream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
printException(e);
}


}


}
}


public static void createPath(String path) {
File file = new File(path);
if (!file.exists()) {
file.mkdirs();
}
}


/**
* 初始化本地存储的 key,iv
*
* @param activity
*/
public static void initCustomerSecretKey(Activity activity) {
try {
TelephonyManager tm = (TelephonyManager) activity.getSystemService(Activity.TELEPHONY_SERVICE);
String deviceId = tm.getDeviceId();
String deviceName = Build.DEVICE;
String packageName = activity.getPackageName();
if (deviceId == null) {
deviceId = "";
}
if (deviceName == null) {
deviceName = "";
}
if (packageName == null) {
packageName = "com.rytong.tools";
}
String message = deviceId.concat(deviceName).concat(packageName)
.concat(RSACipher.PUBLIC_CER_MODULUS_FILENAME).concat(HMac.KEY_MAC_MD5);
byte[] sha1 = HMac.SHA1(message.getBytes());
byte[] md5 = MD5.getMD5(message.getBytes());
byte[] secretKey = new byte[sha1.length + md5.length];
System.arraycopy(sha1, 0, secretKey, 0, sha1.length);
System.arraycopy(md5, 0, secretKey, sha1.length, md5.length);
AESCipher.customerKey_ = ClientHello.getAESKey(secretKey);
AESCipher.customerIv_ = new byte[16];
for (int i = 0; i < 16; i++) {
AESCipher.customerIv_[i] = secretKey[secretKey.length - 1 - i];
}
} catch (Exception e) {
printOutToConsole(e);
}
}


/**
* 清空界面所有控件
*/
public static void clearWidget() {
// TODO Auto-generated method stub
if (null != Component.VWIDGETARRAY && !Component.VWIDGETARRAY.isEmpty()) {
int size = Component.VWIDGETARRAY.size();
Component comp;
int index = Integer.MIN_VALUE;
for (int i = 0; i < size; i++) {
comp = (Component) Component.VWIDGETARRAY.get(i);
if (null != comp.getTag() && comp.getTag().equalsIgnoreCase("body"))
index = i;
}
if (index != Integer.MIN_VALUE) {
comp = (Component) Component.VWIDGETARRAY.get(index);
comp.releaseResource(comp);
}
}
}


}

分享到:
评论

相关推荐

    android 离线下载实现版本更新,图片缓存

    在Android应用开发中,离线下载和图片缓存是两个重要的功能模块,它们极大地提升了用户体验。本文将详细探讨如何在Android应用中实现这些功能,并针对标题和描述中的内容进行深入解析。 **一、离线下载** 离线下载...

    uniapp Android离线SDK

    - 下载:首先,开发者需要从官方渠道下载对应版本的uniapp Android离线SDK。 - 集成:将下载的SDK解压,并将其添加到uniapp的开发环境中,通常是放置在指定的插件目录下。 - 配置:在uniapp的项目配置文件中指定...

    ArcGIS for Android离线地图

    ArcGIS for Android 离线地图开发DEMO,包含离线地图数据

    Android API 离线文档——3

    Documentation for Android SDK(API 19) Android SDK 官方使用说明文档,对应Android 4.4.2 开发库。...需要全部下载后解压使用,文件夹放置于Android SDK安装目录下即可。 离线文档可通过index.html直接打开。

    Android SDK离线包合集(Android 4.0-5.0)

    Android SDK离线包合集(Android 4.0-5.0)。不用去Google下载,直接国内下载离线包,各版本文件独立,任意下载。手机流量上传了一部分,好心疼。如不能下载,请告诉我更新地址。 附上简单教程。 这是Android开发所...

    Uniapp APP Android 离线SDK 版本号Android-SDK@3.6.17.81662-20230112

    本文将详细解析“Android-SDK@3.6.17.81662-20230112”这一特定的Uniapp Android离线SDK版本,并探讨其在实际应用中的关键知识点。 首先,版本号“Android-SDK@3.6.17.81662-20230112”包含了丰富的信息。按照一般...

    android离线系统日志工具

    Android离线系统日志工具是一种可以在设备离线状态下收集和管理系统日志信息的工具。这些工具通常设计用于帮助开发人员在设备无法连接到互联网或调试工具的情况下,仍然能够获取关于设备状态和应用程序行为的日志...

    android sdk离线下载方法

    离线下载资源,是国内的镜像,不用蜗牛般的去谷歌下载了

    android原生离线身份证识别Demo(无需网络、无识别次数限制)

    "android原生离线身份证识别Demo(无需网络、无识别次数限制)" 提供了一个解决方案,它利用本地算法进行身份证信息提取,避免了网络依赖,同时也消除了识别次数的限制,这对于某些对隐私保护和实时性要求较高的应用...

    Android离线webview调试工具,开发H5混合应用必备

    为了解决这个问题,我们有了"Android离线webview调试工具",它是一个专门针对这种困境设计的解决方案。这个工具允许开发者在没有网络障碍的情况下,有效地进行WebView内的H5页面调试。它不仅避免了因网络问题导致的...

    Uniapp APP Android 离线SDK 版本号Android-SDK@3.6.18.81676-20230117

    《 Uniapp Android 离线SDK:Android-SDK@3.6.18.81676-20230117 深度解析》 在移动应用开发领域,Uniapp是一个备受开发者青睐的框架,它允许开发者使用一套代码库构建跨平台的应用程序,覆盖iOS、Android以及Web等...

    android 离线帮助文档

    Android离线帮助文档是开发者和用户在没有网络连接时查阅Android平台相关知识的重要资源。这份HTML版的文档包含了丰富的信息,旨在提供全面的Android开发、设计、测试和优化的指导。下面将详细介绍其中可能包含的...

    Java Android离线识别证件、驾证、行卡AndroidOcrLibs-master.zip

    Java Android离线识别证件、驾证、行卡AndroidOcrLibs 1.API没有任何限制(如:不要求验签,不限制次数,永免费,任由您使用) 2.demo中已基本涵盖了所有核心API的使用,代码写的很烂,但您一定看得懂 3.请尽量扫描...

    Android sdk 各版本离线安装包下载地址及方法(解决更新慢)

    Android sdk 在首次安装好后 要用SDK Manager.exe进行更新,因服务器在国外,下载经常断开及下载非常慢 上面我把SDK的更新所需要各文件下载地址提供出来,用下载工具下载后即可使用,上面已更新到2014年2月6日 第一...

    android官方api离线版

    Android官方API离线版是一个非常宝贵的资源,它包含了大量的Android开发所需的信息,使得开发者无需互联网连接也能查阅Android的API文档。这个压缩包提供的是`.chm`格式的文件,这是一种由微软开发的帮助文件格式,...

    Arcgis for android 离线地图缓存制作教程

    ### ArcGIS for Android 离线地图缓存制作教程 #### 一、ArcGIS地图缓存制作概述 ArcGIS是一款广泛应用于地理信息系统(GIS)领域的软件,它支持地图的创建、管理和分享。随着移动设备的普及和技术的发展,越来越多...

    Android离线地理数据

    Android离线地理数据的实现!

    android离线日志文件打印

    标题“android离线日志文件打印”指的是在Android设备上记录日志信息,并将这些信息保存到特定的文本文件中,这样即使不依赖Eclipse等IDE工具,也能在后续的时间里查看和分析这些日志。 日志是软件开发中的重要工具...

    Android Studio 2021离线环境配置教程完整介绍

    ### Android Studio 2021离线环境配置教程完整介绍 #### 一、基本思路概述 在当前数字化时代,很多开发工作需要在无网络连接的环境中进行,这为软件开发带来了一定挑战。针对Android应用开发,特别是使用Android ...

    Android离线包前端代码

    Android离线包前端代码,在前端打包的过程中同时生成离线包,我的思路是 webpack 插件在 emit 钩子时(生成资源并输出到目录之前),通过 compilation 对象(代表了一次单一的版本构建和生成资源)遍历读取 webpack ...

Global site tag (gtag.js) - Google Analytics