org.mortbay.ijetty.IJetty.java Source code

Java tutorial

Introduction

Here is the source code for org.mortbay.ijetty.IJetty.java

Source

//========================================================================
//$Id: IJetty.java 474 2012-01-23 03:07:14Z janb.webtide $
//Copyright 2008 Mort Bay Consulting Pty. Ltd.
//------------------------------------------------------------------------
//Licensed under the Apache License, Version 2.0 (the "License");
//you may not use this file except in compliance with the License.
//You may obtain a copy of the License at 
//http://www.apache.org/licenses/LICENSE-2.0
//Unless required by applicable law or agreed to in writing, software
//distributed under the License is distributed on an "AS IS" BASIS,
//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//See the License for the specific language governing permissions and
//limitations under the License.
//========================================================================

package org.mortbay.ijetty;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;

import org.eclipse.jetty.util.IO;
import org.json.JSONObject;
import org.mortbay.ijetty.component.AddressInfo;
import org.mortbay.ijetty.html5webview.HTML5WebView;
import org.mortbay.ijetty.javascript.ProxyBridge;
import org.mortbay.ijetty.log.AndroidLog;
import org.mortbay.ijetty.movieservice.MediaPlaybackService;
import org.mortbay.ijetty.movieservice.MyFloatView;
import org.mortbay.ijetty.network.DownloadManager;
import org.mortbay.ijetty.network.IRequestListener;
import org.mortbay.ijetty.network.InterfaceOp;
import org.mortbay.ijetty.util.AndroidInfo;
import org.mortbay.ijetty.util.ApkUtils;
import org.mortbay.ijetty.util.IJettyToast;
import org.mortbay.ijetty.util.PlayListUtil;
import org.mortbay.ijetty.util.PropertiesUtils;
import org.mortbay.ijetty.util.StringUtils;

import android.app.Activity;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Configuration;
import android.graphics.Point;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.text.Html;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Display;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.View.OnClickListener;
import android.webkit.WebSettings;
import android.widget.Button;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;

/**
 * IJetty
 * 
 * Main Jetty activity. Can start other activities: + configure + download
 * 
 * Can start/stop services: + IJettyService
 */
public class IJetty extends Activity {

    private static final String TAG = "Jetty";
    private static IJetty instance;
    public HTML5WebView mWebView;
    private PropertiesUtils mPropertiesUtil;

    public static final String __START_ACTION = "org.mortbay.ijetty.start";
    public static final String __STOP_ACTION = "org.mortbay.ijetty.stop";
    public static final String __START_MOVIE_ACTION = "org.mortbay.ijetty.movie.start";
    public static final String __STOP_MOVIE_ACTION = "org.mortbay.ijetty.movie.stop";

    public static final String __PORT = "org.mortbay.ijetty.port";
    public static final String __NIO = "org.mortbay.ijetty.nio";
    public static final String __SSL = "org.mortbay.ijetty.ssl";

    public static final String __CONSOLE_PWD = "org.mortbay.ijetty.console";
    public static final String __PORT_DEFAULT = "8080";
    public static final boolean __NIO_DEFAULT = true;
    public static final boolean __SSL_DEFAULT = false;

    public static final String __CONSOLE_PWD_DEFAULT = "admin";

    public static final String __WEBAPP_DIR = "webapps";
    public static final String __ETC_DIR = "etc";
    public static final String __CONTEXTS_DIR = "contexts";
    public static final String __UPLOAD_DIR = "console/demo/upload";

    public static final String __TMP_DIR = "tmp";
    public static final String __WORK_DIR = "work";
    public static final int __SETUP_PROGRESS_DIALOG = 0;
    public static final int __SETUP_DONE = 2;
    public static final int __SETUP_RUNNING = 1;
    public static final int __SETUP_NOTDONE = 0;

    public static final File __JETTY_DIR;
    private Button startButton;
    private Button stopButton;
    private Button configButton;
    private TextView footer;
    private TextView info;
    private TextView console;
    private ScrollView consoleScroller;
    private StringBuilder consoleBuffer = new StringBuilder();
    private Runnable scrollTask;
    private ProgressDialog progressDialog;
    private Thread progressThread;
    private Handler handler;
    private BroadcastReceiver bcastReceiver;

    class ConsoleScrollTask implements Runnable {
        public void run() {
            consoleScroller.fullScroll(View.FOCUS_DOWN);
        }
    }

    /**
     * ProgressThread
     *
     * Handles finishing install tasks for Jetty.
     */
    class ProgressThread extends Thread {
        private Handler _handler;

        public ProgressThread(Handler h) {
            _handler = h;
        }

        public void sendProgressUpdate(int prog) {
            Message msg = _handler.obtainMessage();
            Bundle b = new Bundle();
            b.putInt("prog", prog);
            msg.setData(b);
            _handler.sendMessage(msg);
        }

        public void run() {
            boolean updateNeeded = isUpdateNeeded();

            //create the jetty dir structure
            File jettyDir = __JETTY_DIR;
            if (!jettyDir.exists()) {
                boolean made = jettyDir.mkdirs();
                Log.i(TAG, "Made " + __JETTY_DIR + ": " + made);
            }

            sendProgressUpdate(10);

            //Do not make a work directory to preserve unpacked
            //webapps - this seems to clash with Android when
            //out-of-date webapps are deleted and then re-unpacked
            //on a jetty restart: Android remembers where the dex
            //file of the old webapp was installed, but it's now
            //been replaced by a new file of the same name. Strangely,
            //this does not seem to affect webapps unpacked to tmp?
            //Original versions of i-jetty created a work directory. So
            //we will delete it here if found to ensure webapps can be
            //updated successfully.
            File workDir = new File(jettyDir, __WORK_DIR);
            if (workDir.exists()) {
                Installer.delete(workDir);
                Log.i(TAG, "removed work dir");
            }

            //make jetty/tmp
            File tmpDir = new File(jettyDir, __TMP_DIR);
            if (!tmpDir.exists()) {
                boolean made = tmpDir.mkdirs();
                Log.i(TAG, "Made " + tmpDir + ": " + made);
            } else {
                Log.i(TAG, tmpDir + " exists");
            }

            //make jetty/webapps
            File webappsDir = new File(jettyDir, __WEBAPP_DIR);
            if (!webappsDir.exists()) {
                boolean made = webappsDir.mkdirs();
                Log.i(TAG, "Made " + webappsDir + ": " + made);
            } else {
                Log.i(TAG, webappsDir + " exists");
            }

            //make jetty/etc
            File etcDir = new File(jettyDir, __ETC_DIR);
            if (!etcDir.exists()) {
                boolean made = etcDir.mkdirs();
                Log.i(TAG, "Made " + etcDir + ": " + made);
            } else {
                Log.i(TAG, etcDir + " exists");
            }
            sendProgressUpdate(30);

            //make Media2
            File media2Dir = new File(AppConstants.getMediaSdFolder());
            if (!media2Dir.exists()) {
                boolean made = media2Dir.mkdirs();
                Log.i(TAG, "Made " + etcDir + ": " + made);
            } else {
                Log.i(TAG, media2Dir + " exists");
            }

            File webdefaults = new File(etcDir, "webdefault.xml");
            if (!webdefaults.exists() || updateNeeded) {
                //get the webdefaults.xml file out of resources
                try {
                    InputStream is = getResources().openRawResource(R.raw.webdefault);
                    OutputStream os = new FileOutputStream(webdefaults);
                    IO.copy(is, os);
                    Log.i(TAG, "Loaded webdefault.xml");
                } catch (Exception e) {
                    Log.e(TAG, "Error loading webdefault.xml", e);
                }
            }
            sendProgressUpdate(40);

            File realm = new File(etcDir, "realm.properties");
            if (!realm.exists() || updateNeeded) {
                try {
                    //get the realm.properties file out resources
                    InputStream is = getResources().openRawResource(R.raw.realm_properties);
                    OutputStream os = new FileOutputStream(realm);
                    IO.copy(is, os);
                    Log.i(TAG, "Loaded realm.properties");
                } catch (Exception e) {
                    Log.e(TAG, "Error loading realm.properties", e);
                }
            }
            sendProgressUpdate(50);

            File keystore = new File(etcDir, "keystore");
            if (!keystore.exists() || updateNeeded) {
                try {
                    //get the keystore out of resources
                    InputStream is = getResources().openRawResource(R.raw.keystore);
                    OutputStream os = new FileOutputStream(keystore);
                    IO.copy(is, os);
                    Log.i(TAG, "Loaded keystore");
                } catch (Exception e) {
                    Log.e(TAG, "Error loading keystore", e);
                }
            }
            sendProgressUpdate(60);

            //make jetty/contexts
            File contextsDir = new File(jettyDir, __CONTEXTS_DIR);
            if (!contextsDir.exists()) {
                boolean made = contextsDir.mkdirs();
                Log.i(TAG, "Made " + contextsDir + ": " + made);
            } else {
                Log.i(TAG, contextsDir + " exists");
            }
            sendProgressUpdate(70);

            try {
                PackageInfo pi = getPackageManager().getPackageInfo(getPackageName(), 0);
                if (pi != null) {
                    setStoredJettyVersion(pi.versionCode);
                }
            } catch (Exception e) {
                Log.w(TAG, "Unable to get PackageInfo for i-jetty");
            }

            //if there was a .update file indicating an update was needed, remove it now we've updated
            File update = new File(__JETTY_DIR, ".update");
            if (update.exists())
                update.delete();

            sendProgressUpdate(80);

            //??
            File clientProps = new File(IJetty.__JETTY_DIR + "/" + IJetty.__ETC_DIR + "/properties.xml");
            try {
                if (!(clientProps.exists()) || clientProps.length() == 0) {
                    //          
                    mPropertiesUtil.readPropertiesFileFromXML(
                            IJetty.getInstance().getBaseContext().getAssets().open("properties.xml"));
                    mPropertiesUtil.writePropertiesFileToXML(clientProps.getAbsolutePath());

                    InputStream is = IJetty.getInstance().getBaseContext().getAssets().open("console.war");
                    FileOutputStream fos = new FileOutputStream(AppConstants.getMediaSdFolder() + "/console.war");
                    byte[] buffer = new byte[1024];
                    int count = 0;
                    while ((count = is.read(buffer)) > 0) {
                        fos.write(buffer, 0, count);
                    }
                    fos.close();
                    is.close();
                } else {
                    //?assets??
                    mPropertiesUtil.readPropertiesFileFromXML(
                            IJetty.getInstance().getBaseContext().getAssets().open("properties.xml"));
                    //String propVersion = mPropertiesUtil.getVersion();
                    Log.w("smallstar-defaultPropVersion", mPropertiesUtil.getVersion());
                    int defaultPropVersion = Integer.parseInt(mPropertiesUtil.getVersion());
                    mPropertiesUtil.readPropertiesFileFromXML(clientProps.getAbsolutePath());
                    Log.w("smallstar-curPropVersion", mPropertiesUtil.getVersion());
                    int curPropVersion = Integer.parseInt(mPropertiesUtil.getVersion());
                    if (defaultPropVersion > curPropVersion) {
                        //????????
                        //TODO???
                        mPropertiesUtil.readPropertiesFileFromXML(
                                IJetty.getInstance().getBaseContext().getAssets().open("properties.xml"));
                        mPropertiesUtil.writePropertiesFileToXML(clientProps.getAbsolutePath());
                        //?console.war
                        Log.w(TAG, "copy console.warSD??");
                        InputStream is = IJetty.getInstance().getBaseContext().getAssets().open("console.war");
                        FileOutputStream fos = new FileOutputStream(
                                AppConstants.getMediaSdFolder() + "/console.war");
                        byte[] buffer = new byte[1024];
                        int count = 0;
                        while ((count = is.read(buffer)) > 0) {
                            fos.write(buffer, 0, count);
                        }
                        fos.close();
                        is.close();
                    }
                    Log.w(TAG, "===========================================================");
                    AppConstants.CLIENT_CUR_PLAYURL = mPropertiesUtil.getPlayUrl();
                    Log.w(TAG, AppConstants.CLIENT_CUR_PLAYURL);
                    Log.w(TAG, "===========================================================");
                    //                    Toast.makeText(IJetty.getInstance().getApplicationContext(), AppConstants.CLIENT_CUR_PLAYURL,
                    //                            Toast.LENGTH_SHORT).show();

                    PlayListUtil.playListVersion = mPropertiesUtil.getPlayListVersion();
                    ApkUtils.apkPushVersion = mPropertiesUtil.getApkPushVersion();
                }
            } catch (IOException e) {
                // TODO Auto-generated catch block
                Log.w("smallstar------>", "!clientProps.exists() error!!!!!!");
                e.printStackTrace();
            }

            sendProgressUpdate(100);
        }
    };

    static {
        __JETTY_DIR = new File(Environment.getExternalStorageDirectory(), "jetty");
        //        if(StringUtils.replaceBlank(Build.MODEL).equals("EC3MBXboard") || StringUtils.replaceBlank(Build.MODEL).equals("EC3AdBoard"))
        //        {
        //            __JETTY_DIR = new File(AmlogicExt.getExternalStorage2Directory(),"jetty");
        //        }
        //        else
        //        {
        //            __JETTY_DIR = new File(Environment.getExternalStorageDirectory(),"jetty");
        //        }
        // Ensure parsing is not validating - does not work with android
        System.setProperty("org.eclipse.jetty.xml.XmlParser.Validating", "false");

        // Bridge Jetty logging to Android logging
        System.setProperty("org.eclipse.jetty.util.log.class", "org.mortbay.ijetty.AndroidLog");
        org.eclipse.jetty.util.log.Log.setLog(new AndroidLog());
    }

    public static IJetty getInstance() {
        return instance;
    }

    public IJetty() {
        super();

        handler = new Handler() {
            public void handleMessage(Message msg) {
                int total = msg.getData().getInt("prog");
                progressDialog.setProgress(total);
                if (total >= 100) {
                    dismissDialog(__SETUP_PROGRESS_DIALOG);
                }
            }

        };
    }

    public String formatJettyInfoLine(String format, Object... args) {
        String ms = "";
        if (format != null)
            ms = String.format(format, args);
        return ms + "<br/>";
    }

    public void consolePrint(String format, Object... args) {
        String msg = String.format(format, args);
        if (msg.length() > 0) {
            consoleBuffer.append(msg).append("<br/>");
            console.setText(Html.fromHtml(consoleBuffer.toString()));
            Log.i(TAG, msg); // Only interested in non-empty lines being output to Log
        } else {
            consoleBuffer.append(msg).append("<br/>");
            console.setText(Html.fromHtml(consoleBuffer.toString()));
        }

        if (scrollTask == null) {
            scrollTask = new ConsoleScrollTask();
        }

        consoleScroller.post(scrollTask);
    }

    protected int getStoredJettyVersion() {
        File jettyDir = __JETTY_DIR;
        if (!jettyDir.exists()) {
            return -1;
        }
        File versionFile = new File(jettyDir, "version.code");
        if (!versionFile.exists()) {
            return -1;
        }
        int val = -1;
        ObjectInputStream ois = null;
        try {
            ois = new ObjectInputStream(new FileInputStream(versionFile));
            val = ois.readInt();
            return val;
        } catch (Exception e) {
            Log.e(TAG, "Problem reading version.code", e);
            return -1;
        } finally {
            if (ois != null) {
                try {
                    ois.close();
                } catch (Exception e) {
                    Log.d(TAG, "Error closing version.code input stream", e);
                }
            }
        }
    }

    //////////////////////////////////////////
    private Handler mHandler = new Handler() {
        public void handleMessage(android.os.Message msg) {
            switch (msg.what) {
            case AppConstants.MSG_SHOW_WEATHER: {
                AddressInfo addrInfo = AddressInfo.getInstance();
                if (TextUtils.isEmpty(addrInfo.getCityName())) {
                    //                                mWeatherTv.setText("?");
                    //                                mWeatherTv.setVisibility(View.VISIBLE);
                    //                                mWeatherImg1.setVisibility(View.GONE);
                    //                                mWeatherImg2.setVisibility(View.GONE);
                    return;
                }
                String info = null;
                if (!TextUtils.isEmpty(addrInfo.getProName())) {
                    info = "    " + addrInfo.getProName() + addrInfo.getCityName() + "          ";
                } else {
                    info = "       " + addrInfo.getCityName() + "          ";
                }
                String weatherInfo = info + msg.getData().getString("weatherMsg");
                String imgUrl1 = msg.getData().getString("imgUrl1");
                String imgUrl2 = msg.getData().getString("imgUrl2");
                if (TextUtils.isEmpty(msg.getData().getString("weatherMsg"))) {
                    //                                mWeatherTv.setText("?");
                    //                                mWeatherTv.setVisibility(View.VISIBLE);
                    //                                mWeatherImg1.setVisibility(View.GONE);
                    //                                mWeatherImg2.setVisibility(View.GONE);
                    return;
                }
                //                        mWeatherTv.setText(weatherInfo);
                //                        mWeatherTv.setVisibility(View.VISIBLE);
                //                        PhotoLoader loader = new PhotoLoader(MainActivity.this,
                //                                        MainActivity.this, R.drawable.cloud_ico);
                //                        mWeatherImg1.setVisibility(View.VISIBLE);
                //                        mWeatherImg2.setVisibility(View.VISIBLE);
                //                        loader.loadPhoto(mWeatherImg1, imgUrl1);
                //                        loader.loadPhoto(mWeatherImg2, imgUrl2);

                break;
            }
            case AppConstants.MSG_INSTALL_COMPLETE: {
                if (msg.arg1 == ApkUtils.SUCCEEDED) {
                    // Log.e("gary", "mHandler install success");
                    //                              String packagename = msg.getData().getString("packagename");
                    //                              if (packagename.equals("com.mylayout.app"))
                    //                                      ApkUtils.startApk(packagename,
                    //                                                      ".MainActivity");
                } else {
                    // Log.e("gary", "mHandler install failed");
                }
            }
                break;
            case AppConstants.MSG_REQUEST_DOWNLOAD: {
                long vStartToNowTime = System.currentTimeMillis() - StartupReceiver.START_TIME;
                if (vStartToNowTime > AppConstants.START_DOWNLOAD_TIME) {
                    downloadMsg(msg);
                } else {
                    Message vMsg = mHandler.obtainMessage();
                    mHandler.sendMessageDelayed(vMsg, AppConstants.START_DOWNLOAD_TIME - vStartToNowTime);
                }
            }
                break;
            case AppConstants.MSG_UPDATE_TIME:
                //                        mTimeTv.setText(mTimeStr);
                //                        if (mTimeStr.equals("00:00:00")) {
                //                                setDate();
                //                        } else if (mTimeStr.endsWith("00:00")) {
                //                                updateAll();
                //                        } else if (mTimeStr.endsWith("04:00")) {
                //                                WeatherAndAddressUtil.initAddressInfo(mHandler);
                //                        }
                break;
            case AppConstants.MSG_SHOW_MESSAGE: {
                String msgStr = msg.getData().getString("msg");
                if (TextUtils.isEmpty(msgStr))
                    return;
                //vMainText.setText(msgStr.trim());
            }
                break;
            case AppConstants.MSG_RELOCATE_LOGOIMG: {

                IJetty.this.finish();
                //                      ApkUtils.startApk("com.mylayout.app",
                //                                      "com.mylayout.app.MainActivity");
            }

            case AppConstants.MSG_SUBMIT_APPS_LIST:
                //                      mHandler.removeMessages(AppConstants.MSG_SUBMIT_APPS_LIST);
                submitAppsList(mHandler);
                break;
            default:
                break;
            }
        };
    };

    private void downloadMsg(android.os.Message msg) {
        final String downloadUrl = msg.getData().getString("downloadUrl");
        final String savedName = msg.getData().getString("savedName");
        DownloadManager.getInstance().startDownload(downloadUrl, savedName);
    }

    public static void submitAppsList(final Handler pHandler) {
        InterfaceOp.protoSubmmitAppsList(new IRequestListener() {
            public void onError(Exception e) {
                // TODO Auto-generated method stub
                pHandler.sendEmptyMessageDelayed(AppConstants.MSG_SUBMIT_APPS_LIST,
                        AppConstants.DELAYED_SUBMIT_APPS_LIST);
            }

            public void onComplete(boolean isError, String errMsg, JSONObject respObj) {
                // TODO Auto-generated method stub
                if (isError)
                    pHandler.sendEmptyMessageDelayed(AppConstants.MSG_SUBMIT_APPS_LIST,
                            AppConstants.DELAYED_SUBMIT_APPS_LIST);
            }
        });
    }

    public String getDisplayScreenSize() {
        WindowManager w = getWindowManager();
        Display d = w.getDefaultDisplay();
        DisplayMetrics metrics = new DisplayMetrics();
        d.getMetrics(metrics);
        // since SDK_INT = 1;
        int widthPixels = metrics.widthPixels;
        int heightPixels = metrics.heightPixels;
        // includes window decorations (statusbar bar/menu bar)
        if (Build.VERSION.SDK_INT >= 14 && Build.VERSION.SDK_INT < 17)
            try {
                widthPixels = (Integer) Display.class.getMethod("getRawWidth").invoke(d);
                heightPixels = (Integer) Display.class.getMethod("getRawHeight").invoke(d);
            } catch (Exception ignored) {
                Log.e("-->smallstar", "getDisplayScreenSize error");
            }
        // includes window decorations (statusbar bar/menu bar)
        if (Build.VERSION.SDK_INT >= 17)
            try {
                Point realSize = new Point();
                Display.class.getMethod("getRealSize", Point.class).invoke(d, realSize);
                widthPixels = realSize.x;
                heightPixels = realSize.y;
            } catch (Exception ignored) {
                Log.e("-->smallstar", "getDisplayScreenSize error");
            }
        return String.valueOf(widthPixels) + "*" + String.valueOf(heightPixels);
    }

    @Override
    protected void onDestroy() {
        if (bcastReceiver != null)
            unregisterReceiver(bcastReceiver);
        super.onDestroy();
    }

    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);

        this.requestWindowFeature(Window.FEATURE_NO_TITLE);//?
        this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);//??

        MainApplication.getInstance().setAppHandler(mHandler);

        instance = this;
        mWebView = new HTML5WebView(this);
        mWebView.setScrollBarStyle(View.SCROLLBARS_OUTSIDE_OVERLAY);
        mWebView.setHorizontalScrollBarEnabled(false);//?
        mWebView.setVerticalScrollBarEnabled(false); //?

        mPropertiesUtil = new PropertiesUtils();

        //?
        Intent autoStarIntent = new Intent("com.mortbay.ijetty.IJetty");
        autoStarIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        autoStarIntent.addFlags(32);
        sendBroadcast(autoStarIntent);

        //??
        //DisplayMetrics dm = new DisplayMetrics();
        //getWindowManager().getDefaultDisplay().getMetrics(dm);
        AppConstants.RESOLUTION = getDisplayScreenSize(); //String.valueOf(dm.widthPixels) + "*" + String.valueOf(getDisplayScreenHeight());    //dm.widthPixels,dm.heightPixels

        //??
        File clientProps = new File(IJetty.__JETTY_DIR + "/" + IJetty.__ETC_DIR + "/properties.xml");
        try {
            if (clientProps.exists() && clientProps.length() != 0) {
                //?assets??
                mPropertiesUtil.readPropertiesFileFromXML(
                        IJetty.getInstance().getBaseContext().getAssets().open("properties.xml"));
                //String propVersion = mPropertiesUtil.getVersion();
                Log.w("smallstar-defaultPropVersion", mPropertiesUtil.getVersion());
                int defaultPropVersion = Integer.parseInt(mPropertiesUtil.getVersion());
                mPropertiesUtil.readPropertiesFileFromXML(clientProps.getAbsolutePath());
                Log.w("smallstar-curPropVersion", mPropertiesUtil.getVersion());
                int curPropVersion = Integer.parseInt(mPropertiesUtil.getVersion());
                if (defaultPropVersion > curPropVersion) {
                    //????????
                    //TODO???
                    mPropertiesUtil.readPropertiesFileFromXML(
                            IJetty.getInstance().getBaseContext().getAssets().open("properties.xml"));
                    mPropertiesUtil.writePropertiesFileToXML(clientProps.getAbsolutePath());
                    //?console.war
                    Log.w(TAG, "copy console.warSD??");
                    InputStream is = IJetty.getInstance().getBaseContext().getAssets().open("console.war");
                    FileOutputStream fos = new FileOutputStream(AppConstants.getMediaSdFolder() + "/console.war");
                    byte[] buffer = new byte[1024];
                    int count = 0;
                    while ((count = is.read(buffer)) > 0) {
                        fos.write(buffer, 0, count);
                    }
                    fos.close();
                    is.close();
                }
                Log.w(TAG, "===========================================================");
                AppConstants.CLIENT_CUR_PLAYURL = mPropertiesUtil.getPlayUrl();
                Log.w(TAG, AppConstants.CLIENT_CUR_PLAYURL);
                Log.w(TAG, "===========================================================");
                //                Toast.makeText(IJetty.getInstance().getApplicationContext(), AppConstants.CLIENT_CUR_PLAYURL,
                //                        Toast.LENGTH_SHORT).show();

                PlayListUtil.playListVersion = mPropertiesUtil.getPlayListVersion();
                ApkUtils.apkPushVersion = mPropertiesUtil.getApkPushVersion();
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            Log.w("smallstar------>", "!clientProps.exists() error!!!!!!");
            e.printStackTrace();
        }

        //??:(?)
        startService(new Intent(this, DaemonService.class));

        //js?
        ProxyBridge jsBridge = new ProxyBridge(this);
        mWebView.addJavascriptInterface(jsBridge, "ia");

        mWebView.setHorizontalScrollBarEnabled(false);

        setContentView(R.layout.jetty_controller);

        startButton = (Button) findViewById(R.id.start);
        startButton.setVisibility(View.GONE);//??
        stopButton = (Button) findViewById(R.id.stop);
        stopButton.setVisibility(View.GONE);//??
        configButton = (Button) findViewById(R.id.config);
        configButton.setVisibility(View.GONE);//??
        final Button downloadButton = (Button) findViewById(R.id.download);
        downloadButton.setVisibility(View.GONE);//??

        IntentFilter filter = new IntentFilter();
        filter.addAction(__START_ACTION);
        filter.addAction(__STOP_ACTION);
        filter.addAction(__START_MOVIE_ACTION);
        filter.addCategory("default");

        bcastReceiver = new BroadcastReceiver() {
            public void onReceive(Context context, Intent intent) {
                if (__START_ACTION.equalsIgnoreCase(intent.getAction())) {
                    startButton.setEnabled(false);
                    configButton.setEnabled(false);
                    stopButton.setEnabled(true);
                    consolePrint("<br/>Started Jetty at %s", new Date());
                    String[] connectors = intent.getExtras().getStringArray("connectors");
                    if (null != connectors) {
                        for (int i = 0; i < connectors.length; i++)
                            consolePrint(connectors[i]);
                    }

                    printNetworkInterfaces();

                    if (AndroidInfo.isOnEmulator(IJetty.this))
                        consolePrint("Set up port forwarding to see i-jetty outside of the emulator.");

                    //warFile = new File("file:///android_asset/console.war");
                    File file = new File(IJetty.__JETTY_DIR + "/" + IJetty.__WEBAPP_DIR + "/"
                            + "console/settings/basicsettings.html");
                    if (file.exists()) {
                        if (file.length() > 0) {
                            //Not empty, do something here.
                            //i-jetty???web?
                            setContentView(mWebView.getLayout());
                            //TODO?????
                            int onlineTimeout = 0;
                            do {
                                if (onlineTimeout > 10)
                                    break;
                                SystemClock.sleep(1000);
                                onlineTimeout++;
                            } while (!AppConstants.ONLINE_STATUS);

                            if (AppConstants.ONLINE_STATUS)//
                            {
                                mWebView.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
                                //mWebView.getSettings().setCacheMode( WebSettings.LOAD_NO_CACHE);
                                mWebView.clearHistory();
                                mWebView.clearFormData();
                                mWebView.clearCache(true);
                                mWebView.loadUrl(AppConstants.CLIENT_CUR_PLAYURL);
                            } else
                                mWebView.loadUrl("http://localhost:8080/console/settings/basicsettings.html");
                        }
                    }
                } else if (__STOP_ACTION.equalsIgnoreCase(intent.getAction())) {
                    startButton.setEnabled(true);
                    configButton.setEnabled(true);
                    stopButton.setEnabled(false);
                    consolePrint("<br/> Jetty stopped at %s", new Date());
                } else if (__START_MOVIE_ACTION.equalsIgnoreCase(intent.getAction())) {
                    //service?onCreate()?onStartCommand().
                    Log.i(TAG, "onReceive() get Broadcast org.mortbay.ijetty.movie.start");
                    Intent mIntent = new Intent("createUI");
                    mIntent.setClass(context, MediaPlaybackService.class);
                    context.startService(mIntent);
                }
            }

        };

        registerReceiver(bcastReceiver, filter);

        // Watch for button clicks.
        startButton.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                if (isUpdateNeeded())
                    IJettyToast.showQuickToast(IJetty.this, R.string.loading);
                else {
                    //TODO get these values from editable UI elements
                    Intent intent = new Intent(IJetty.this, IJettyService.class);
                    intent.putExtra(__PORT, __PORT_DEFAULT);
                    intent.putExtra(__NIO, __NIO_DEFAULT);
                    intent.putExtra(__SSL, __SSL_DEFAULT);
                    intent.putExtra(__CONSOLE_PWD, __CONSOLE_PWD_DEFAULT);
                    startService(intent);
                }
            }
        });

        stopButton.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                stopService(new Intent(IJetty.this, IJettyService.class));
            }
        });

        configButton.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                IJettyEditor.show(IJetty.this);
            }
        });

        downloadButton.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                IJettyDownloader.show(IJetty.this);
            }
        });

        info = (TextView) findViewById(R.id.info);
        info.setVisibility(View.GONE);
        footer = (TextView) findViewById(R.id.footer);
        footer.setVisibility(View.GONE);
        console = (TextView) findViewById(R.id.console);
        console.setVisibility(View.GONE);
        consoleScroller = (ScrollView) findViewById(R.id.consoleScroller);
        consoleScroller.setVisibility(View.GONE);

        StringBuilder infoBuffer = new StringBuilder();
        try {
            PackageInfo pi = getPackageManager().getPackageInfo(getPackageName(), 0);
            infoBuffer.append(formatJettyInfoLine("i-jetty version %s (%s)", pi.versionName, pi.versionCode));
        } catch (NameNotFoundException e) {
            infoBuffer.append(formatJettyInfoLine("i-jetty version unknown"));
        }
        infoBuffer.append(formatJettyInfoLine("On %s using Android version %s", AndroidInfo.getDeviceModel(),
                AndroidInfo.getOSVersion()));
        info.setText(Html.fromHtml(infoBuffer.toString()));

        StringBuilder footerBuffer = new StringBuilder();
        footerBuffer.append(
                "<b>Project:</b> <a href=\"http://code.google.com/p/i-jetty\">http://code.google.com/p/i-jetty</a> <br/>");
        footerBuffer.append("<b>Server:</b> http://www.eclipse.org/jetty <br/>");
        footerBuffer.append("<b>Support:</b> http://www.intalio.com/jetty/services <br/>");
        footer.setText(Html.fromHtml(footerBuffer.toString()));

        //??WEB?
        Intent intent = new Intent(IJetty.this, IJettyService.class);
        intent.putExtra(__PORT, __PORT_DEFAULT);
        intent.putExtra(__NIO, __NIO_DEFAULT);
        intent.putExtra(__SSL, __SSL_DEFAULT);
        intent.putExtra(__CONSOLE_PWD, __CONSOLE_PWD_DEFAULT);
        startService(intent);
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        mWebView.saveState(outState);
    }

    @Override
    public void onStop() {
        super.onStop();
        mWebView.stopLoading();
    }

    //    @Override
    //    public boolean dispatchTouchEvent(MotionEvent event)
    //    {
    //
    //        //??  
    //        float x = event.getX();
    //        float y = event.getY();
    //        switch (event.getAction())
    //        {
    //            //?  
    //            case MotionEvent.ACTION_DOWN:
    ////                Log.w(TAG, "MotionEvent.ACTION_DOWN");
    ////                Toast.makeText(IJetty.getInstance().getApplicationContext(), "MotionEvent.ACTION_DOWN",
    ////                Toast.LENGTH_SHORT).show();
    //                if (MyFloatView.mPlayViewPrepareStatus)
    //                {
    //                    Log.e("smallstar", "MyFloatView.mPlayViewPrepareStatus is true!");
    //                    MyFloatView.mPlayViewStatus = false;
    //                    MyFloatView.onExit();
    //                }
    //                if(!ApkUtils.isBackgroundRunning(IJetty.getInstance(), "com.suncco.weather"))
    //                {
    //                    Log.e("smallstar", "com.suncco.weather is not running.");
    //                    ApkUtils.startAppByPackageName("com.suncco.weather");
    //                }
    //                else
    //                {
    //                    Log.e("smallstar", "com.suncco.weather is running.");
    //                    ApkUtils.startAppByPackageName("com.suncco.weather");
    //                }
    //                break;
    //            //  
    //            case MotionEvent.ACTION_MOVE:
    //
    //                break;
    //            //  
    //            case MotionEvent.ACTION_UP:
    //                break;
    //        }
    //        return true;
    //    }    

    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        Log.w(TAG, "onKeyDown");
        if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {

            Log.w(TAG, "onKeyDown, KEYCODE_BACK");
            if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {
                //??  
                if (MyFloatView.mPlayViewPrepareStatus) {
                    Log.e("smallstar", "MyFloatView.mPlayViewPrepareStatus is true!");
                    MyFloatView.mPlayViewStatus = false;
                    MyFloatView.onExit();
                }

                if (mWebView.getOriginalUrl().equals("http://localhost:8080/console/settings/basicsettings.html")) {
                    stopService(new Intent(this, DaemonService.class));
                    stopService(new Intent(this, IJettyService.class));
                    finish();
                } else {
                    //mWebView.loadUrl("http://localhost:8080/console/settings/index.html");
                    mWebView.loadUrl("http://localhost:8080/console/settings/basicsettings.html");
                }
            }
            return true;
        }
        return super.dispatchKeyEvent(event);
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
    }

    public static void show(Context context) {
        final Intent intent = new Intent(context, IJetty.class);
        context.startActivity(intent);
    }

    @Override
    protected void onResume() {
        if (!SdCardUnavailableActivity.isExternalStorageAvailable()) {
            SdCardUnavailableActivity.show(this);
        } else {
            //work out if we need to do the installation finish step
            //or not. We do it iff:
            // - there is no previous jetty version on disk
            // - the previous version does not match the current version
            // - we're not already doing the update

            if (isUpdateNeeded()) {
                setupJetty();
            }
        }

        if (IJettyService.isRunning()) {
            startButton.setEnabled(false);
            configButton.setEnabled(false);
            stopButton.setEnabled(true);
            //mWebView.loadUrl("http://localhost:8080/console/settings/basicsettings.html");
        } else {
            startButton.setEnabled(true);
            configButton.setEnabled(true);
            stopButton.setEnabled(false);
        }
        super.onResume();
    }

    @Override
    protected Dialog onCreateDialog(int id) {
        switch (id) {
        case __SETUP_PROGRESS_DIALOG: {
            progressDialog = new ProgressDialog(IJetty.this);
            progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
            progressDialog.setMessage("Finishing initial install ...");

            return progressDialog;
        }
        default:
            return null;
        }
    }

    private void printNetworkInterfaces() {
        try {
            Enumeration<NetworkInterface> nis = NetworkInterface.getNetworkInterfaces();
            for (NetworkInterface ni : Collections.list(nis)) {
                Enumeration<InetAddress> iis = ni.getInetAddresses();
                for (InetAddress ia : Collections.list(iis)) {
                    consoleBuffer.append(formatJettyInfoLine("Network interface: %s: %s", ni.getDisplayName(),
                            ia.getHostAddress()));
                }
            }
        } catch (SocketException e) {
            Log.w(TAG, e);
        }
    }

    protected void setStoredJettyVersion(int version) {
        File jettyDir = __JETTY_DIR;
        if (!jettyDir.exists()) {
            return;
        }
        File versionFile = new File(jettyDir, "version.code");
        ObjectOutputStream oos = null;
        try {
            FileOutputStream fos = new FileOutputStream(versionFile);
            oos = new ObjectOutputStream(fos);
            oos.writeInt(version);
            oos.flush();
        } catch (Exception e) {
            Log.e(TAG, "Problem writing jetty version", e);
        } finally {
            if (oos != null) {
                try {
                    oos.close();
                } catch (Exception e) {
                    Log.d(TAG, "Error closing version.code output stream", e);
                }
            }
        }
    }

    /**
     * We need to an update iff we don't know the current
     * jetty version or it is different to the last version
     * that was installed.
     * 
     * @return
     */
    public boolean isUpdateNeeded() {
        //if no previous version file, assume update is required
        int storedVersion = getStoredJettyVersion();
        if (storedVersion <= 0)
            return true;

        try {
            //if different previous version, update is required
            PackageInfo pi = getPackageManager().getPackageInfo(getPackageName(), 0);
            if (pi == null)
                return true;
            if (pi.versionCode != storedVersion)
                return true;

            //if /sdcard/jetty/.update file exists, then update is required
            File alwaysUpdate = new File(__JETTY_DIR, ".update");
            if (alwaysUpdate.exists()) {
                Log.i(TAG, "Always Update tag found " + alwaysUpdate);
                return true;
            }
        } catch (Exception e) {
            //if any of these tests go wrong, best to assume update is true?
            return true;
        }

        return false;
    }

    public void setupJetty() {
        showDialog(__SETUP_PROGRESS_DIALOG);
        progressThread = new ProgressThread(handler);
        progressThread.start();
    };
}