package com.android.metro.metrofirst;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Locale;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.Timer;
import java.util.TimerTask;

import org.apache.commons.net.ftp.FTPFile;
import org.json.JSONArray;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;

import com.android.metro.MetroCmd;
import com.android.metro.MetroHexControl;
import com.android.metro.MetroLog;
import com.android.metro.MetroMulticastManager;
import com.android.metro.MetroNetwork;
import com.android.metro.bridge.uDEF;
import com.android.metro.bridge.uBridge;
import com.android.metro.bridge.uXmlCommand;
import com.android.metro.bridge.Utils;
import com.android.metro.bridge.uDebug;
import com.android.metro.showservice.uShowService;
import com.android.metro.tools.uFtp;
import com.android.metro.tools.uHotKeyTable;
import com.android.metro.tools.uSurfaceView;
import com.android.metro.tools.uSystemController;
import com.android.metro.tools.uView;
import com.android.metro.tools.NanoHTTPD;
import com.android.metro.tools.uWebView;

import android.net.ConnectivityManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.os.PowerManager;
import android.os.RecoverySystem;
import android.os.StrictMode;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.provider.Settings.SettingNotFoundException;
import android.app.Activity;
import android.app.Instrumentation;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.AssetManager;
import android.content.res.Configuration;
import android.graphics.Color;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.ColorDrawable;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.View;
import android.view.WindowManager;
import android.view.ViewGroup.LayoutParams;
import android.widget.RelativeLayout;
import android.widget.Toast;

public class MainActivity extends Activity implements Handler.Callback {

	private static uDebug udebug = new uDebug(32, "[MainActivity]");

	// / static
	public static final String SERVER_URL = "http://service.tv.co.kr:8080/UIS/";
	public static MainActivity thiz = null;;
	
	// log system
	public static MetroLog metrolog = null;

	// value
	NanoHTTPD mHttpd = null;
//	uATSCController mAtscController = null;
	private uSystemController mSystemControl = null;
	public static SystemInfo msi = new SystemInfo();
//	private uViewGroup mviews = null;
	public uViewGroup mviews = null;
	private uBridge bridge = null;
	private uBridge mShowServiceConn = null; // show service를 닫기 위한 connection
	public static boolean mShowServiceConnected = false;
	public static boolean mSystemSettingServiceConnected = false;
	private uXMLManager xmlManager = null;
	private ArrayList<Integer> marrKeyQ = new ArrayList<Integer>();
	private Boolean bUpgradeWorking = false;

	private uHotKeyTable hotkeys = new uHotKeyTable();
//	private SpeedKeyDrop  speedkey = new SpeedKeyDrop();

	private Intent intentShowService = null;
	private ComponentName cnShowService = null;
	private RunnableCreate monCreateRunnable = new RunnableCreate();
	private Handler m_main_Handler = null;
	private Boolean mIsCreate = false;

	private uBridge mSystemSettingService = null;
	private uCmdLauncher run = new uCmdLauncher();
	private MetroCmd metrorun = new MetroCmd();
	private uToast mtoast = null;
	
	//private boolean isHexSwitchIP = false;
	//private final int HEX_SWITCH_RECOUNT = 5;

//	private static GetKMsg gkmsg= null;
	private static final int MESSAGE_ID_METRO_UPDATE_RSP = 1;

	private Instrumentation mInst = new Instrumentation();

	private ArrayList<Integer> mKeyCode = new ArrayList<Integer>();
	private boolean mBlockAddKey = false;
	private boolean mSendKeyRunning = true;

	private RelativeLayout mMainView = null;

	private View mDoorBrokenView = null;
	public static final int MSG_WHAT_DOOR_BROKEN_SHOW = 10001;
	public static final int MSG_WHAT_DOOR_BROKEN_HIDE = 10002;
	private int mDoorBrokenBlinkSpeed = 1000;

	private static final int LOG_UPLOAD_INTERVAL = 5000;
	public Runnable mLogUploadRunnable = new Runnable() {
		@Override
		public void run() {
			final String LOGCAT_UPLOAD_START_MARKER = uDEF.PathDataLogStartFile;
			final String LOGCAT_UPLOAD_TARGET = uDEF.PathDataLogFile + ".1";
			final String LOGCAT_UPLOAD_TARGET_BAK = LOGCAT_UPLOAD_TARGET + ".bak";
			final String METRO_COMPONENT_SET = "METRO COMPONENT_MODE";
			final String METRO_COMPONENT_SET_CHECK = uDEF.PathDataLog + "/display_set_ok";

			boolean metroComponentSet = false;
			
			String mmpMaster = null;
			String mmpSlave = null;
			
			while (null != mLogUploadThread && mLogUploadThread.isAlive() && !mLogUploadThread.isInterrupted()) {
				Utils.Sleep(LOG_UPLOAD_INTERVAL);
				
				if (MetroMulticastManager.metroAPI.GetUpgradeStatus()) {
//					udebug.m("uploading log skip, upgrade is running");
					continue;
				}

				final long cur_time = System.currentTimeMillis();
				if(1386264809000L > cur_time){
//					udebug.m("skip low time");
					if (Utils.FileExist(LOGCAT_UPLOAD_START_MARKER)) {
						Utils.Del(LOGCAT_UPLOAD_START_MARKER);
					}
					continue;
				}

				if (Utils.FileExist(LOGCAT_UPLOAD_TARGET)) {
					//20180115 SHKANG EDIT START
					//Always check display set success or not for every 5 seconds
					//Previous version checked only once when boot completed
					udebug.m("Check display set...");
					
					metroComponentSet = false;

					BufferedReader br = null;
					String line = null;
					long skipPos = 0;
					
					try {
						br = new BufferedReader(new FileReader(LOGCAT_UPLOAD_TARGET));
						br.skip(skipPos);
						while(br.ready()){
							line = br.readLine();
							if (line.contains(METRO_COMPONENT_SET)) {
								udebug.lm(33, "=========================================");
								udebug.lm(33, "Display set success!!");
								udebug.lm(33, "=========================================");
								Utils.String2File("1", METRO_COMPONENT_SET_CHECK);
								metroComponentSet = true;
							}
						}
						br.close();
						br = null;
					} catch (FileNotFoundException e) {
						e.printStackTrace();
					} catch (IOException e) {
						e.printStackTrace();
					} finally{
						if(null != br){
							try {
								br.close();
							} catch (IOException e) {
								e.printStackTrace();
							}
							br = null;
						}
					}
					
					if (!metroComponentSet) {
						udebug.error("=========================================");
						udebug.error("Display set failed! Reboot!!");
						udebug.error("=========================================");
						PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
						pm.reboot(null);
						return;
					}
					//20180115 SHKANG EDIT END
					
					File from = new File(LOGCAT_UPLOAD_TARGET);
					File to = new File(LOGCAT_UPLOAD_TARGET_BAK);
					final Boolean moveResult = Utils.Rename(from, to);
					from = null;
					if (moveResult) {
						String myIp = null;
						myIp = Utils.getIPAddress(true);
						if (null == myIp || myIp.length() < 7) {
							udebug.error("Invalid IP.");
							to.delete();
							to = null;
							if (Utils.FileExist(LOGCAT_UPLOAD_START_MARKER)) {
								Utils.Del(LOGCAT_UPLOAD_START_MARKER);
							}
							continue;
						}

						String myIps[] = null;
						myIps = myIp.trim().split("\\.");
						if (null == myIps || myIps.length < 4) {
							udebug.error("IP split failed.");
							to.delete();
							to = null;
							if (Utils.FileExist(LOGCAT_UPLOAD_START_MARKER)) {
								Utils.Del(LOGCAT_UPLOAD_START_MARKER);
							}
							continue;
						}
						
						if (null == msi.mmp) continue;
						
	//					String LOGCAT_UPLOAD_FTP_SERVER = "ftp://it:it1234@11." + myIps[1] + ".1.97/Log";
						
						if (msi.mmp.endsWith("1.97")) {
							mmpMaster = String.format("%s.%s.1.97", myIps[0], myIps[1]);
							mmpSlave = String.format("%s.%s.6.97", myIps[0], myIps[1]);
						} else { // if (msi.mmp.endsWith("6.97")) {
							mmpMaster = String.format("%s.%s.6.97", myIps[0], myIps[1]);
							mmpSlave = String.format("%s.%s.1.97", myIps[0], myIps[1]);
						}
						
						String targetFtpIp = null;
						
						// AVAU CPU issue, so Slave first
						if (!Utils.Ping(mmpSlave, 0.2f)) {
							udebug.error("Ping to [%s] failed", mmpSlave);
							if (!Utils.Ping(mmpMaster, 0.2f)) {
								udebug.error("Ping to [%s] failed", mmpMaster);
							} else {
								targetFtpIp = mmpMaster;
							}
						} else {
							targetFtpIp = mmpSlave;
						}
						
						if (null == targetFtpIp) {
							udebug.error("There is no available ftp [%s][%s]",
									mmpMaster, mmpSlave);
							to.delete();
							to = null;
							if (Utils.FileExist(LOGCAT_UPLOAD_START_MARKER)) {
								Utils.Del(LOGCAT_UPLOAD_START_MARKER);
							}
							continue;
						}

						uFtp ftp = new uFtp();
						
						String LOGCAT_UPLOAD_FTP_SERVER = String.format("ftp://it:it1234@%s/Log", targetFtpIp);
						
						final long ctime = System.currentTimeMillis();
						Date d = new Date(ctime);
						
						SimpleDateFormat timeFormatForDirYMD = new SimpleDateFormat ( "yyyyMMdd", Locale.KOREA );
						String stimeYMD = timeFormatForDirYMD.format(d);
						
//						SimpleDateFormat timeFormatYMDHMSS = new SimpleDateFormat ( "yyyyMMdd_HHmmssSSS", Locale.KOREA );
//						String stimeYMDHMSS = timeFormatYMDHMSS.format(d);
//						
//						SimpleDateFormat timeFormatH = new SimpleDateFormat ( "HH", Locale.KOREA );
//						String stimeH = timeFormatH.format(d);

						String destName = String.format(Locale.KOREA, "%s/%03d/%s/%s/%s_%s.txt",
								LOGCAT_UPLOAD_FTP_SERVER,
								Integer.valueOf(myIps[2]),
								stimeYMD,
								myIp,
								myIp,
								stimeYMD);
						
						if (false == ftp.connect(targetFtpIp, 21)) {
							to.delete();
							to = null;
							if (Utils.FileExist(LOGCAT_UPLOAD_START_MARKER)) {
								Utils.Del(LOGCAT_UPLOAD_START_MARKER);
							}
							continue;
						}
						
						if (false == ftp.login("it", "it1234")) {
							to.delete();
							to = null;
							if (Utils.FileExist(LOGCAT_UPLOAD_START_MARKER)) {
								Utils.Del(LOGCAT_UPLOAD_START_MARKER);
							}
							continue;
						}

						boolean cmdResult = false;
						String logDir = String.format("/Log/%03d", Integer.valueOf(myIps[2]));
						
						ftp.mkdir(logDir);
						cmdResult = ftp.cd(logDir);
						if (cmdResult) {
//							udebug.lm(33, "logUploader CD success");
						} else {
							udebug.error("logUploader CD failed, retry after 9 seconds");
							Utils.Sleep(9000);
							continue;
						}
						
						// Only 11.*.1.177, 11.*.2.180 and 11.*.6.200 remove
						// cf) PID: 177~180 RD: 193~200 CARTYPE: 1, 2, 6
						if ((myIps[2].equals("1") && myIps[3].equals("177"))
							|| (myIps[2].equals("2") && myIps[3].equals("180"))
							|| (myIps[2].equals("6") && myIps[3].equals("200"))) {
							if (myIps[2].equals("1")) {	// 11.*.1.177
							} else if (myIps[2].equals("2")) {	// 11.*.2.180
							} else {	// 11.*.6.200
							}
							
							FTPFile[] logDateList = ftp.list();
//							udebug.lm(33, "logUploader logDateList.length = [%d]", logDateList.length);

							for (int i=0; i<logDateList.length; ++i) {
								FTPFile logDate = logDateList[i];
								String logDateName = logDate.getName();
//								udebug.lm(33, "logUploader logDir[%s]", logDir);
//								udebug.lm(33, "logUploader logDateName[%s]", logDateName);
								
								if (null != logDateName && logDateName.length() == 8) {
									String myDir = String.format("/Log/%03d/%s",
											Integer.valueOf(myIps[2]), logDateName);
									cmdResult = ftp.cd(myDir);
									if (cmdResult) {
										long year = Long.valueOf(logDateName.substring(0, 4));
										long month = Long.valueOf(logDateName.substring(4, 6));
										long day = Long.valueOf(logDateName.substring(6, 8));
										
										long cur_year = Long.valueOf(stimeYMD.substring(0, 4));
										long cur_month = Long.valueOf(stimeYMD.substring(4, 6));
										long cur_day = Long.valueOf(stimeYMD.substring(6, 8));
										
										year *= 10000;
										month *= 100;
										
										cur_year *= 10000;
										cur_month *= 100;
										
										long days = year + month + day;
										long cur_days = cur_year + cur_month + cur_day;
										
										boolean remove = false;
										
//										udebug.lm(33, "logUploader days[%d] cur_days[%d] days + 3[%d]", days, cur_days, days + 3);
										
										if (cur_days >= (days + 3)) { // 3일까지 로그 저장
											remove = true;
										}
										
										if (remove) {
											String deleteTarget = String.format("%s/%03d/%s",
													LOGCAT_UPLOAD_FTP_SERVER, Integer.valueOf(myIps[2]), logDateName);
											udebug.lm(33, "Remove older log directory [%s]", deleteTarget);
											ftp.deleteDir(deleteTarget);
										}
									}
								}
							}
						}
						
						long uploadSize = ftp.append(LOGCAT_UPLOAD_TARGET_BAK, destName);
//						udebug.m("ftp upload file(%s) size = %d", destName, uploadSize);
						if (0 < uploadSize) {
							to.delete();
							to = null;
						}

						ftp.disconnect();
						ftp = null;
					} else {
						udebug.error("Cannot move File[%s] to File[%s]", LOGCAT_UPLOAD_TARGET, LOGCAT_UPLOAD_TARGET_BAK);
						if (Utils.FileExist(LOGCAT_UPLOAD_START_MARKER)) {
							Utils.Del(LOGCAT_UPLOAD_START_MARKER);
						}
						continue;
					}
				}

				if (!Utils.FileExist(LOGCAT_UPLOAD_START_MARKER)) {
					udebug.m("Create [%s]", LOGCAT_UPLOAD_START_MARKER);
					Utils.String2File("1", LOGCAT_UPLOAD_START_MARKER);
				}
			}
		}
	};
	public Thread mLogUploadThread = new Thread(mLogUploadRunnable, "mLogUploadThread");

	private class SendKeyRunnable implements Runnable {
		@Override
		public void run() {
			while (mSendKeyRunning) {
				Utils.Sleep(100);

				synchronized (mKeyCode) {
					if (mKeyCode.size() == 0) continue;

					// 내부 변환 과정 null 체크
					Integer kc = mKeyCode.remove(0);
					if (null != kc) {
						final int keyCode = kc.intValue();
						mInst.sendKeyDownUpSync(keyCode);
					} else {
						udebug.error("Integer remove occurred null");
					}
				}
			}
		}
	}

	private class SendKeyThread extends Thread {
		public SendKeyThread(Runnable r) {
			super(r);
		}

		public synchronized void addKey(int key) {
			if (mBlockAddKey) return;
			mKeyCode.add(key);
		}

		public synchronized void setBlockAddKey(boolean block) {
			mBlockAddKey = block;
			mKeyCode.clear();

			MetroMulticastManager.metroAPI.ClearMessage();
		}
	}
	
	private Handler mDoorBroken = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			super.handleMessage(msg);

			switch (msg.what) {
				case MSG_WHAT_DOOR_BROKEN_SHOW:
					if (null == mMainView) {
						mMainView = (RelativeLayout) findViewById(R.id.mainView);
						if (null == mMainView) {
							udebug.error("mMainView is null");
							return;
						}
					}

					if (null == mDoorBrokenView) {
						mDoorBrokenView = new View(MainActivity.this);
						RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
						mDoorBrokenView.setLayoutParams(params);

			            ColorDrawable cdRed = new ColorDrawable(0xffff0000);
			            ColorDrawable cdBlack = new ColorDrawable(0xffffffff);

			            AnimationDrawable a = new AnimationDrawable();
			            a.addFrame(cdRed, mDoorBrokenBlinkSpeed);
			            a.addFrame(cdBlack, mDoorBrokenBlinkSpeed);
			            a.setOneShot(false);

			            mDoorBrokenView.setBackground(a);
			            a.start();

			            mMainView.addView(mDoorBrokenView);
					}
					break;

				case MSG_WHAT_DOOR_BROKEN_HIDE:
					if (null == mMainView) {
						mMainView = (RelativeLayout) findViewById(R.id.mainView);
						if (null == mMainView) {
							udebug.error("mMainView is null");
							return;
						}
					}

					if (null != mDoorBrokenView) {
						mDoorBrokenView.setVisibility(View.GONE);
					}
					break;

				default:
					break;
			}
		}
	};
	
	private SendKeyThread mSendKeyThread = new SendKeyThread(new SendKeyRunnable());

//	public static class KillMySelfThread {
//		private static Thread mThread = null;
//		private static boolean kill_myself = false;
//
//		private KillMySelfThread() {
//		}
//
//		private static Runnable mRunnable = new Runnable() {
//			@Override
//			public void run() {
//				udebug.InFnc();
//
//				while (null != mThread && mThread.isAlive() && !mThread.isInterrupted()) {
//					Utils.Sleep(10);
//
//					if (!kill_myself) continue;
//
//					android.os.Process.killProcess(android.os.Process.myPid());
//					udebug.lm(33, "==========================================================");
//					udebug.lm(33, "android.os.Process.killProcess(android.os.Process.myPid())");
//					udebug.lm(33, "==========================================================");
//					break;
//				}
//
//				udebug.OutFnc();
//			}
//		};
//
//		public static void start() {
//			if (null == mThread) {
//				mThread = new Thread(mRunnable);
//				kill_myself = false;
//			}
//
//			mThread.setName("[KILL_MYSELF_THREAD]");
//			mThread.start();
//		}
//
//		public static void stop() {
//			kill_myself = true;
//		}
//	}

	private class UpgradeRebootRunnable implements Runnable {
		private File mFile = null;

		@Override
		public void run() {
			if (null == mFile || !mFile.exists()) {
				udebug.error("CheckUpgradeRebootRunnable.mFile is invalid");
				return;
			}

			udebug.lm(33, "RecoverySystem.installPackage(); start");
			try {
				RecoverySystem.installPackage(MainActivity.this, mFile);
			} catch (IOException e) {
				e.printStackTrace();
			}
			udebug.lm(33, "RecoverySystem.installPackage(); end");
		}

		public void setFile(File file) {
			mFile = file;
		}
	}
	private UpgradeRebootRunnable mCheckUpgradeRebootRunnable = new UpgradeRebootRunnable();
	private Handler mUpgradeRebootHandler = new Handler();

	private Handler mSelfKillHandler = new Handler();
	private Runnable mSelfKillRunnable = new Runnable() {
		@Override
		public void run() {
/*			PendingIntent i = PendingIntent.getActivity(getApplicationContext(), 0,
					new Intent(getIntent()), getIntent().getFlags());
			AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
			Log.d("[ModLauncher2]", "[check_sdcard_runnable] set alarm for start launcher");
			am.set(AlarmManager.RTC, System.currentTimeMillis() + 5000, i);
			Log.d("[ModLauncher2]", "[check_sdcard_runnable] System.exit(2)");
//			System.exit(2);
*/
			moveTaskToBack(true);
			finish();
//			KillMySelfThread.start();
			android.os.Process.killProcess(android.os.Process.myPid());
		}
	};
	
//	private Handler check_saved_md5_handler = new Handler();
	private Runnable check_saved_md5_runnable = new Runnable() {
		@Override
		public void run() {
			int count = 1;
			while (count <= 5) {
				udebug.lm(33, "Wait initializing for md5 check [%d/%d]", count, 5);
				Utils.Sleep(1000);
				++count;
			}
			udebug.lm(33, "[firmware_clean] for %s folder", uDEF.PathSDCARD_download_firmware);

			File dnFwFolder = new File(uDEF.PathSDCARD_download_firmware);
			if (!dnFwFolder.exists()) {
				udebug.lm(33, "[firmware_clean] There is no %s folder", uDEF.PathSDCARD_download_firmware);
				return;
			}

			String fws[] = dnFwFolder.list();
			if (fws == null || fws.length == 0) {
				udebug.lm(33, "[firmware_clean] There is no files in %s folder", uDEF.PathSDCARD_download_firmware);
				return;
			/*} else {
				for (int idx=0; idx<fws.length; idx++) {
					udebug.lm(33, "[firmware_clean] Removing [%s]", fws[idx]);
					File fw = new File(uDEF.PathSDCARD_download_firmware + "/" + fws[idx]);
					fw.delete();
					fw = null;
				}*/
			}
			
			String updatezip = null;

			for (int idx=0; idx<fws.length; idx++) {
				if (fws[idx].endsWith(".zip")) {
					updatezip = fws[idx];
				}
			}

			if (updatezip == null || updatezip.length() == 0) {
				udebug.lm(33, "[firmware_clean] Can not access update.zip");
				Utils.Del(uDEF.PathSDCARD_download_firmware);
				Utils.exec2("busybox sync");
				Utils.Sleep(10);
				File dir = new File(uDEF.PathSDCARD_download_firmware);
				boolean result = false;
				result = dir.mkdirs();
				udebug.lm(33, "restore created folder(%s) result = %b", dir.getAbsolutePath(), result);
				return;
			}
			
			//Compare and remove
			FirmwareChecker fc = new FirmwareChecker();
			fc.execute(uDEF.PathSDCARD_download_firmware + uDEF.FILE_SEPERATOR + "update.zip");
		}
	};
	private Thread check_saved_md5_thread = new Thread(check_saved_md5_runnable);
	
	private class FirmwareChecker extends AsyncTask<String, Integer, String> {
		@Override
		protected String doInBackground(String... files) {
			String result = null;

			if (null == files[0]) {
				udebug.lm(34, "Param files[0] is null");
				return result;
			}

			String file = files[0];
			
			File fwFile = new File(file);
			File sdcard = new File(uDEF.PathSDCARD);
			if (!fwFile.exists()) {
				udebug.lm(34, "There is no [%s] on download fw folder", file);
				fwFile = null;
				return result;
			}

			//Get update.zip fw version
			if (Utils.Unzip(fwFile, sdcard, "system/build.prop")) {
				Properties prop = new Properties();
				try {
					prop.load(new FileReader(sdcard.getCanonicalPath() + File.separator + "build.prop"));
				} catch (FileNotFoundException e) {
					e.printStackTrace();
					return result;
				} catch (IOException e) {
					e.printStackTrace();
					return result;
				}

				final String BUIlD_VERSION = "ro.build.version.incremental";
				String savedFwVersion = null;
				if (prop.containsKey(BUIlD_VERSION)) {
					savedFwVersion = prop.getProperty(BUIlD_VERSION, null);
					savedFwVersion = savedFwVersion.trim();
				}

				if (null != savedFwVersion) {
					//Get current fw version
					String kernelVersion = SystemProperties.get(BUIlD_VERSION, null);
					if (null != kernelVersion && 0 < kernelVersion.length()) {
						kernelVersion = kernelVersion.trim();
						
						udebug.lm("Current fw version: %s", kernelVersion);
						udebug.lm("Downloaded fw version: %s", savedFwVersion);

						//Compare fw version
						if (!savedFwVersion.equals(kernelVersion)) {
							result = file;
						} else {
							udebug.lm("Current/Downloaded FW file is matched! Preserve saved file!");
						}
					}
				}
			}

			return result;
		}

		@Override
		protected void onPostExecute(String result) {
			super.onPostExecute(result);

			if (null != result && 0 < result.length()) {
				udebug.lm("remove [%s/*] cause it's not same with current installed kernel version",
						uDEF.PathSDCARD_download_firmware);
				File f = new File(uDEF.PathSDCARD_download_firmware);
				Utils.Del(f, true);
				Utils.exec2("busybox sync");
			}
		}
	}

	private static final int KILL_METRO_PERIOD = 3000;
	private Timer check_kill_metro_timer = new Timer();
	private TimerTask check_kill_metro_task = new TimerTask() {
		@Override
		public void run() {
			File file = new File(uDEF.PathSdcardAppsKillMetro);
			if (file.exists()) {
				finish();
			}
			file = null;
		}
	};

	// android.os.NetworkOnMainThreadException 발생
	// MainUI Thread 에서 Network 이용 시 발생하는 오류(Honeycom - Android 3.0 이상부터 발생함)
	// 핸들러(혹은 쓰레드)로 우회 시킴
	private static final Handler mMetroUpdateRspHandler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			super.handleMessage(msg);

			switch (msg.what) {
				case MESSAGE_ID_METRO_UPDATE_RSP: {
					MetroMulticastManager.metroAPI.UpdateRsp(1, (byte)msg.arg1, (byte)0, (byte)0x10000000, "");
				}
					break;
			}
		}
	};

	public static class SystemInfo {
		public String mmp = null;
		
		public class VERSION {
			public String main;
			public String launcher;
			public String source;
		}

		public class PVS {
			public Boolean enable = false;
			public String url = "";
		}

		public VERSION version = new VERSION();
		public PVS pvs = new PVS();
		public String projectName = "";
		public String mainurl = "";
		public String initurl = "";
		public String build = "";
		public String modelType = "";
	}
/*
	private class SpeedKeyDrop {
		private int keycode = 0;
		private int action = 0;
		private long uptime = 0;
		private long steptime = 300; // 300ms
		
		public void SetStepTime(long ms){
			steptime = ms;
		}

		public Boolean CheckTime(KeyEvent event) {
			long ct = System.currentTimeMillis();
			int kc = event.getKeyCode();
			int ac = event.getAction();

			if(keycode == kc && action == ac){
				if(ct - uptime < steptime){
					return false;
				}
			}
			keycode = kc;
			action = ac;
			uptime = ct;
			return true;
		}
	}
*/
	public static void WriteLog(String type,String format, Object...args){
		try{
			MainActivity.metrolog.write(type,format, args);
		}catch(Exception e){
			udebug.error("Error %s", e.getMessage());
			e.printStackTrace();
		}
	}

	private class RunnableCreate implements Runnable {
		/* (non-Javadoc)
		 * @see java.lang.Runnable#run()
		 */
		@Override
		public void run() {
			udebug.InFnc();
			onCreateBridge();
			OnStartService();
			Thread t = new Thread(new Initialize());
			t.setName("MainActivity.RunnableCreate");
			t.start();
			udebug.OutFnc();
		}
	}
	
	private class uToast{
		private int duration = 0;
		private String stxt = "";
		private Context context = null;
		public uToast(Context c){
			context = c;
		}

		public void Set(int ms,String msg, Object...args){
			duration = ms;
			if(0 >= duration) duration = Toast.LENGTH_LONG;
			stxt = Utils.StringFormat(msg, args);
		}
		
		public void Show(){
			Toast.makeText(context, stxt, duration).show();
		}
	}

	//private BroadcastReceiver modBroadcastReceiver = null; 
	// //////////////////////////////////////////////////////////////
	// thread
	// //////////////////////////////////////////////////////////////
/*
	private class GetKMsg implements Runnable {
		public uThread thread = new uThread(this);
		private boolean bcat_done = false;
		
		public void Start(){
			thread.start();
			while(!bcat_done){
				Utils.Sleep(100);
			}
		}
		
		public void Stop(){
			thread.Exit(false);
		}
		
		@Override
		public void run() {
			udebug.InFnc();
		    //String scmd = "/system/bin/sh -c cat /proc/kmsg";
			String scmd = "cat /proc/kmsg";
			
			
			FileReader fr = null;
			try {
				fr = new FileReader("/proc/kmsg");
				udebug.lm(33, "fr.ready() = %b",fr.ready());
				while(fr.ready()){
					udebug.m("%c",fr.read());	
				}
				fr.close();
				fr = null;
				
			} catch (FileNotFoundException e1) {
				e1.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
			

	        StringBuffer echo = new StringBuffer();
	        Runtime runtime = Runtime.getRuntime();
	        //Log.v("ping ", "About to ping using runtime.exec");
	        Process proc = null;
	        int exit = 0;
	        
			try {
				proc = runtime.exec(scmd);
				udebug.lm(33, "runtime.exec(%s)",scmd);
		        
				proc.waitFor();
				udebug.lm(33, "proc.waitFor()");
				
		        exit = proc.exitValue();
		        
		        bcat_done = true;
		        udebug.lm(33, "exit = %d",exit);
		        
		        if (exit == 0) {
		            InputStreamReader reader = new InputStreamReader(proc.getInputStream());
		            BufferedReader buffer = new BufferedReader(reader);
		            String line = "";
						while ((line = buffer.readLine()) != null) {
							udebug.lm(33, "line = %s",line);
						    echo.append(line + "\n");
						}
		        } else if (exit == 1) {
		        	
		        } else {
		        }
			} catch (IOException e) {
				e.printStackTrace();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
	        		    

			udebug.OutFnc();
		}
	}
*/

	private class Initialize implements Runnable {
		/*
		 * (non-Javadoc)
		 * 
		 * @see java.lang.Runnable#run()
		 */
		@Override
		public void run() {
			// TODO Auto-generated method stub
			udebug.lm(33, "Begin -------------------");

			int count = 0;
			
			udebug.lm("wait connect %s", uDEF.NAME_LAUNCHER);
			while (false == xmlManager.mBridgeGroup.GetBridge(uDEF.NAME_LAUNCHER).IsConnected()) {
				udebug.lm("Utils.Sleep(500)");
				Utils.Sleep(500);
			}
			udebug.lm("done connect %s", uDEF.NAME_LAUNCHER);

			udebug.lm("wait connect %s", uDEF.NAME_SHOW_SERVICE);
			while (false == xmlManager.mBridgeGroup.GetBridge(uDEF.NAME_SHOW_SERVICE).IsConnected()) {
				udebug.lm("Utils.Sleep(500)");
				Utils.Sleep(500);
				++count;
				
				if (10 < count) {
					udebug.error("Can not connect to %s, kill %s and restart application", uDEF.NAME_SHOW_SERVICE, uDEF.NAME_SHOW_SERVICE);
					mSelfKillHandler.post(mSelfKillRunnable);
					return;
				}
			}
			udebug.lm("done connect %s", uDEF.NAME_SHOW_SERVICE);
			udebug.lm("wait connect %s", uDEF.NAME_SYSTEM_SETTING_SERVICE);
			while (false == xmlManager.mBridgeGroup.GetBridge(uDEF.NAME_SYSTEM_SETTING_SERVICE).IsConnected()) {
				udebug.lm("Utils.Sleep(500)");
				Utils.Sleep(500);
			}
			udebug.lm("done connect %s", uDEF.NAME_SYSTEM_SETTING_SERVICE);
			
			// HTTP 서버 구동
			File wwwroot = new File(".").getAbsoluteFile();
			try {
				// new NanoHTTPD(8090, wwwroot);
				mHttpd = new NanoHTTPD(MainActivity.this, 8090, wwwroot);
				mHttpd.SetBridge(bridge);
				
			} catch (IOException e) {
				e.printStackTrace();
			}

			UpdateInfo();
			
			//untp.SetServer("time.bora.net", 123);
			//untp.sync();
			
			//{ net work refresh
//			udebug.m("get ConnectivityManager");
//			ConnectivityManager cm = (ConnectivityManager)(MainActivity.thiz.getSystemService(Context.CONNECTIVITY_SERVICE));
//
//			udebug.m("get EhternetManager");
//			EthernetManager em = (EthernetManager)(MainActivity.thiz.getSystemService("ethernet"));
//
//			udebug.m("after cm, em");
//			if(null != cm && null != em){
//				NetworkInfo ni = cm.getNetworkInfo(ConnectivityManager.TYPE_ETHERNET);
//				if(false == ni.isConnected()){
//			        udebug.lm(35, "NetWork Refresh");
//			        udebug.lm(35, "NetWork Set Disable");
//			        em.setEthEnabled(false);
//			        em.setStackConnected(false);
//			        em.setHWConnected(false);
//
//			        Utils.Sleep(500);
//			        udebug.lm(35, "NetWork Set Enable");
//			        em.setHWConnected(true);
//			        em.setStackConnected(true);
//			        em.setEthEnabled(true);
//			        Utils.Sleep(500);
//				} else {
//					udebug.m("ni is connected");
//				}
//			}
//			//} net work refresh
			
			// set display
			// {
			//m_main_Handler.postDelayed(new MetroDisplay(getResources().getString(R.string.resolution)), 100);
//			final String curResolution = getResources().getString(R.string.resolution);
			String resolution = null;
			resolution = SystemProperties.get("ro.ubicod.metro.display.mode", "768p");
			
//			String curResolution = getResources().getString(R.string.resolution);
			
//			File dpconf = new File(uDEF.PathSdcardDisplayResolution);
//			boolean fromFile = false;
//			if (dpconf.canRead()) {
//				fromFile = true;
//				curResolution = Utils.Cat(uDEF.PathSdcardDisplayResolution);
//				if (null != curResolution) {
//					curResolution = curResolution.trim();
//				}
//			} else {
//				curResolution = getResources().getString(R.string.resolution);
//			}

//			if (null != curResolution && 0 < curResolution.length()) {
//				udebug.m("Current resolution = %s", curResolution);
				udebug.m("set hdmi_resolution");
				bridge.CommandSendTo(true, uDEF.TARGET_DISPLAY_CONTROLLER, "set", "hdmi_resolution", resolution);
//				udebug.m("Touch display resolution file");
//				if (!fromFile) Utils.String2File(curResolution, uDEF.PathSdcardDisplayResolution);
//			}
			// }
			
			udebug.lm(33, "bridge %s",bridge);

			//if (null != bridge)
			// bridge가 null 일경우 오류를 발생시키는 것이 맞다.
			
			String start_url = null;
//			if (0 < msi.mainurl.length()) {
//				bridge.CommandSendTo(false, uDEF.TARGET_WINDOW1, "sethome", "value", msi.mainurl);
//			}
			
			// check pvs page
//			if (true == msi.pvs.enable) {
//				start_url = msi.pvs.url;
//				udebug.lm(33, "PVS Url Open %s",start_url);
//			}
			
			// check main page
//			if(null == start_url || 0 >= start_url.length()){
//				start_url = msi.mainurl;
//				udebug.lm(33, "Main Url Open %s",start_url);
//			}
			
			// check init file
//			if(null == start_url || 0 >= start_url.length()){
////					start_url = msi.mainurl;
//				start_url = uDEF.PathSDCARD_main_init_html;
//				if (false == Utils.FileExist(start_url)) {
//					udebug.lm(33, "FAIL FileExist start_url = %s",start_url);
//					start_url = null;
//				}else{
//					udebug.lm(33, "System Open %s",start_url);
//				}
//			}
			
			// check resource init
//			if(null == start_url || 0 >= start_url.length()){
				start_url = msi.initurl;
				udebug.lm(33, "System Open %s",start_url);
//			}

			// default power hot key 등록
//			int index = 0;
//			uXmlCommand command = new uXmlCommand();
//			command.New("hotkey", "from", bridge.GetName(),"to",uDEF.NAME_MANAGER);
//			command.NewNodeName("", "key","name", "power");
//			//command.SetNodeAtt("key", "name", "power");
//			index = 0;
//			command.SetNodeAtt("key", "code", Integer.toString(KeyEvent.KEYCODE_ENDCALL));
//			command.SetNodeAtt("key", "action", Integer.toString(0));
//			command.NewNodeName("key", "open", "index", Integer.toString(index));
//			command.SetNodeAtt(String.format("key[@name='power']/*[@index=%d]", index), "to", "hidden");
//			command.SetNodeAtt(String.format("key[@name='power']/*[@index=%d]", index), "request", "false");
//			command.NewNodeName(String.format("key[@name='power']/*[@index=%d]", index), "value");
//			command.SetNodeValue(String.format("key[@name='power']/*[@index=%d]", index) + "/" + "value", "file:///android_asset/setup/power.html");
//
//			udebug.cmd(33, "command : %s", command.GetXml());
//			bridge.CommandSendTo(false, command);
//			
//			command.release();
//			command = null;

			/*
			int irecount = HEX_SWITCH_RECOUNT; // 3 -> 5, 한 번에 Hex 스위치 값을 못받는 경우가 발생함
			
			udebug.lm(33, "isHexSwitchIP %s", isHexSwitchIP);
			while(false == isHexSwitchIP){
				// metro ip 설정
				//MetroSerial ms = new MetroSerial();
				if(0 >= irecount){
					udebug.error("HexSwitch cancel break");
					break;
				}
				irecount--;
				udebug.lm(33,"irecount=%s", irecount);
				udebug.lm(33,"MetroHexControl.HexSwitch 0x30");
				MetroHexControl.HexSwitch((byte)0x30, (byte)0x00, new MetroHexControl.Callback() {
					@Override
					public void OnRecv(byte[] data, int length) {
						udebug.lm("MetroHexControl.HexSwitch = %s",Utils.convertBytes2Hex(data, length));
						// 10 02 31 08 09 0C 0E 0F FF 10 03 8F
						// 10 02 31 00 01 02 02 10 03 5B

						if (null != data) {
							udebug.lm("data = %s", data.toString());
						} else {
							udebug.error("data for hexswitch is null");
						}
						
						if(10 == length)
						{
							byte check = 0x00;
							if(10 == length){
								for(int i = 0; i < 9; i++){
									check += data[i];
								}
							}
							if(check == data[9]){
								String result = "";
								byte id[] = {data[6],data[5],data[4],data[3]};
								String sip2 = Utils.StringFormat("%d%d",id[0],id[1]);
								int ip[] = {0,0,0,0};
								
								ip[0] = 11;
								ip[1] = Utils.parseInt(sip2);
								ip[2] = id[2];
								
								if("PID".equals(msi.modelType)){
									ip[3] = (0xb0 + id[3]);
								}else{
									ip[3] = (0xc0 + id[3]);
								}
	
								String sip = Utils.StringFormat("%d.%d.%d.%d",ip[0],ip[1],ip[2],ip[3]);
								udebug.m(33,"------------------------");
								udebug.m(33,"msi.modelType = %s",msi.modelType);
								udebug.m(33,"hex %d.%d.%d.%d",id[0],id[1],id[2],id[3]);
								udebug.m(33,"From = %s",Utils.getIPAddress(true));
								udebug.m(33,"To   = %s",sip);
								udebug.m(33,"------------------------");

								metrorun.mmanager.SetNetworkEth0("static",sip,uDEF.SUBNET_CLASS_A,"11.1.1.1","11.1.1.1");

								isHexSwitchIP = true;
							}
						}else{
							udebug.error("HexSwitch -> again");
							Utils.Sleep(1000);
						}
					}
				});
			}
			
//			if(false == isHexSwitchIP){
//				// Error Hex Set switch ip 
//			}
			
			*/

			//////////////////////////////////////////
			//TODO MulticastManager thread start
			metrorun.mmanager.startIfNotRunning();

			// 초기화 이전에 특정 페이지가 열려 있으면 초기 화면을 열지 않는다.
			String getResult = bridge.CommandSendTo(true, uDEF.TARGET_WINDOW1, "open_done");
			udebug.lm(33, "Window1 open done = %s", getResult);
			if (false == "true".equals(getResult)) {
				getResult = bridge.CommandSendTo(true, uDEF.TARGET_WINDOW1, "get_url");
				udebug.lm(33, "Opened window1 url = %s", getResult);
				// url 을 열기 전에 ping test를 하고, 응답이 없으면 기본 페이지를 연다.
				if (null == getResult || "null".equals(getResult)) {
					udebug.lm(33, "show TARGET_WINDOW2");
					bridge.CommandSendTo(false, uDEF.TARGET_WINDOW2, "show");
					udebug.lm(33, "open splash TARGET_WINDOW2");
					bridge.CommandSendTo(false, uDEF.TARGET_WINDOW2, "open", "value", "file:///android_asset/setup/splash.html");
					bridge.CommandSendTo(false, uDEF.TARGET_WINDOW1, "open", "value", start_url);
					//bridge.CommandSendTo(false, uDEF.TARGET_OVERLAY_BOTTOM, "open", "value", "file:///android_asset/setup/bottom.html");
				} else {
					udebug.lm(33, "Already open page : %s, length : %d", getResult, getResult.length());
				}
			}
			
			mSendKeyThread.start();

			check_saved_md5_thread.start();

			udebug.lm(33, "End -------------------");
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see android.os.Handler.Callback#handleMessage(android.os.Message)
	 */
	@Override
	public boolean handleMessage(Message msg) {
		// { 필수코드
		if (uBridge.WHAT_CONNECTED == msg.what) {
			return false;
		}
		if (uBridge.WHAT_RESPONSE == msg.what) {
			return false;
		}
		// } 필수코드

//		if (uATSCController.MESSAGE_WHAT_ATSC_MESSENGER == msg.what) {
//			mAtscController.receiveMessengerMessage(msg.arg1, msg.arg2);
//			return false;
//		}

		String to = "";
		String from = "";
		String sxml = "";

		Bundle data = null;
		data = msg.getData();

		if (null != data) {
			from = data.getString("from");
			to = data.getString("to");
			sxml = data.getString("data");
		}

		udebug.cmd(36, ">> >> [MainActivity] from = %s", from);
		udebug.cmd(36, ">> >> [MainActivity] to = %s", to);
		udebug.cmd(36, ">> >> [MainActivity] msg.what = %d", msg.what);
		udebug.cmd(36, ">> >> [MainActivity] uptime = %d", msg.arg2);
		udebug.cmd(36, ">> >> [MainActivity] data = %s", sxml);

		uXmlCommand cmd = new uXmlCommand(sxml);

		Target(cmd);
		
		cmd.release();
		cmd = null;
		return true;
	}

	public void Target(uXmlCommand cmd) {
		StringTokenizer to = new StringTokenizer(cmd.to(), "|");
		while (to.hasMoreElements()) {
			String starget = to.nextToken();
			if (starget.equals(uDEF.TARGET_WINDOW1)) {
				Command(starget,cmd);
			} else if (starget.equals(uDEF.TARGET_WINDOW2)) {
				Command(starget,cmd);
			} else if (starget.equals(uDEF.TARGET_POPUP)) {
				Command(starget,cmd);
			} else if (starget.equals(uDEF.TARGET_VIDEO)) {
				Command(starget,cmd);
			} else if (starget.equals(uDEF.NAME_LAUNCHER)) {
				Command(starget,cmd);
			} else if (starget.equals(uDEF.TARGET_METRO)) {
				if (null != metrorun) {
					metrorun.Command(starget, cmd);
				}
			} else {
				udebug.lm(31, "UnKnown %s", cmd.GetXml());
			}
		}
	}

	private void Command(String target, uXmlCommand cmd) {
		Boolean bcommand = false;
		String request = cmd.GetAtt("request");
		final String strCmd = cmd.cmd();
		
		udebug.lm("strCmd = %s",strCmd);

		if ("UnKnown".equals(strCmd)){
		}else if ("action".equals(strCmd)){
			bcommand = run.action(target, cmd);
			
		} else if ("callback".equals(strCmd)){
			bcommand = run.callback(target, cmd);
			
		} else if ("can_go_back".equals(strCmd)){
			bcommand = run.can_go_back(target, cmd);
			
		} else if ("firmwareupdate".equals(strCmd)){
			bcommand = run.firmwareupdate(target, cmd);
			
		} else if ("forced_rotation".equals(strCmd)){
			bcommand = run.forced_rotation(target, cmd);
			
		} else if ("full_reversion".equals(strCmd)){
			bcommand = run.full_reversion(target, cmd);
			
		} else if ("get_forced_rotation".equals(strCmd)){
			bcommand = run.get_forced_rotation(target, cmd);
			
		} else if ("get_pkg_list".equals(strCmd)){
			bcommand = run.get_pkg_list(target, cmd);
						
		} else if ("get_pkg_version".equals(strCmd)){
			bcommand = run.get_pkg_version(target, cmd);
			
		} else if ("get_setupinfo".equals(strCmd)){
			bcommand = run.get_setupinfo(target, cmd);
			
//		} else if ("get_unknown_sources".equals(strCmd)){
//			bcommand = run.get_unknown_sources(target, cmd);
			
		} else if ("get_url".equals(strCmd)){
			bcommand = run.get_url(target, cmd);
			
		} else if ("go_back".equals(strCmd)){
			bcommand = run.go_back(target, cmd);
			
		} else if ("hide".equals(strCmd)){
			bcommand = run.hide(target, cmd);
			
		} else if ("home".equals(strCmd)){
			bcommand = run.home(target, cmd);
			
		} else if ("hotkey_table".equals(strCmd)){
			bcommand = run.hotkey_table(target, cmd);
			
		} else if ("install".equals(strCmd)){
			bcommand = run.install(target, cmd);

		} else if ("intent".equals(strCmd)){
			bcommand = run.intent(target, cmd);

		} else if ("iptv".equals(strCmd)){
			bcommand = run.iptv(target, cmd);

		} else if ("is_show".equals(strCmd)){
			bcommand = run.is_show(target, cmd);

		} else if ("key".equals(strCmd)){
			bcommand = run.key(target, cmd);

		} else if ("open".equals(strCmd)){
			bcommand = run.open(target, cmd);

		} else if ("open_done".equals(strCmd)){
			bcommand = run.open_done(target, cmd);

		} else if ("play".equals(strCmd)){
			bcommand = run.play(target, cmd);
			
		} else if ("play_callback".equals(strCmd)){
			bcommand = run.play_callback(target, cmd);
			
		} else if ("play_info".equals(strCmd)){
			bcommand = run.play_info(target, cmd);
			
		} else if ("play_pause".equals(strCmd)){
			bcommand = run.play_pause(target, cmd);
			
		} else if ("play_pauseplay".equals(strCmd)){
			bcommand = run.play_pauseplay(target, cmd);
			
		} else if ("play_seek".equals(strCmd)){
			bcommand = run.play_seek(target, cmd);
			
		} else if ("play_start".equals(strCmd)){
			bcommand = run.play_start(target, cmd);
			
		} else if ("play_stop".equals(strCmd)){
			bcommand = run.play_stop(target, cmd);
			
		} else if ("play_subtitle".equals(strCmd)){
			bcommand = run.play_subtitle(target, cmd);
			
		} else if ("play_subtitle_synctime".equals(strCmd)){
			bcommand = run.play_subtitle_synctime(target, cmd);
			
		} else if ("set_setupinfo".equals(strCmd)){
			bcommand = run.set_setupinfo(target, cmd);
			
		} else if ("reboot".equals(strCmd)){
			bcommand = run.reboot(target, cmd);
			
		} else if ("restart".equals(strCmd)){
			bcommand = run.restart(target, cmd);
			
		} else if ("sethome".equals(strCmd)){
			bcommand = run.sethome(target, cmd);
			
		} else if ("show".equals(strCmd)){
			bcommand = run.show(target, cmd);

		} else if ("softkeyboard".equals(strCmd)){
			bcommand = run.softkeyboard(target, cmd);
			
		} else if ("source_reversion".equals(strCmd)){
			bcommand = run.source_reversion(target, cmd);
			
		} else if ("toast".equals(strCmd)){
			bcommand = run.toast(target, cmd);
			
		} else if ("touch".equals(strCmd)){
			bcommand = run.touch(target, cmd);
			
		} else if ("uninstall".equals(strCmd)){
			bcommand = run.uninstall(target, cmd);

		} else if ("unknown_sources".equals(strCmd)){
			bcommand = run.unknown_sources(target, cmd);

		}
		
		if (false == bcommand) {
			udebug.lm(31, "bcommand false = %s", cmd.GetXml());
		}
		
		if(true == "true".equals(request)){
			bridge.ResponseData(cmd, "%s", bcommand);
		}		
	}
	
	public void OnEvent(Intent intent) {
		String saction = intent.getAction();

		if(Intent.ACTION_BOOT_COMPLETED.equals(saction)){
			OnBootCompleted();
		} else {
			//  /mnt/sdcard/sub_sda1
			udebug.lm("intent.getData().getPath() = %s",intent.getData().getPath());
			udebug.lm("intent.getDataString() = %s",intent.getDataString());
			
			MainActivity.WriteLog("evt","%s = %s, %s \r\n",saction,intent.getData().getPath(),intent.getDataString());
			
			if (null != bridge) {
				bridge.CommandSendTo(false, uDEF.NAME_MANAGER, "action", "name", saction, "value", intent.getData().getPath());
			}
			
			if(saction.equals(ConnectivityManager.CONNECTIVITY_ACTION)){
				// network event
			}
		}
	}

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);
		udebug.lm(33, "requestCode[%d] resultCode[%d] data[%s]", requestCode, resultCode, (data == null ) ? data : data.getDataString());
	}

	public void OnBootCompleted() {
		if (null != m_main_Handler) {
			// boot completed & run start
			udebug.lm(33, "monCreateHandler.removeCallbacks(monCreateRunnable)");
			m_main_Handler.removeCallbacks(monCreateRunnable);
			udebug.lm(33, "monCreateHandler.postDelayed(monCreateRunnable, 100)");
			m_main_Handler.postDelayed(monCreateRunnable, 100);
		}
	}

	private void OnStartService() {
		// create
		if (null == intentShowService) {
			intentShowService = new Intent(this, uShowService.class);
			intentShowService.putExtra("from", uDEF.NAME_SHOW_SERVICE);
//			mAtscController = new uATSCController(MainActivity.this);

			// start
			cnShowService = startService(intentShowService);
//			mAtscController.doStartService();

			udebug.lm(33, "new Thread ");
//			Thread bindAtsc = new Thread(new Runnable() {
//				@Override
//				public void run() {
//					udebug.lm(33, "mAtscController.doBindService()");
//					mAtscController.doBindService();
//				}
//			});
//			bindAtsc.setName("MainActivity.OnStartService.bindAtsc");
//			bindAtsc.start();

			udebug.lm(33, "new Thread ");
			Thread bindShowService = new Thread(new Runnable() {
				@Override
				public void run() {
					udebug.lm(33, "bindService(intentShowService, mShowServiceConn");
					if (null != cnShowService) {
						bindService(intentShowService, mShowServiceConn, Context.BIND_AUTO_CREATE);
					}
				}
			});
			bindShowService.setName("MainActivity.OnStartService.bindShowService");
			bindShowService.start();
	
			udebug.lm(33, "new Thread ");
			Thread bindSystemSettings = new Thread(new Runnable() {
				@Override
				public void run() {
					udebug.lm(33, "bindService(intent, mSettingService");
					// system setting service start
					Intent intent = new Intent("com.android.usystemsettings.uSystemSettingService");
					bindService(intent, mSystemSettingService, BIND_AUTO_CREATE);
				}
			});
			bindSystemSettings.setName("MainActivity.OnStartService.bindSystemSettings");
			bindSystemSettings.start();
		}
	}
	
	public void OnToast(int ms, String msg, Object...args){
		mtoast.Set(ms, msg, args);
		
		if(null != m_main_Handler){
			m_main_Handler.post(new Runnable(){
				@Override
				public void run() {
					mtoast.Show();
				}
			});
		}
	}

	// private MediaPlayer mp = null;
	// //////////////////////////////////////////////////////////////
	// main
	// //////////////////////////////////////////////////////////////
//	
	private void onCreateBridge(){

		uBroadcastReceiver mbr = new uBroadcastReceiver();
		
		udebug.lm(35, "===============================");
		udebug.lm(35, "+ R.string.project = %s +", getResources().getString(R.string.project));
		udebug.lm(35, "+ R.string.svnreversion = %s +", getResources().getString(R.string.svnreversion));

		String kernelVersion = null;
		kernelVersion = SystemProperties.get("ro.build.version.incremental", "0");

		udebug.lm(35, "+ ro.build.version.incremental(Kernel build version) = %s +", kernelVersion);
		udebug.lm(35, "===============================");

		udebug.lm(33, "Begin ============================================");

		udebug.lm(33, "eth0 = %s", Utils.getMACAddress("eth0"));
		udebug.lm(33, "wlan0 = %s", Utils.getMACAddress("wlan0"));
		udebug.lm(33, "ip4 = %s", Utils.getIPAddress(true));
		udebug.lm(33, "ip6 = %s", Utils.getIPAddress(false));
		
		if(null == mSystemControl){
			mSystemControl = new uSystemController(this);
		}

		if(null == marrKeyQ){
			marrKeyQ = new ArrayList<Integer>();
		}
		
		if(null == bridge){
			bridge = new uBridge(uDEF.NAME_LAUNCHER);
		}
		
		if(null == mviews){
			mviews = new uViewGroup();
			mviews.SetBridge(bridge);
			mviews.AddView(uViewGroup.VIEW_VIDEO, new uView("video", this, R.id.videoView1, uView.TYPE_VIDEO));
			mviews.AddView(uViewGroup.VIEW_WINDOW1, new uView("window1", this, R.id.webView1, uView.TYPE_WEB));
			mviews.AddView(uViewGroup.VIEW_WINDOW2, new uView("window2", this, R.id.webView2, uView.TYPE_WEB));
//			mviews.AddView(uViewGroup.VIEW_POPUP, new uView("popup", this, R.id.popup, uView.TYPE_WEB));

			uWebView v = mviews.GetView(uViewGroup.VIEW_WINDOW2).GetWebView();
			if (null != v) {
				v.setBackgroundColor(Color.TRANSPARENT);
			}
			
			// Launcher
			if (null != bridge) {
				bridge.SetCallBack((Handler.Callback) this);
				bridge.AddTargets(uDEF.TARGET_VIDEO, uDEF.TARGET_WINDOW1
						, uDEF.TARGET_WINDOW2, uDEF.TARGET_POPUP);
				bridge.AddTargets(uDEF.TARGET_METRO);
			}
		}

		if(null == xmlManager){
			xmlManager = new uXMLManager();
			xmlManager.SetDumpPath("%s/system.xml", getCacheDir());
			xmlManager.SetSystemReference(mSystemControl);
			
			udebug.lm("xmlManager.CreateThread() \n");
			xmlManager.CreateThread();
			
			uBridge Launcher2Manager = xmlManager.NewAddBridge(uDEF.NAME_LAUNCHER);
			if (null != bridge) {
				udebug.lm("bridge.onServiceConnected(null, Launcher2Manager.GetBinder()) \n");
				bridge.onServiceConnected(null, Launcher2Manager.GetBinder());
			}
		}
		if(null == mShowServiceConn){
			uBridge ShowService2Manager = xmlManager.NewAddBridge(uDEF.NAME_SHOW_SERVICE);
			mShowServiceConn = ShowService2Manager;
			ShowService2Manager.AddTargets(uDEF.TARGET_OVERLAY_TOP, uDEF.TARGET_OVERLAY_CENTER,
					uDEF.TARGET_OVERLAY_BOTTOM);
			ShowService2Manager.AddTargets(uDEF.TARGET_OVERLAY_HIDDEN);
			ShowService2Manager.AddTargets(uDEF.TARGET_OVERLAY_OSD_CHANNEL_NUMBER);
			ShowService2Manager.AddTargets(uDEF.TARGET_OVERLAY_OSD_REMAIN_TIME, uDEF.TARGET_OVERLAY_OSD_WATCH_TIME_END,
					uDEF.TARGET_OVERLAY_OSD_MUTE);
		}
		if (null == mSystemSettingService) {
			uBridge SystemSettingService = xmlManager.NewAddBridge(uDEF.NAME_SYSTEM_SETTING_SERVICE);
			mSystemSettingService = SystemSettingService;
			SystemSettingService.AddTargets(uDEF.TARGET_NETWORK_CONTROLLER,uDEF.TARGET_DISPLAY_CONTROLLER);
		}
		if(null != run){
			run.SetupCmdLauncher(this, bridge, mSystemControl, mviews);
		}
		
		if(null != metrorun){
			metrorun.SetupCmdLauncher(this, bridge, mviews);
		}

		mIsCreate = true;
	}
	
	
	public Boolean OnKeyEvent(KeyEvent event){
		// udebug.dkey(event);

		final int code = event.getKeyCode();
		final int act = event.getAction();

		if (KeyEvent.KEYCODE_ENDCALL != code) {
			synchronized (mSystemControl) {
				String displayOn = mSystemControl.getSetupInfo("backlight");
				if (true == "false".equals(displayOn)) {
					return true;
				}
			}
		}

//		if(false == speedkey.CheckTime(event)){
//			udebug.lm(34, "droup key %d %d", code, act);
//			return true;
//		}
		
		String hotkey_name = null;
		hotkey_name = hotkeys.Search(code, act);
		if (null != hotkey_name && 0 < hotkey_name.length()) {
			/*
			 * drop key 조건
			 * 1. keycode는 같으나 action이 다른 경우
			 * 2. key disable true 되어 있는 경우
			 * 3. Search가 된경우 disable true로 변경된다.
			 * 4. hotkey_event에서 명령어 수행후 disable false 해주어야 한다.
			 */
			
			if("drop".equals(hotkey_name)){
				udebug.lm(36, "Drop Key %d %d",event.getAction(), event.getKeyCode());
				return true;
			}
			// send key
			if (null != bridge) {
				bridge.CommandSendTo(false, uDEF.NAME_MANAGER, "hotkey_event", "name", hotkey_name, "keycode",
						Integer.toString(code), "scancode", Integer.toString(event.getScanCode()), "action",
						Integer.toString(act));
			}
			return true; // skip key
		}

		switch (act) {
			case KeyEvent.ACTION_UP:
				if (10 <= marrKeyQ.size()) {
					marrKeyQ.remove(0);
				}
				marrKeyQ.add(code);

				if (true == chekKey(marrKeyQ, "12369")) {
					udebug.lm(36, "On Key 12369");
					udebug.lm(33, "android.provider.Settings.ACTION_SETTINGS = [%s]",android.provider.Settings.ACTION_SETTINGS);
					startActivity(new Intent(android.provider.Settings.ACTION_SETTINGS));
				}

				if (true == chekKey(marrKeyQ, "12347")) {
					udebug.lm(36, "On Key 12347");
					String init_html = uDEF.PathSDCARD_main_init_html;
					File file = new File(init_html);
					if (null != bridge) {
						if (file.isFile()) {
							bridge.CommandSendTo(false, uDEF.TARGET_WINDOW1, "open", "value", "file://" + file.getAbsolutePath());
						} else {
//							bridge.CommandSendTo(false, uDEF.TARGET_WINDOW1, "open", "value", msi.initurl);
							bridge.CommandSendTo(false, uDEF.TARGET_WINDOW1, "open", "value", "file:///android_asset/setup/setup.html");
						}
					}
				}

				if (true == chekKey(marrKeyQ, "15987")) {
					udebug.lm(36, "On Key 15987");
					String usb_update_zip = uDEF.PathSDCARD + "/sub_sda1/update.zip";
					Upgrade(usb_update_zip);
				}
				break;
			case KeyEvent.ACTION_MULTIPLE:
				break;
			default:
				break;
		}

		// 1. view 상태 확인
		// 2. key 전달 여부 확인
		// 3. home 이면 skip
		// 4. home 아니면 webview back 키

		// mviews.GetView(starget);
		// mv.GetWebView().CallbackKeyEvent(keycode, scancode, action);

		if (null != mviews && null != mviews.GetView(mviews.GetFocusId())) {
			int itype = mviews.GetView(mviews.GetFocusId()).GetType();
			if (uView.TYPE_WEB == itype || uView.TYPE_OVERLAY_WEB == itype ) {
				boolean done = mviews.GetView(mviews.GetFocusId()).GetWebView().GetKeyCallbackDone();
				if (true == done) {
					return true;
				}

				mviews.GetView(mviews.GetFocusId()).GetWebView()
						.CallbackKeyEvent(code, event.getScanCode(), act);
			}
		}

		// video view 의 콘트롤을 직접 하기를 원할 수 있다.
		// key 전달이 아닌 직접 구현할 경우 key를 전달받지 않기를 원할 수도 있다.
		// 추후 고민해 보자
		switch (code) {
			case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
			case KeyEvent.KEYCODE_MEDIA_STOP:
			case KeyEvent.KEYCODE_MEDIA_NEXT:
			case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
			case KeyEvent.KEYCODE_MEDIA_REWIND:
			case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
				if (null != mviews) {
					uSurfaceView msv = null;
					msv = mviews.GetView(uViewGroup.VIEW_VIDEO).GetVideoView();
					if (msv.isShow()) {
						udebug.lm(33, "show Video View toss key event");
						msv.dispatchKeyEvent(event);
					}
				}
				break;
		}

		// bridge.CommandSendTo(false, uDEF.TARGET_WINDOW1,"key",
		// "keycode", Integer.toString(code),
		// "scancode", Integer.toString(event.getScanCode()),
		// "action",Integer.toString(act)
		// );

		if(KeyEvent.KEYCODE_MENU == code){
			// Android key skip
			return true;
		}
		
		if(KeyEvent.KEYCODE_BACK == code){
			// Android key skip
//			if(KeyEvent.ACTION_UP == act){
//				View mv = mviews.GetFocusView();
//				if(null != mv){
//					if(null != mv.GetWebView()){
//						udebug.cd(33,"[%s] mv.GetWebView().goBack()",mv.GetName());
//						mv.GetWebView().goBack();
//					}
//				}
//			}
			// H/E 2013.04.08 back key skip
			return true;
		}		
		return false;
	}

	////////////////////////////////////////////////////////////////
	
	@Override
	public void onConfigurationChanged(Configuration newConfig) {
		udebug.InFnc();
		//udebug.cd(35,"SKIP super.onConfigurationChanged(newConfig)");
		super.onConfigurationChanged(newConfig);
	}

	private static final String SYS_BOOT_COUNT = "persist.sys.bootcount";
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		//
		//if(true == Utils.FileExist(uDEF.PathSDCARD + "/"))
		//
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		thiz = this;

		MetroHexControl.ResumeWatchdog();
		String watchdogResult = MetroHexControl.Watchdog();
		udebug.lm(33, "watchdogResult = %s", watchdogResult);

		new Handler().postDelayed(new Runnable() {
			@Override
			public void run() {
				// Set boot count start
				String bCount = SystemProperties.get(SYS_BOOT_COUNT);
				Integer c = 0;
				if (null != bCount && 0 != bCount.length()) {
					c = Integer.valueOf(bCount);
				}
				++c;
				Log.i("[ModLauncher2]", SYS_BOOT_COUNT + " = " + bCount + " -> " + c);
				SystemProperties.set(SYS_BOOT_COUNT, c.toString());
				// Set boot count end
			}
		}, 1 * 100);	// Increase boot count

		if (null == mMainView) {
			mMainView = (RelativeLayout) findViewById(R.id.mainView);
		}

//		KillMySelfThread.kill_myself = false;

		uDEF.InitPath( getResources().getString(R.string.project));
		uDebug.Config(); // check is_sdcard_mount
		uDebug.ToFile();
		
		if (null != mLogUploadThread && !mLogUploadThread.isAlive()) {
			udebug.lm(33, "Start log auto upload thread");
			mLogUploadThread.start();
		}

		if(uDebug.IsSignalRestart()){
			// reboot
			udebug.error("-----------");
			udebug.error("s i g n a l");
			udebug.error("-----------");
			udebug.error("REBOOT");
			udebug.error("-----------");
			PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
			pm.reboot(null);
			return;
		}
		/* CAUTION: enable only in metroapp */
//		String spid = null;
//		spid = Utils.getPID("com.android.metro.metrofirst");
//		if(null != spid && 0 < spid.length()){
//			PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
//			pm.reboot(null);
//			udebug.error("I am metroapp, metrofirst is still alive! reboot system");
//			return;
//		}

		// 아직 완성되지 않은 코드
		// kmsg 캡춰 실패 하였다
//		if(null == gkmsg){
//			gkmsg = new GetKMsg();
//			gkmsg.Start();
//		}
		
		udebug.lm("uDebug.is_sdcard_mount = %b", uDebug.is_sdcard_mount);
		
		if(false == uDebug.is_sdcard_mount){
			Log.e("[MetroLauncher]", "[onCreate] sdcard not mounted, restart after 5 seconds");
			mSelfKillHandler.postDelayed(mSelfKillRunnable , 5 * 1000);
			return;
		}

		check_kill_metro_timer.schedule(check_kill_metro_task, 5 * 1000, KILL_METRO_PERIOD);

		if (android.os.Build.VERSION.SDK_INT > 9) {
			// service bind time out을 처리하기 위한 옵션
			// 사용화 에서는 제거하는 것이 좋다고 하는데?
			// 제거하면 어떻게 해야 할까?
			StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
			StrictMode.setThreadPolicy(policy);
		}

		
		udebug.lm(33, "Begin ============================================");

		getWindow().setFlags(
				WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
				WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);		
		
		int version = android.os.Build.VERSION.SDK_INT;
		if(version > 14){
			getWindow().addFlags(16777216);
		}		
		
		try {
			int iautotime = 0;
			iautotime = android.provider.Settings.System.getInt(getContentResolver(), android.provider.Settings.Global.AUTO_TIME);
			android.provider.Settings.System.putInt(getContentResolver(), android.provider.Settings.Global.AUTO_TIME, 0);
			//iautotime = android.provider.Settings.System.getInt(getContentResolver(), android.provider.Settings.Global.AUTO_TIME);
			//android.provider.Settings.System.putInt(getContentResolver(), android.provider.Settings.Global.AUTO_TIME, 0);
			udebug.m("iautotime:%d", iautotime);
		} catch (SettingNotFoundException e) {
			udebug.error("Error %s", e.getMessage());
			e.printStackTrace();
		}
		
		getWindow().getDecorView().setSystemUiVisibility(
				View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
				View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
				View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
				View.SYSTEM_UI_FLAG_LOW_PROFILE
				);

		if(null == metrolog){
			metrolog = new MetroLog(this);
			metrolog.Start();
		}
		
		if(null == m_main_Handler){
			
			if(!MetroNetwork.isNetworkEnable()){
				MetroNetwork.DHCP_enable();
			}
			
			udebug.lm(35,"+==================================+");
			udebug.lm(35,"+ MetroNetwork.isEnableEth0 = %b +",MetroNetwork.isEnableEth0);
			udebug.lm(35,"+ IP = %s               +",Utils.getIPAddress(true));
			udebug.lm(35,"+==================================+");
			
			UpdateResorce();
			
			/*
			if(null == metrolog){
				metrolog = new MetroLog(this);
				metrolog.write("Application Start");
				// start get resource
				metrolog.Start();
			}
			*/
			
			udebug.lm(33, "InitializeFolder() \n");
			InitializeFolder();
			m_main_Handler = new Handler();
			
			// boot completed & run start
			udebug.lm(33, "monCreateHandler.postDelayed(monCreateRunnable, 3000)");
			m_main_Handler.postDelayed(monCreateRunnable, 3000);
			java.lang.System.setProperty("java.net.preferIPv6Addresses", "false");
			java.lang.System.setProperty("java.net.preferIPv4Stack", "true");
			
		}else{
			udebug.lm(33, "monCreateHandler.postDelayed(monCreateRunnable, 10000)");
			m_main_Handler.postDelayed(monCreateRunnable, 10000);
		}
		
		if(null == mtoast){
			mtoast = new uToast(this);
		}

		udebug.lm(33, "End ============================================");
	}

	@Override
	protected void onResume() {
		super.onResume();
		udebug.InFnc();

		if(false == uDebug.is_sdcard_mount) {
			Log.e("[ModLauncher2]", "[onResume] sdcard not mounted, return");
			return;
		}

		udebug.OutFnc();
	}

	@Override
	protected void onPause() {
		super.onPause();
		udebug.InFnc();
		udebug.OutFnc();
	}

	@Override
	protected void onStop() {
		super.onStop();
		udebug.InFnc();
		udebug.OutFnc();
	}

	@Override
	protected void onDestroy() {
		super.onDestroy();

		udebug.InFnc();

		MetroMulticastManager.metroAPI.ClearMessage();

		if (mSendKeyThread.isAlive() && !mSendKeyThread.isInterrupted()) {
			mSendKeyRunning = false;
			mSendKeyThread.interrupt();
			mSendKeyThread = null;
		}

		if (null != mviews) {
			mviews.Destroy();
		}

		if (null != mSelfKillHandler) {
			mSelfKillHandler.removeCallbacks(mSelfKillRunnable);
			mSelfKillHandler = null;
		}
		
//		if (null != check_saved_md5_handler) {
//			check_saved_md5_handler.removeCallbacks(check_saved_md5_runnable);
////			check_saved_md5_handler = null;
//		}

		if (null != check_kill_metro_task) {
			check_kill_metro_task.cancel();
			check_kill_metro_task = null;
		}

		if (null != check_kill_metro_timer) {
			check_kill_metro_timer.cancel();
			check_kill_metro_timer.purge();
			check_kill_metro_timer = null;
		}
		
		if(null != metrorun){
			metrorun.Destroy();
			metrorun = null;
		}
		
		if (true == mShowServiceConnected) {
			unbindService(mShowServiceConn);
			mShowServiceConnected = false;
			mShowServiceConn = null;
		}
		if (true == mSystemSettingServiceConnected) {
			unbindService(mSystemSettingService);
			mSystemSettingServiceConnected = false;
			mSystemSettingService = null;
		}
//		if (null != mAtscController) {
//			mAtscController.doUnbindService();
//			mAtscController = null;
//		}
		if (null != mSystemControl) {
			synchronized (mSystemControl) {
				mSystemControl.exit();
				mSystemControl = null;
			}
		}
		
		if(null != m_main_Handler){
			// boot completed & run stop
			udebug.lm(33, "monCreateHandler.removeCallbacks(monCreateRunnable)");
			m_main_Handler.removeCallbacks(monCreateRunnable);
			m_main_Handler = null;
		}

		if (null != mviews) {
			for (int i=0; i < uViewGroup.VIEW_MAX; i++) {
				if (null != mviews.GetView(i) && null != mviews.GetView(i).GetWebView()) {
					mviews.GetView(i).GetWebView().removeThread();
				}
			}
		}

		if (null != mHttpd) {
			mHttpd.stop();
		}

		
//		if(null != gkmsg){
//			gkmsg.Stop();
//			gkmsg = null;
//		}

//		KillMySelfThread.stop();

		udebug.OutFnc();
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see android.app.Activity#dispatchKeyEvent(android.view.KeyEvent)
	 */
	@Override
	public boolean dispatchKeyEvent(KeyEvent event) {
		Boolean result = false;
		
		if (true == bUpgradeWorking) {
			udebug.lm(31, "Key Drop Upgrade");
			udebug.dkey(event);
			return true;
		}
		
		if (false == mIsCreate){
			return true;
		}
		
		result = OnKeyEvent(event);
		if(true == result) return result;
		
		return super.dispatchKeyEvent(event);
	}

	// //////////////////////////////////////////////////////////////////////////////////////////////////////
	// //////////////////////////////////////////////////////////////////////////////////////////////////////
	// //////////////////////////////////////////////////////////////////////////////////////////////////////

	private Boolean chekKey(ArrayList<Integer> keyQ, String skey) {
		byte[] keys = skey.getBytes();
		Boolean bre = false;
		if (0 < keys.length && keys.length <= keyQ.size()) {
			bre = true;
			for (int i = 0; i < keys.length; i++) {
				int ikey = keyQ.get(keyQ.size() - keys.length + i).byteValue();
				ikey = ikey - KeyEvent.KEYCODE_0 + 48; // 48 = '0'
				// udebug.cd(33, "[%c] = [%c]",keys[i], ikey);
				if (keys[i] != ikey) {
					return false;
				}
			}
		}
		return bre;
	}

	private void InitializeFolder() {
		int i = 0;
		String[] ftree = new String[10];
		
		ftree[i++] = uDEF.PathSDCARD_project;
		ftree[i++] = uDEF.PathSDCARD_main;
		ftree[i++] = uDEF.PathSDCARD_storage;
		ftree[i++] = uDEF.PathSDCARD_storage_database;
		ftree[i++] = uDEF.PathSDCARD_download;
		ftree[i++] = uDEF.PathSDCARD_download_firmware;
		ftree[i++] = uDEF.PathSDCARD_download_main;
		ftree[i++] = uDEF.PathSDCARD_download_apps;
		ftree[i++] = uDEF.PathSDCARD_log;
		ftree[i++] = uDEF.PathSDCARD_log_metro;
		
		File root = new File(uDEF.PathSDCARD);

		Environment.getExternalStorageDirectory().getAbsolutePath();
		udebug.m(33,"ExternalStorage.getPath = %s", Environment.getExternalStorageDirectory().getPath());
		udebug.m(33,"ExternalStorage.getAbsolutePath = %s", Environment.getExternalStorageDirectory().getAbsolutePath());

		if (null != getCacheDir()) {
			udebug.m(33, "getCacheDir.getPath = %s", getCacheDir().getPath());
			udebug.m(33, "getCacheDir.getAbsolutePath = %s", getCacheDir().getAbsolutePath());
		}else{
			udebug.m(31, "getCacheDir.getPath = null");
		}
		
		udebug.lm("uDEF.PathSDCARD = " + uDEF.PathSDCARD);
		udebug.lm("root.getPath() = " + root.getPath());
		udebug.lm("root.isDirectory() = " + root.isDirectory());

		if (true == root.isDirectory()) {
			for (i = 0; i < ftree.length; i++) {
				File mk = new File(ftree[i]);
				if (false == mk.isDirectory()) {
					boolean result = mk.mkdirs();
					//udebug.lm("mkdirs = " + mk.toString() + " | result = " + result);
					if(result){
						udebug.lm(33,"PathSDCARD = [%s]",ftree[i]);
					}else{
						udebug.lm(31,"PathSDCARD = [%s] Error",ftree[i]);
					}
				}else{
					udebug.lm("PathSDCARD = [%s]",ftree[i]);
				}
			}
		}

		File path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
		String filePath = path.getAbsolutePath();
		udebug.lm(33, "Environment.DIRECTORY_DOWNLOADS = %s", filePath);

	}
	
	public String CatAsset(String sfile, Object... args) {
		String stxt = null;
		AssetManager am = getAssets(); 
		InputStream is = null;
		ByteArrayOutputStream baos = null;

		try {
			
			is = am.open(Utils.StringFormat(sfile, args));
			baos = new ByteArrayOutputStream();
			
			byte[] buffer = new byte[1024];
			int readsize = 0;
			
			while (-1 != (readsize = is.read(buffer, 0, 1024))) {
				baos.write(buffer, 0, readsize);
			}
			stxt = baos.toString();
			baos.close();
			baos = null;
			is.close();
			is = null;
		} catch (FileNotFoundException e) {
			Log.v("", "Error " + e.getMessage());
			e.printStackTrace();
		} catch (IOException e) {
			Log.v("", "Error " + e.getMessage());
			e.printStackTrace();
		} finally {
			try {
				if (null != is) is.close();
				is = null;
			} catch (IOException e) {
				Log.v("", "Error " + e.getMessage());
				e.printStackTrace();
			}
		}
		return stxt;
	}	

	private void UpdateResorce(){
		
		msi.build = getResources().getString(R.string.buildtime);
		msi.projectName = getResources().getString(R.string.project);
		msi.version.source = getResources().getString(R.string.svnreversion);
		msi.projectName = msi.projectName.trim();
		msi.version.source = msi.version.source.trim();
		
//		String resolution = getResources().getString(R.string.resolution);
		String resolution = null;
		resolution = SystemProperties.get("ro.ubicod.metro.display.mode", "768p");
		if(null != resolution && "1080p".equals(resolution)){
			msi.modelType = "PID";
		}else{
			msi.modelType = "RD";
		}

		udebug.lm("msi.build= %s", msi.build);
		udebug.lm("msi.projectName= %s", msi.projectName);
		udebug.lm("msi.version.source= %s", msi.version.source);
		udebug.lm("msi.modelType= %s", msi.modelType);
		udebug.lm("resolution= %s", resolution);

		// get version
		if(Utils.FileExist("%s/version", uDEF.PathSDCARD_main)){
			final String assetUiVer = CatAsset("setup/version");
			final String sdcardUiVer = Utils.Cat("%s/version", uDEF.PathSDCARD_main);

			//20150408 Check Main UI Version on App side
			long curVer = Utils.convertVersion(assetUiVer);
			long newVer = Utils.convertVersion(sdcardUiVer);
			if( curVer < newVer ) {
				udebug.lm(33, "There is a newer UI on SDCARD [asset:%s][sdcard:%s]", assetUiVer, sdcardUiVer);
				msi.version.main = sdcardUiVer;
				msi.initurl =  "file:///sdcard/metro/main/intro.html";
			} else {
				udebug.lm(33, "There is an older or same UI on SDCARD [asset:%s][sdcard:%s]", assetUiVer, sdcardUiVer);
				msi.initurl =  "file:///android_asset/setup/intro.html";
				msi.version.main = assetUiVer;
			}
		}else{
			udebug.lm(33, "There is no UI on SDCARD");
			msi.version.main = CatAsset("setup/version");
			msi.initurl =  "file:///android_asset/setup/intro.html";
		}
		if (null == msi.version.main || 0 >= msi.version.main.length()) {
			msi.version.main = "0.0.0";
		}
		msi.version.main = msi.version.main.trim();
		
		try {
			PackageInfo info = null;
			info = getPackageManager().getPackageInfo(getPackageName(), 0);
			msi.version.launcher = info.versionName;
		} catch (NameNotFoundException e) {
			udebug.lm(31, "Error = %s", e.getMessage());
			e.printStackTrace();
		}
		msi.version.launcher = msi.version.launcher.trim();
		
		udebug.lm("msi.projectName= %s", msi.projectName);
		udebug.lm("msi.version.main= %s", msi.version.main);
		udebug.lm("msi.version.launcher= %s", msi.version.launcher);
		udebug.lm("msi.version.source= %s", msi.version.source);
	}
	
	private void UpdateInfo() {
		if (null != bridge) {
//			String value = "";
			uXmlCommand cmd = new uXmlCommand();
			// auto load
			// 1 load default config
			// 1-1 현재 안드로이드 세팅 값을 /system/info/network 에 그대로 저장한다.
//			cmd.New("sync", "from", bridge.GetName(), "to", uDEF.TARGET_NETWORK_CONTROLLER);
//			bridge.CommandSendTo(true, cmd);
//
//			// 1-2 /system/storage/network 내용이 있는지 검사, 있으면 그 설정을 따른다.
//			// 1-3 /system/storage/network 내용이 없거나 불충분할 경우 아무것도 하지 않는다.
//			uXmlCommand networkCmd = new uXmlCommand();
//			networkCmd.New("get", "from", bridge.GetName(), "to", uDEF.TARGET_SYSTEM, "path", "/system/storage/network");
//
//			String networkCmdResult = bridge.CommandSendTo(true, networkCmd);
//			udebug.cmd(33, "networkCmdResult = %s", networkCmdResult);
//
//			if (null != networkCmdResult && 0 < networkCmdResult.length()) {
//				udebug.lm("networkCmdResult = %s", networkCmdResult);
//
//				if (false == networkCmdResult.equals(uDEF.RESPONSE_FAIL)) {
//					networkCmd.SetXml(networkCmdResult);
//
//					networkCmdResult = networkCmd.GetNodeValue("ifname");
//
//					udebug.lm(33, "networkCmdResult(ifname) : %s", networkCmdResult);
//
//					String type = null;
//					String ip = null;
//
//					if (null != networkCmdResult && 0 < networkCmdResult.length()) {
//						if (true == networkCmdResult.equals("eth0")) {
//							type = networkCmd.GetNodeValue("eth0/netinfo/type");
//							ip = networkCmd.GetNodeValue("eth0/netinfo/ip");
//
//							if (null != type && 0 < type.length()) {
//								String gateway = networkCmd.GetNodeValue("eth0/netinfo/gateway");
//								String subnet = networkCmd.GetNodeValue("eth0/netinfo/subnet");
//								String dns = networkCmd.GetNodeValue("eth0/netinfo/dns");
//								bridge.CommandSendTo(true, uDEF.TARGET_NETWORK_CONTROLLER, "set", "ifname", "eth0", "type", type, "ip", ip, "gateway", gateway, "subnet", subnet, "dns", dns);
//							}
//						} else if (true == networkCmdResult.equals("wlan0")) {
//							type = networkCmd.GetNodeValue("wlan0/netinfo/type");
//							ip = networkCmd.GetNodeValue("wlan0/netinfo/ip");
//
//							if (null != type && 0 < type.length()) {
//								String ssid = networkCmd.GetNodeValue("wlan0/ssid");
//								String passwd = networkCmd.GetNodeValue("wlan0/passwd");
//								String gateway = networkCmd.GetNodeValue("wlan0/netinfo/gateway");
//								String subnet = networkCmd.GetNodeValue("wlan0/netinfo/subnet");
//								String dns = networkCmd.GetNodeValue("wlan0/netinfo/dns");
//								bridge.CommandSendTo(true, uDEF.TARGET_NETWORK_CONTROLLER, "set", "ifname", "wlan0", "ssid", ssid, "passwd", passwd, "type", type, "ip", ip, "gateway", gateway, "subnet", subnet, "dns", dns);
//							}
//						} else {
//							udebug.lm(31, "unknown device name : %s", networkCmdResult);
//						}
//					} else {
//						networkCmd.New("get", "from", bridge.GetName(), "to", uDEF.TARGET_SYSTEM, "path", "/system/info/network/ifname");
//						networkCmdResult = bridge.CommandSendTo(true, networkCmd);
//						networkCmd.SetXml(networkCmdResult);
//						networkCmdResult = networkCmd.GetValue();
//
//						// network device name 이 없는 경우(인터넷 연결이 안된 경우)
//						if (null == networkCmdResult || 0 >= networkCmdResult.length()) {
//							udebug.lm(33, "Connect eth0 dhcp (default)");
//
//							networkCmd.New("set", "from", bridge.GetName(), "to", uDEF.TARGET_SYSTEM, "path", "/system/storage");
//							networkCmd.NewNodeName("network","ifname","eth0");
//							networkCmd.NewNodeName("network/eth0/netinfo","type","dhcp");
//							
//							bridge.CommandSendTo(true, networkCmd);
//							Thread t = new Thread(new Runnable() {
//								@Override
//								public void run() {
//									bridge.CommandSendTo(false, uDEF.TARGET_NETWORK_CONTROLLER, "set", "ifname", "eth0", "type", "dhcp");
//								}
//							});
//							t.setName("MainActivity.SetNetwork");
//							t.start();
//						} else {
//							udebug.lm(33, "Do nothing, device is online, no network setting");
//						}
//					}
//
//					// 20130806 shkang 네트워크 연결 체크를 JoinMulticast 직전으로 이동
//					int timeout = 1;
//					final int TIME_OUT_MAX = 5;
//					ip = null;
//
//					while (true) {
//						udebug.lm(33, "Wait for connect... %d times... (%d seconds)", timeout, timeout);
//
//						Utils.Sleep(1000);
//
//						if (TIME_OUT_MAX <= timeout) {
//							udebug.lm(31, "Can not connect ethernet/wifi. Time out(%d)", timeout);
//							break;
//						}
//
//						networkCmd.New("get", "from", bridge.GetName(), "to", uDEF.TARGET_SYSTEM, "path", "/system/info/network");
//						networkCmdResult = bridge.CommandSendTo(true, networkCmd);
//
//						udebug.cmd(33, "networkCmdResult = %s", networkCmdResult);
//						networkCmd.SetXml(networkCmdResult);
//						ip = networkCmd.GetNodeValue("eth0/netinfo/ip");
//						if (null != ip && 0 < ip.length()) break;
//						ip = networkCmd.GetNodeValue("wlan0/netinfo/ip");
//						if (null != ip && 0 < ip.length()) break;
//
//						timeout++;
//					}
//				}
//			}

			// 2. version set
			cmd.New("set", "from", bridge.GetName(), "to", uDEF.TARGET_SYSTEM, "path", "/system/info");
			cmd.NewNodeName("project","name",msi.projectName);
			cmd.NewNodeName("version","main",msi.version.main);
			cmd.NewNodeName("version","launcher",msi.version.launcher);
			cmd.NewNodeName("version","source",msi.version.source);

			bridge.CommandSendTo(false, cmd);

//			cmd.New("get", "from", bridge.GetName(), "to", uDEF.TARGET_SYSTEM, "path", "/system/storage/pvs");
//			value = bridge.CommandSendTo(true, cmd);
//			udebug.lm("sxml = %s", value);
//			if (null != value && false == value.equals(uDEF.RESPONSE_FAIL)) {
//				cmd.SetXml(value);
//				value = cmd.GetNodeAtt("", "enable");
//				if(null == value || 0 >= value.length()){
//					// attribute에 없을 경우 node에서 검사하자
//					value = cmd.GetNodeValue("enable");
//				}
//				
//				if (null != value && value.equals("true")) {
//					msi.pvs.enable = true;
//				}
//				value = cmd.GetNodeValue("url");
//				if (null != value) {
//					msi.pvs.url = uDEF.Macro(value);
//				}
//			}
//
//			cmd.New("get", "from", bridge.GetName(), "to", uDEF.TARGET_SYSTEM, "path", "/system/storage/mainurl");
//			value = bridge.CommandSendTo(true, cmd);
//			udebug.lm("sxml = %s", value);
//			if (null != value && false == value.equals(uDEF.RESPONSE_FAIL)) {
//				cmd.SetXml(value);
//				value = cmd.GetValue();
//				if (null != value && 0 < value.length()) {
//					msi.mainurl = value;
//				}
//			}
			
//			networkCmd.release();
//			networkCmd = null;
			
			cmd.release();
			cmd = null;
		}
		

		udebug.lm(33, "PVS");
		udebug.lm(33, "PVS enable = %s", msi.pvs.enable);
		udebug.lm(33, "PVS url = %s", msi.pvs.url);
	}

	public void Upgrade(String sfile, Object... args) {

		String usb_update_zip = Utils.StringFormat(sfile, args);
		String update_zip = "";
		if (true == bUpgradeWorking) {
			udebug.lm(33, "bUpgradeWorking Skip %s", usb_update_zip);
			return;
		}

		Message msg = null;

		msg = Message.obtain(null, MESSAGE_ID_METRO_UPDATE_RSP, 70, 0);
		mMetroUpdateRspHandler.sendMessage(msg);
//		msg.recycle();	// return message to pool

		if(false == usb_update_zip.startsWith("/nand/")){
			
			File file = new File(usb_update_zip);
			if(false == file.isFile() || 70*1024*1024 > file.length()){
				udebug.lm(31, "upgrade cancel return");
				bUpgradeWorking = false;
				String callback = null;
				callback = Utils.StringFormat("javascript:%s('%s')", "setMulticastStatus", "false");
				udebug.lm(31, "callback [%s]", callback);
				if (null != bridge) {
					bridge.CommandSendTo(false, uDEF.TARGET_WINDOW1, "callback", "value", callback);
				}
				return;
			}
		}

		do {
			if (usb_update_zip.equals(uDEF.PathSDCARD + File.separator + "update.zip")) {
				update_zip = "/nand/update.zip";
				udebug.lm(33, "update_zip = %s", update_zip);
			} else if (false == usb_update_zip.equals("/nand/update.zip")) {
				File file = new File(usb_update_zip);
				if (file.exists()) {
					// prevent sdcard
					/**uDebug.StopLogcat();*/
					Utils.Sleep(100);
					update_zip = usb_update_zip.replace("sdcard/", "data/media/0/");
					MetroHexControl.StopWatchdog();
					udebug.lm(33, "update_zip = %s, stop HW Watchdog", update_zip);
				} else {
					udebug.lm(31, "upgrade cancel return");
					bUpgradeWorking = false;
					String callback = null;
					callback = Utils.StringFormat("javascript:%s('%s')", "setMulticastStatus", "false");
					udebug.lm(31, "callback [%s]", callback);
					if (null != bridge) {
						bridge.CommandSendTo(false, uDEF.TARGET_WINDOW1, "callback", "value", callback);
					}
					return;
				}

				/*
				if (true == file.isFile()) {
					udebug.lm(35, "copy %s to %s", usb_update_zip, "/data/media/0/update.zip");

					FileInputStream in = null;
					FileOutputStream out = null;
					int iread = 0;
					byte[] buffer = new byte[8192];
					File target = new File("/data/media/0/update.zip");
					if (true == target.isFile()) target.delete();
	
					try {
						in = new FileInputStream(file);
						out = new FileOutputStream(target);
						bUpgradeWorking = true;
						while (0 < (iread = in.read(buffer))) {
							out.write(buffer, 0, iread);
						}
						in.close();
						out.close();
						out.flush();
						in = null;
						out = null;
						update_zip = "/data/media/0/update.zip";
						//bUpgradeWorking = false;
						//Upgrade(new String(update_zip));
						//return;
						break;
					} catch (IOException e) {
						e.printStackTrace();
						udebug.lm(31, "Error %s", e.getMessage());
						bUpgradeWorking = false;
					}
					try {
						if (null != in) in.close();
						if (null != out) {
							out.flush();
							out.close();
						}
						in = null;
						out = null;
					} catch (IOException e1) {
						udebug.lm(31, "Error %s", e1.getMessage());
						e1.printStackTrace();
					}
					if (false == bUpgradeWorking) {
						return;
					}
				} else {
					udebug.lm(31, "upgrade cancel return");
					bUpgradeWorking = false;
					String callback = null;
					callback = Utils.StringFormat("javascript:%s('%s')", "setMulticastStatus", "false");
					udebug.lm(31, "callback [%s]", callback);
					if (null != bridge) {
						bridge.CommandSendTo(false, uDEF.TARGET_WINDOW1, "callback", "value", callback);
					}
					return;
				}
				*/
			}
		}while(false);

		bUpgradeWorking = true;
//		Intent intent = new Intent();
		udebug.lm(35, "===================================");
		udebug.lm(35, "                             |     ");
		udebug.lm(35, ".   .,---.,---.,---.,---.,---|,---.");
		udebug.lm(35, "|   ||   ||   ||    ,---||   ||---'");
		udebug.lm(35, "`---'|---'`---|`    `---^`---'`---'");
		udebug.lm(35, "     |    `---'                    ");
		udebug.lm(35, "===================================");
		udebug.lm(35, "update_zip = %s", update_zip);

		udebug.lm(33, "msg start");
		msg = Message.obtain(null, MESSAGE_ID_METRO_UPDATE_RSP, 100, 0);
		mMetroUpdateRspHandler.sendMessage(msg);
//		msg.recycle();	// return message to pool

		udebug.lm(33, "msg end, sync start");
		Utils.exec2("busybox sync");
		udebug.lm(33, "sync end");

		// shkang 20140205 fix firmware upgrade bug
		udebug.lm(33, "Start upgrade reboot handler 0");
		mCheckUpgradeRebootRunnable.setFile(new File(update_zip));
		mUpgradeRebootHandler.post(mCheckUpgradeRebootRunnable);
		udebug.lm(33, "Start upgrade reboot handler 1");

		bUpgradeWorking = false;
	}

	public boolean getUrlInfo() {
		udebug.InFnc();

		URL serverUrl = null;
		HttpURLConnection con = null;

		try {
			String strxml = "";
			BufferedReader reader = null;

			String strUrlInfoUrl = SERVER_URL + "initialize.do?stdMac=" + Utils.getMACAddress("eth0");
			udebug.lm("strUrlInfoUrl = " + strUrlInfoUrl);

			serverUrl = new URL(strUrlInfoUrl);
			con = (HttpURLConnection) serverUrl.openConnection();
			con.setRequestMethod("GET");
			con.setReadTimeout(30 * 1000);
			con.connect();

			strxml = "";
			if (HttpURLConnection.HTTP_OK == con.getResponseCode()) {
				String strline = null;
				reader = new BufferedReader(new InputStreamReader(con.getInputStream()));
				while (null != (strline = reader.readLine())) {
					strxml += strline;
				}
				reader.close();
				reader = null;
				con.disconnect();
				con = null;
			}

			udebug.lm("strxml = " + strxml);

			XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
			factory.setNamespaceAware(true);
			XmlPullParser parser = factory.newPullParser();
			parser.setInput(new StringReader(strxml));

			int eventType = parser.getEventType();

			while (eventType != XmlPullParser.END_DOCUMENT) {

				switch (eventType) {
					case XmlPullParser.START_DOCUMENT:
						udebug.lm("XmlPullParser.START_DOCUMENT");
						break;
					case XmlPullParser.END_DOCUMENT:
						break;
					case XmlPullParser.START_TAG:
						udebug.lm("XmlPullParser.START_TAG");
						String tag = parser.getName();

						if (tag.equals("initUrl")) {
						}
						udebug.lm(tag);

						break;
					case XmlPullParser.END_TAG:
						udebug.lm("XmlPullParser.END_TAG");
						break;

					case XmlPullParser.TEXT:
						udebug.lm("XmlPullParser.TEXT");
						break;
				}
				eventType = parser.next();
			} // while
			parser = null;

		} catch (IOException e) {
			udebug.lm("IOException" + e.getMessage());
			if (null != con) con.disconnect();
			e.printStackTrace();
		} catch (XmlPullParserException e) {
			udebug.lm("IOException" + e.getMessage());
			e.printStackTrace();
		}

		return true;
	}

	public void setSetupInfo(String kind, String value) {
		if (null == mSystemControl) {
			udebug.lm(31, "mSystemControl is null");
			return;
		}

		synchronized (mSystemControl) {
			mSystemControl.setSetupInfo(kind, value);
		}
	}

	public String getSetupInfo(String kind) {
		String result = null;
		if (null == mSystemControl) {
			udebug.lm(31, "mSystemControl is null, return \"false\"");
			return null;
		}

		synchronized (mSystemControl) {
			result = mSystemControl.getSetupInfo(kind);
		}

		return result;
	}

	public uBridge getBridge() {
		return this.bridge;
	}
	
	public String source_version(){
		return msi.version.source;
	}
	
	public String full_reversion(){
		return msi.version.launcher + "." + msi.version.source;
	}
	
	public void HotkeyUpdate(JSONArray json){
		hotkeys.Update(json);
	}

	// set은 없음
	public Boolean isUprading() {
		return bUpgradeWorking;
	}

	public void SendKey(int keycode) {
		mSendKeyThread.addKey(keycode);
	}
	
	public void BlockSendKey(boolean block) {
		mSendKeyThread.setBlockAddKey(block);
	}
	
	public void ShowDoorBroken(boolean show) {
		if (show) {
			mDoorBroken.sendEmptyMessage(MSG_WHAT_DOOR_BROKEN_SHOW);
		} else {
			mDoorBroken.sendEmptyMessage(MSG_WHAT_DOOR_BROKEN_HIDE);
		}
	}
}
