Merge mozilla-central to build-system.
authorMitchell Field <mitchell.field@live.com.au>
Tue, 19 Apr 2011 13:22:32 +1000
changeset 68303 c5c1cac00a06b9030cafd3caa2f0ea0a9949e39c
parent 68302 62dcc1af0d1b12c02487dd5c8263fde95b8efb3f (current diff)
parent 68283 fc1ed658bf4b8214bc480dc4e005ea56d364c152 (diff)
child 68304 0b3b74b8f08761301587f61436540f5dcea69add
push id19579
push usermitchell.field@live.com.au
push dateTue, 19 Apr 2011 14:40:50 +0000
treeherdermozilla-central@2b974a79020f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone6.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to build-system.
configure.in
content/html/content/reftests/409604-1-ref.html
content/html/content/reftests/409604-1.html
content/html/content/reftests/583514-1-ref.html
content/html/content/reftests/583514-1.html
content/html/content/reftests/583514-2-ref.html
content/html/content/reftests/583514-2.html
content/xslt/public/nsIXSLTProcessorObsolete.idl
intl/uconv/src/nsUConvDll.cpp
intl/uconv/src/nsUConvDll.h
intl/uconv/src/nsUCvMinDll.h
js/src/configure.in
js/src/xpconnect/loader/mozJSLoaderConstructors.h
toolkit/components/console/hudservice/tests/browser/test-bug-595934-dom-events-external.html
toolkit/components/console/hudservice/tests/browser/test-bug-595934-dom-events-external.js
xpcom/tests/xptinfo/Makefile.in
xpcom/tests/xptinfo/xptiITestInterface.idl
xpcom/tests/xptinfo/xptunit/test_jar_xptloading.js
--- a/accessible/src/base/nsOuterDocAccessible.cpp
+++ b/accessible/src/base/nsOuterDocAccessible.cpp
@@ -84,17 +84,17 @@ nsOuterDocAccessible::GetChildAtPoint(PR
   if (aX < docX || aX >= docX + docWidth || aY < docY || aY >= docY + docHeight)
     return nsnull;
 
   // Always return the inner doc as direct child accessible unless bounds
   // outside of it.
   nsAccessible* child = GetChildAt(0);
   NS_ENSURE_TRUE(child, nsnull);
 
-  if (aWhichChild = eDeepestChild)
+  if (aWhichChild == eDeepestChild)
     return child->GetChildAtPoint(aX, aY, eDeepestChild);
   return child;
 }
 
 nsresult
 nsOuterDocAccessible::GetAttributesInternal(nsIPersistentProperties *aAttributes)
 {
   nsAutoString tag;
--- a/accessible/src/html/nsHyperTextAccessible.cpp
+++ b/accessible/src/html/nsHyperTextAccessible.cpp
@@ -305,17 +305,17 @@ nsHyperTextAccessible::GetPosAndText(PRI
     return nsnull;
   }
 
   nsIFrame *startFrame = nsnull;
   if (aEndFrame) {
     *aEndFrame = nsnull;
   }
   if (aBoundsRect) {
-    aBoundsRect->Empty();
+    aBoundsRect->SetEmpty();
   }
   if (aStartAcc)
     *aStartAcc = nsnull;
   if (aEndAcc)
     *aEndAcc = nsnull;
 
   nsIntRect unionRect;
   nsAccessible *lastAccessible = nsnull;
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -3291,26 +3291,25 @@ const BrowserSearch = {
     if (window.location.href != getBrowserURL()) {
       var win = getTopWin();
       if (win) {
         // If there's an open browser window, it should handle this command
         win.focus()
         win.BrowserSearch.webSearch();
       } else {
         // If there are no open browser windows, open a new one
-
-        // This needs to be in a timeout so that we don't end up refocused
-        // in the url bar
-        function webSearchCallback() {
-          setTimeout(BrowserSearch.webSearch, 0);
+        function observer(subject, topic, data) {
+          if (subject == win) {
+            BrowserSearch.webSearch();
+            Services.obs.removeObserver(observer, "browser-delayed-startup-finished");
+          }
         }
-
         win = window.openDialog("chrome://browser/content/", "_blank",
                                 "chrome,all,dialog=no", "about:blank");
-        win.addEventListener("load", webSearchCallback, false);
+        Services.obs.addObserver(observer, "browser-delayed-startup-finished", false); 
       }
       return;
     }
 #endif
     var searchBar = this.searchBar;
     if (searchBar && window.fullScreen)
       FullScreen.mouseoverToggle(true);
 
@@ -4029,26 +4028,29 @@ var FullScreen = {
     }
 
     // In tabs-on-top mode, move window controls to the tab bar,
     // and in tabs-on-bottom mode, move them back to the navigation toolbar.
     // When there is a chance the tab bar may be collapsed, put window
     // controls on nav bar.
     var fullscreenflex = document.getElementById("fullscreenflex");
     var fullscreenctls = document.getElementById("window-controls");
-    var ctlsOnTabbar = TabsOnTop.enabled &&
-                       !gPrefService.getBoolPref("browser.tabs.autoHide");
-    if (fullscreenctls.parentNode.id == "nav-bar" && ctlsOnTabbar) {
+    var navbar = document.getElementById("nav-bar");
+    var ctlsOnTabbar = window.toolbar.visible &&
+                       (navbar.collapsed ||
+                          (TabsOnTop.enabled &&
+                           !gPrefService.getBoolPref("browser.tabs.autoHide")));
+    if (fullscreenctls.parentNode == navbar && ctlsOnTabbar) {
       document.getElementById("TabsToolbar").appendChild(fullscreenctls);
       // we don't need this space in tabs-on-top mode, so prevent it from 
       // being shown
       fullscreenflex.removeAttribute("fullscreencontrol");
     }
     else if (fullscreenctls.parentNode.id == "TabsToolbar" && !ctlsOnTabbar) {
-      document.getElementById("nav-bar").appendChild(fullscreenctls);
+      navbar.appendChild(fullscreenctls);
       fullscreenflex.setAttribute("fullscreencontrol", "true");
     }
 
     var controls = document.getElementsByAttribute("fullscreencontrol", "true");
     for (var i = 0; i < controls.length; ++i)
       controls[i].hidden = aShow;
   }
 };
--- a/browser/base/content/openLocationLastURL.jsm
+++ b/browser/base/content/openLocationLastURL.jsm
@@ -91,13 +91,12 @@ let gOpenLocationLastURL = {
     else {
       let str = Components.classes["@mozilla.org/supports-string;1"]
                           .createInstance(Components.interfaces.nsISupportsString);
       str.data = val;
       prefSvc.setComplexValue(LAST_URL_PREF, nsISupportsString, str);
     }
   },
   reset: function() {
-    if (prefSvc.prefHasUserValue(LAST_URL_PREF))
-        prefSvc.clearUserPref(LAST_URL_PREF);
+    prefSvc.clearUserPref(LAST_URL_PREF);
     gOpenLocationLastURLData = "";
   }
 };
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -809,31 +809,31 @@
                             aBrowser.currentURI);
                 if (uri.scheme == "about")
                   newTitle = uri.spec + sep + newTitle;
                 else
                   newTitle = uri.prePath + sep + newTitle;
               }
             } catch (e) {}
 
-            if (window.TabView) {
+            if ("TabView" in window) {
               let groupName = TabView.getActiveGroupName();
               if (groupName)
                 newTitle = groupName + sep + newTitle;
             }
 
             return newTitle;
           ]]>
         </body>
       </method>
 
       <method name="updateTitlebar">
         <body>
           <![CDATA[
-            if (window.TabView && TabView.isVisible()) {
+            if ("TabView" in window && TabView.isVisible()) {
               // ToDo: this will be removed when we gain ability to draw to the menu bar.
               // Bug 586175
               this.ownerDocument.title = TabView.windowTitle;
             }
             else {
               this.ownerDocument.title = this.getWindowTitleForBrowser(this.mCurrentBrowser);
             }
           ]]>
--- a/browser/base/content/tabview/groupitems.js
+++ b/browser/base/content/tabview/groupitems.js
@@ -1142,17 +1142,19 @@ GroupItem.prototype = Utils.extend(new I
   
   // ----------
   // Handles error event for loading app tab's fav icon.
   _onAppTabError : function(event) {
     iQ(".appTabIcon", this.$appTabTray).each(function(icon) {
       let $icon = iQ(icon);
       if ($icon.data("xulTab") == event.target) {
         $icon.attr("src", Utils.defaultFaviconURL);
+        return false;
       }
+      return true;
     });
   },
 
   // ----------
   // Adds the given xul:tab as an app tab in this group's apptab tray
   //
   // Parameters:
   //   options - change how the app tab is added.
@@ -1188,19 +1190,20 @@ GroupItem.prototype = Utils.extend(new I
 
   // ----------
   // Removes the given xul:tab as an app tab in this group's apptab tray
   removeAppTab: function GroupItem_removeAppTab(xulTab) {
     // remove the icon
     iQ(".appTabIcon", this.$appTabTray).each(function(icon) {
       let $icon = iQ(icon);
       if ($icon.data("xulTab") != xulTab)
-        return;
+        return true;
         
       $icon.remove();
+      return false;
     });
     
     // adjust the tray
     this.adjustAppTabTray(true);
 
     xulTab.removeEventListener("error", this._onAppTabError, false);
   },
 
@@ -1210,27 +1213,28 @@ GroupItem.prototype = Utils.extend(new I
     let self = this;
 
     let elements = iQ(".appTabIcon", this.$appTabTray);
     let length = elements.length;
 
     elements.each(function(icon) {
       let $icon = iQ(icon);
       if ($icon.data("xulTab") != xulTab)
-        return;
+        return true;
 
       let targetIndex = xulTab._tPos;
 
       $icon.remove();
       if (targetIndex < (length - 1))
         self.$appTabTray[0].insertBefore(
           icon,
         iQ(".appTabIcon:nth-child(" + (targetIndex + 1) + ")", self.$appTabTray)[0]);
       else
         $icon.appendTo(self.$appTabTray);
+      return false;
     });
   },
 
   // ----------
   // Function: hideExpandControl
   // Hide the control which expands a stacked groupItem into a quick-look view.
   hideExpandControl: function GroupItem_hideExpandControl() {
     this.$expander.hide();
@@ -1663,23 +1667,22 @@ GroupItem.prototype = Utils.extend(new I
   // ----------
   // Function: _addHandlers
   // Helper routine for the constructor; adds various event handlers to the container.
   _addHandlers: function GroupItem__addHandlers(container) {
     let self = this;
 
     // Create new tab and zoom in on it after a double click
     container.mousedown(function(e) {
-      if (!Utils.isLeftClick(e))
+      if (!Utils.isLeftClick(e) || self.$titlebar[0] == e.target || 
+          self.$titlebar.contains(e.target)) {
+        self._lastClick = 0;
+        self._lastClickPositions = null;
         return;
-
-      // clicking in the title bar shouldn't create new tabs
-      if (self.$titlebar[0] == e.target || self.$titlebar.contains(e.target))
-        return;
-
+      }
       if (Date.now() - self._lastClick <= UI.DBLCLICK_INTERVAL &&
           (self._lastClickPositions.x - UI.DBLCLICK_OFFSET) <= e.clientX &&
           (self._lastClickPositions.x + UI.DBLCLICK_OFFSET) >= e.clientX &&
           (self._lastClickPositions.y - UI.DBLCLICK_OFFSET) <= e.clientY &&
           (self._lastClickPositions.y + UI.DBLCLICK_OFFSET) >= e.clientY) {
         self.newTab();
         self._lastClick = 0;
         self._lastClickPositions = null;
@@ -2033,20 +2036,21 @@ let GroupItems = {
     if (xulTab.ownerDocument.defaultView != gWindow || !xulTab.pinned)
       return;
 
     let iconUrl = xulTab.image || Utils.defaultFaviconURL;
     this.groupItems.forEach(function(groupItem) {
       iQ(".appTabIcon", groupItem.$appTabTray).each(function(icon) {
         let $icon = iQ(icon);
         if ($icon.data("xulTab") != xulTab)
-          return;
+          return true;
 
         if (iconUrl != $icon.attr("src"))
           $icon.attr("src", iconUrl);
+        return false;
       });
     });
   },  
 
   // ----------
   // Function: addAppTab
   // Adds the given xul:tab to the app tab tray in all groups
   addAppTab: function GroupItems_addAppTab(xulTab) {
--- a/browser/base/content/tabview/iq.js
+++ b/browser/base/content/tabview/iq.js
@@ -212,19 +212,17 @@ iQClass.prototype = {
   // ----------
   // Function: each
   // Execute a callback for every element in the matched set.
   each: function iQClass_each(callback) {
     if (typeof callback != "function") {
       Utils.assert(false, "each's argument must be a function");
       return null;
     }
-    for (let i = 0; this[i] != null; i++) {
-      callback(this[i]);
-    }
+    for (let i = 0; this[i] != null && callback(this[i]) !== false; i++) {}
     return this;
   },
 
   // ----------
   // Function: addClass
   // Adds the given class(es) to the receiver.
   addClass: function iQClass_addClass(value) {
     Utils.assertThrow(typeof value == "string" && value,
--- a/browser/base/content/tabview/items.js
+++ b/browser/base/content/tabview/items.js
@@ -656,17 +656,17 @@ Item.prototype = {
       };
 
       // ___ mouseup
       var handleMouseUp = function(e) {
         iQ(gWindow)
           .unbind('mousemove', handleMouseMove)
           .unbind('mouseup', handleMouseUp);
 
-        if (dropTarget) {
+        if (startSent && dropTarget) {
           var dropOptions = dropTarget.dropOptions;
           if (dropOptions && typeof dropOptions.drop == "function")
             dropOptions.drop.apply(dropTarget, [e]);
         }
 
         if (startSent && typeof self.dragOptions.stop == "function")
           self.dragOptions.stop.apply(self, [e]);
 
--- a/browser/base/content/tabview/tabview.css
+++ b/browser/base/content/tabview/tabview.css
@@ -8,16 +8,17 @@ html {
 }
 
 body {
   padding: 0px;
   margin: 0 auto;
 }
 
 #content {
+  overflow: -moz-hidden-unscrollable;
   position: absolute;
   top: 0;
   left: 0;
   width: 100%;
   height: 100%;
 }
 
 #bg {
--- a/browser/base/content/tabview/ui.js
+++ b/browser/base/content/tabview/ui.js
@@ -178,46 +178,51 @@ let UI = {
         if (iQ(":focus").length > 0) {
           iQ(":focus").each(function(element) {
             // don't fire blur event if the same input element is clicked.
             if (e.target != element && element.nodeName == "INPUT")
               element.blur();
           });
         }
         if (e.originalTarget.id == "content") {
-          // Create an orphan tab on double click
-          if (Date.now() - self._lastClick <= self.DBLCLICK_INTERVAL && 
-              (self._lastClickPositions.x - self.DBLCLICK_OFFSET) <= e.clientX &&
-              (self._lastClickPositions.x + self.DBLCLICK_OFFSET) >= e.clientX &&
-              (self._lastClickPositions.y - self.DBLCLICK_OFFSET) <= e.clientY &&
-              (self._lastClickPositions.y + self.DBLCLICK_OFFSET) >= e.clientY) {
-            GroupItems.setActiveGroupItem(null);
-            TabItems.creatingNewOrphanTab = true;
-
-            let newTab = 
-              gBrowser.loadOneTab("about:blank", { inBackground: true });
-
-            let box = 
-              new Rect(e.clientX - Math.floor(TabItems.tabWidth/2),
-                       e.clientY - Math.floor(TabItems.tabHeight/2),
-                       TabItems.tabWidth, TabItems.tabHeight);
-            newTab._tabViewTabItem.setBounds(box, true);
-            newTab._tabViewTabItem.pushAway(true);
-            UI.setActiveTab(newTab._tabViewTabItem);
-
-            TabItems.creatingNewOrphanTab = false;
-            newTab._tabViewTabItem.zoomIn(true);
-
+          if (!Utils.isLeftClick(e)) {
             self._lastClick = 0;
             self._lastClickPositions = null;
-            gTabView.firstUseExperienced = true;
           } else {
-            self._lastClick = Date.now();
-            self._lastClickPositions = new Point(e.clientX, e.clientY);
-            self._createGroupItemOnDrag(e);
+            // Create an orphan tab on double click
+            if (Date.now() - self._lastClick <= self.DBLCLICK_INTERVAL && 
+                (self._lastClickPositions.x - self.DBLCLICK_OFFSET) <= e.clientX &&
+                (self._lastClickPositions.x + self.DBLCLICK_OFFSET) >= e.clientX &&
+                (self._lastClickPositions.y - self.DBLCLICK_OFFSET) <= e.clientY &&
+                (self._lastClickPositions.y + self.DBLCLICK_OFFSET) >= e.clientY) {
+              GroupItems.setActiveGroupItem(null);
+              TabItems.creatingNewOrphanTab = true;
+
+              let newTab =
+                gBrowser.loadOneTab("about:blank", { inBackground: true });
+
+              let box =
+                new Rect(e.clientX - Math.floor(TabItems.tabWidth/2),
+                         e.clientY - Math.floor(TabItems.tabHeight/2),
+                         TabItems.tabWidth, TabItems.tabHeight);
+              newTab._tabViewTabItem.setBounds(box, true);
+              newTab._tabViewTabItem.pushAway(true);
+              UI.setActiveTab(newTab._tabViewTabItem);
+
+              TabItems.creatingNewOrphanTab = false;
+              newTab._tabViewTabItem.zoomIn(true);
+
+              self._lastClick = 0;
+              self._lastClickPositions = null;
+              gTabView.firstUseExperienced = true;
+            } else {
+              self._lastClick = Date.now();
+              self._lastClickPositions = new Point(e.clientX, e.clientY);
+              self._createGroupItemOnDrag(e);
+            }
           }
         }
       });
 
       iQ(window).bind("unload", function() {
         self.uninit();
       });
 
--- a/browser/base/content/test/tabview/Makefile.in
+++ b/browser/base/content/test/tabview/Makefile.in
@@ -125,16 +125,17 @@ include $(topsrcdir)/config/rules.mk
                  browser_tabview_bug634085.js \
                  browser_tabview_bug634158.js \
                  browser_tabview_bug634672.js \
                  browser_tabview_bug635696.js \
                  browser_tabview_bug640765.js \
                  browser_tabview_bug641802.js \
                  browser_tabview_bug644097.js \
                  browser_tabview_bug645653.js \
+                 browser_tabview_bug649006.js \
                  browser_tabview_dragdrop.js \
                  browser_tabview_exit_button.js \
                  browser_tabview_expander.js \
                  browser_tabview_firstrun_pref.js \
                  browser_tabview_group.js \
                  browser_tabview_launch.js \
                  browser_tabview_multiwindow_search.js \
                  browser_tabview_orphaned_tabs.js \
--- a/browser/base/content/test/tabview/browser_tabview_bug604098.js
+++ b/browser/base/content/test/tabview/browser_tabview_bug604098.js
@@ -1,87 +1,64 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 let originalTab;
 let orphanedTab;
 let contentWindow;
+let contentElement;
 
 function test() {
   waitForExplicitFinish();
 
-  window.addEventListener("tabviewshown", onTabViewWindowLoaded, false);
-  TabView.show();
-}
-
-function onTabViewWindowLoaded() {
-  window.removeEventListener("tabviewshown", onTabViewWindowLoaded, false);
-
-  contentWindow = document.getElementById("tab-view").contentWindow;
-  originalTab = gBrowser.visibleTabs[0];
-
-  test1();
+  showTabView(function() {
+    contentWindow = TabView.getContentWindow();
+    contentElement = contentWindow.document.getElementById("content");
+    originalTab = gBrowser.visibleTabs[0];
+    test1();
+  });
 }
 
 function test1() {
   is(contentWindow.GroupItems.getOrphanedTabs().length, 0, "No orphaned tabs");
 
-  let onTabViewHidden = function() {
-    window.removeEventListener("tabviewhidden", onTabViewHidden, false);
-
-    let onTabViewShown = function() {
-      window.removeEventListener("tabviewshown", onTabViewShown, false);
-
-      is(contentWindow.GroupItems.getOrphanedTabs().length, 1, 
+  whenTabViewIsHidden(function() {
+    showTabView(function() {
+      is(contentWindow.GroupItems.getOrphanedTabs().length, 1,
          "An orphaned tab is created");
       orphanedTab = contentWindow.GroupItems.getOrphanedTabs()[0].tab;
 
       test2();
-    };
-    window.addEventListener("tabviewshown", onTabViewShown, false);
-    TabView.show();
-  };
-  window.addEventListener("tabviewhidden", onTabViewHidden, false);
+    });
+  });
 
   // first click
-  EventUtils.sendMouseEvent(
-    { type: "mousedown" }, contentWindow.document.getElementById("content"), 
-    contentWindow);
-  EventUtils.sendMouseEvent(
-    { type: "mouseup" }, contentWindow.document.getElementById("content"), 
-    contentWindow);
+  mouseClick(contentElement, 0);
   // second click
-  EventUtils.sendMouseEvent(
-    { type: "mousedown" }, contentWindow.document.getElementById("content"), 
-    contentWindow);
-  EventUtils.sendMouseEvent(
-    { type: "mouseup" }, contentWindow.document.getElementById("content"), 
-    contentWindow);
+  mouseClick(contentElement, 0);
 }
 
 function test2() {
   let groupItem = createEmptyGroupItem(contentWindow, 300, 300, 200);
   is(groupItem.getChildren().length, 0, "The group is empty");
 
-  let onTabViewHidden = function() {
-    window.removeEventListener("tabviewhidden", onTabViewHidden, false);
+  hideTabView(function() {
+    is(groupItem.getChildren().length, 1, "A tab is created inside the group");
 
-    is(groupItem.getChildren().length, 1, "A tab is created inside the group");
-    
     gBrowser.selectedTab = originalTab;
     gBrowser.removeTab(orphanedTab);
     gBrowser.removeTab(groupItem.getChildren()[0].tab);
 
     finish();
-  };
-  window.addEventListener("tabviewhidden", onTabViewHidden, false);
+  });
 
   // first click
-  EventUtils.sendMouseEvent(
-    { type: "mousedown" }, groupItem.container, contentWindow);
-  EventUtils.sendMouseEvent(
-    { type: "mouseup" }, groupItem.container, contentWindow);
+  mouseClick(groupItem.container, 0);
   // second click
-  EventUtils.sendMouseEvent(
-    { type: "mousedown" }, groupItem.container, contentWindow);
+  mouseClick(groupItem.container, 0);
+}
+
+function mouseClick(targetElement, buttonCode) {
   EventUtils.sendMouseEvent(
-    { type: "mouseup" }, groupItem.container, contentWindow);
+    { type: "mousedown", button: buttonCode }, targetElement, contentWindow);
+  EventUtils.sendMouseEvent(
+    { type: "mouseup", button: buttonCode }, targetElement, contentWindow);
 }
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/tabview/browser_tabview_bug649006.js
@@ -0,0 +1,94 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+let contentWindow;
+let contentElement;
+let groupItem;
+
+function test() {
+  waitForExplicitFinish();
+
+  registerCleanupFunction(function () {
+    hideTabView(function () {});
+  });
+
+  showTabView(function() {
+    contentWindow = TabView.getContentWindow();
+    contentElement = contentWindow.document.getElementById("content");
+    test1();
+  });
+}
+
+function test1() {
+  is(gBrowser.tabs.length, 1, 
+     "Total number of tabs is 1 before right button double click");
+  // first click
+  mouseClick(contentElement, 2);
+  // second click
+  mouseClick(contentElement, 2);
+
+  is(gBrowser.tabs.length, 1, 
+     "Total number of tabs is 1 after right button double click");
+  test2();
+}
+
+
+function test2() {
+  is(gBrowser.tabs.length, 1, 
+     "Total number of tabs is 1 before left, right and left mouse clicks");
+
+  // first click
+  mouseClick(contentElement, 0);
+  // second click
+  mouseClick(contentElement, 2);
+  // third click
+  mouseClick(contentElement, 0);
+
+  is(gBrowser.tabs.length, 1, 
+     "Total number of tabs is 1 before left, right and left mouse clicks");
+  test3();
+}
+
+function test3() {
+  ok(contentWindow.GroupItems.groupItems.length, 1, "Only one group item exists");
+  groupItem = contentWindow.GroupItems.groupItems[0];
+
+  is(groupItem.getChildren().length, 1, 
+     "The number of tab items in the group is 1 before right button double click");
+
+  // first click
+  mouseClick(groupItem.container, 2);
+  // second click
+  mouseClick(groupItem.container, 2);
+
+  is(groupItem.getChildren().length, 1, 
+     "The number of tab items in the group is 1 after right button double click");
+  test4();
+}
+
+function test4() {
+  is(groupItem.getChildren().length, 1, 
+     "The number of tab items in the group is 1 before left, right, left mouse clicks");
+
+  // first click
+  mouseClick(groupItem.container, 0);
+  // second click
+  mouseClick(groupItem.container, 2);
+  // third click
+  mouseClick(groupItem.container, 0);
+
+  is(groupItem.getChildren().length, 1, 
+     "The number of tab items in the group is 1 before left, right, left mouse clicks");
+
+  hideTabView(function() {
+    is(gBrowser.tabs.length, 1, "Total number of tabs is 1 after all tests");
+    finish();
+  });
+}
+
+function mouseClick(targetElement, buttonCode) {
+  EventUtils.sendMouseEvent(
+    { type: "mousedown", button: buttonCode }, targetElement, contentWindow);
+  EventUtils.sendMouseEvent(
+    { type: "mouseup", button: buttonCode }, targetElement, contentWindow);
+}
+
--- a/browser/components/migration/content/migration.js
+++ b/browser/components/migration/content/migration.js
@@ -452,20 +452,17 @@ var MigrationWizard = {
         if (this._newHomePage) {
           try {
             // set homepage properly
             var prefSvc = Components.classes["@mozilla.org/preferences-service;1"]
                                     .getService(Components.interfaces.nsIPrefService);
             var prefBranch = prefSvc.getBranch(null);
 
             if (this._newHomePage == "DEFAULT") {
-              try {
-                prefBranch.clearUserPref("browser.startup.homepage");
-              }
-              catch (e) { }
+              prefBranch.clearUserPref("browser.startup.homepage");
             }
             else {
               var str = Components.classes["@mozilla.org/supports-string;1"]
                                 .createInstance(Components.interfaces.nsISupportsString);
               str.data = this._newHomePage;
               prefBranch.setComplexValue("browser.startup.homepage",
                                          Components.interfaces.nsISupportsString,
                                          str);
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -256,16 +256,24 @@ BrowserGlue.prototype = {
       case "browser-glue-test": // used by tests
         if (data == "post-update-notification") {
           if (Services.prefs.prefHasUserValue("app.update.postupdate"))
             this._showUpdateNotification();
         }
         else if (data == "force-ui-migration") {
           this._migrateUI();
         }
+        else if (data == "force-distribution-customization") {
+          this._distributionCustomizer.applyPrefDefaults();
+          this._distributionCustomizer.applyCustomizations();
+          // To apply distribution bookmarks use "places-init-complete".
+        }
+        else if (data == "force-places-init") {
+          this._initPlaces();
+        }
         break;
     }
   }, 
 
   // initialization (called on application startup) 
   _init: function BG__init() {
     let os = Services.obs;
     os.addObserver(this, "xpcom-shutdown", false);
--- a/browser/components/places/content/history-panel.js
+++ b/browser/components/places/content/history-panel.js
@@ -79,38 +79,38 @@ function searchHistory(aInput)
   const NHQO = Ci.nsINavHistoryQueryOptions;
   var sortingMode;
   var resultType;
 
   switch (gHistoryGrouping) {
     case "visited":
       resultType = NHQO.RESULTS_AS_URI;
       sortingMode = NHQO.SORT_BY_VISITCOUNT_DESCENDING;
-      break; 
+      break;
     case "lastvisited":
       resultType = NHQO.RESULTS_AS_URI;
       sortingMode = NHQO.SORT_BY_DATE_DESCENDING;
-      break; 
+      break;
     case "dayandsite":
       resultType = NHQO.RESULTS_AS_DATE_SITE_QUERY;
       break;
     case "site":
       resultType = NHQO.RESULTS_AS_SITE_QUERY;
       sortingMode = NHQO.SORT_BY_TITLE_ASCENDING;
       break;
     case "day":
     default:
       resultType = NHQO.RESULTS_AS_DATE_QUERY;
       break;
   }
 
   if (aInput) {
     query.searchTerms = aInput;
     if (gHistoryGrouping != "visited" && gHistoryGrouping != "lastvisited") {
-      sortingMode = NHQO.SORT_BY_TITLE_ASCENDING;
+      sortingMode = NHQO.SORT_BY_FRECENCY_DESCENDING;
       resultType = NHQO.RESULTS_AS_URI;
     }
   }
 
   options.sortingMode = sortingMode;
   options.resultType = resultType;
 
   // call load() on the tree manually
--- a/browser/components/places/tests/unit/test_browserGlue_distribution.js
+++ b/browser/components/places/tests/unit/test_browserGlue_distribution.js
@@ -1,154 +1,97 @@
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et: */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (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.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Places Unit Test code.
- *
- * The Initial Developer of the Original Code is Mozilla Foundation.
- * Portions created by the Initial Developer are Copyright (C) 2009
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *  Marco Bonardo <mak77@bonardo.net>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /**
- * Tests that nsBrowserGlue does not overwrite bookmarks imported from the
- * migrators.  They usually run before nsBrowserGlue, so if we find any
- * bookmark on init, we should not try to import.
+ * Tests that nsBrowserGlue correctly imports bookmarks from distribution.ini.
  */
 
 const PREF_SMART_BOOKMARKS_VERSION = "browser.places.smartBookmarksVersion";
 const PREF_BMPROCESSED = "distribution.516444.bookmarksProcessed";
 const PREF_DISTRIBUTION_ID = "distribution.id";
 
-const TOPIC_FINAL_UI_STARTUP = "final-ui-startup";
+const TOPICDATA_DISTRIBUTION_CUSTOMIZATION = "force-distribution-customization";
 const TOPIC_CUSTOMIZATION_COMPLETE = "distribution-customization-complete";
+const TOPIC_BROWSERGLUE_TEST = "browser-glue-test";
 
-function run_test() {
-  // This is needed but we still have to investigate the reason, could just be
-  // we try to act too late in the game, moving our shutdown earlier will help.
-  let hs = Cc["@mozilla.org/browser/nav-history-service;1"].
-         getService(Ci.nsINavHistoryService);
-  // TODO: re-enable when bug 523936 is fixed.
-  return;
-
+function run_test()
+{
   do_test_pending();
 
   // Copy distribution.ini file to our app dir.
   let distroDir = Services.dirsvc.get("XCurProcD", Ci.nsIFile);
   distroDir.append("distribution");
   let iniFile = distroDir.clone();
   iniFile.append("distribution.ini");
   if (iniFile.exists()) {
     iniFile.remove(false);
     print("distribution.ini already exists, did some test forget to cleanup?");
   }
-
   let testDistributionFile = gTestDir.clone();
   testDistributionFile.append("distribution.ini");
   testDistributionFile.copyTo(distroDir, "distribution.ini");
   do_check_true(testDistributionFile.exists());
 
   // Disable Smart Bookmarks creation.
-  let ps = Cc["@mozilla.org/preferences-service;1"].
-           getService(Ci.nsIPrefBranch);
-  ps.setIntPref(PREF_SMART_BOOKMARKS_VERSION, -1);
-  // Avoid migrateUI, we are just simulating a partial startup.
-  ps.setIntPref("browser.migration.version", 4);
+  Services.prefs.setIntPref(PREF_SMART_BOOKMARKS_VERSION, -1);
 
-  // Initialize Places through the History Service.
-  let hs = Cc["@mozilla.org/browser/nav-history-service;1"].
-           getService(Ci.nsINavHistoryService);
-  // Check a new database has been created.
-  // nsBrowserGlue will use databaseStatus to manage initialization.
-  do_check_eq(hs.databaseStatus, hs.DATABASE_STATUS_CREATE);
-
-  // Initialize nsBrowserGlue.
-  let bg = Cc["@mozilla.org/browser/browserglue;1"].
-           getService(Ci.nsIBrowserGlue);
+  // Initialize Places through the History Service and check that a new
+  // database has been created.
+  do_check_eq(PlacesUtils.history.databaseStatus,
+              PlacesUtils.history.DATABASE_STATUS_CREATE);
 
-  let os = Cc["@mozilla.org/observer-service;1"].
-           getService(Ci.nsIObserverService);
-  let observer = {
-    observe: function(aSubject, aTopic, aData) {
-      os.removeObserver(this, PlacesUtils.TOPIC_INIT_COMPLETE);
+  // Force distribution.
+  Cc["@mozilla.org/browser/browserglue;1"].
+  getService(Ci.nsIObserver).observe(null,
+                                     TOPIC_BROWSERGLUE_TEST,
+                                     TOPICDATA_DISTRIBUTION_CUSTOMIZATION);
 
-      // Simulate browser startup.
-      bg.QueryInterface(Ci.nsIObserver).observe(null,
-                                                TOPIC_FINAL_UI_STARTUP,
-                                                null);
-      // Test will continue on customization complete notification.
-      let cObserver = {
-        observe: function(aSubject, aTopic, aData) {
-          os.removeObserver(this, TOPIC_CUSTOMIZATION_COMPLETE);
-          do_execute_soon(continue_test);
-        }
-      }
-      os.addObserver(cObserver, TOPIC_CUSTOMIZATION_COMPLETE, false);
-    }
-  }
-  os.addObserver(observer, PlacesUtils.TOPIC_INIT_COMPLETE, false);
+  // Test will continue on customization complete notification.
+  Services.obs.addObserver(function(aSubject, aTopic, aData) {
+    Services.obs.removeObserver(arguments.callee,
+                                TOPIC_CUSTOMIZATION_COMPLETE,
+                                false);
+    do_execute_soon(onCustomizationComplete);
+  }, TOPIC_CUSTOMIZATION_COMPLETE, false);
 }
 
-function continue_test() {
-  let bs = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
-           getService(Ci.nsINavBookmarksService);
-
-  dump_table("moz_bookmarks");
-
+function onCustomizationComplete()
+{
   // Check the custom bookmarks exist on menu.
-  let menuItemId = bs.getIdForItemAt(bs.bookmarksMenuFolder, 0);
+  let menuItemId =
+    PlacesUtils.bookmarks.getIdForItemAt(PlacesUtils.bookmarksMenuFolderId, 0);
   do_check_neq(menuItemId, -1);
-  do_check_eq(bs.getItemTitle(menuItemId), "Menu Link Before");
-  menuItemId = bs.getIdForItemAt(bs.bookmarksMenuFolder, 1 + DEFAULT_BOOKMARKS_ON_MENU);
+  do_check_eq(PlacesUtils.bookmarks.getItemTitle(menuItemId),
+              "Menu Link Before");
+  menuItemId =
+    PlacesUtils.bookmarks.getIdForItemAt(PlacesUtils.bookmarksMenuFolderId,
+                                         1 + DEFAULT_BOOKMARKS_ON_MENU);
   do_check_neq(menuItemId, -1);
-  do_check_eq(bs.getItemTitle(menuItemId), "Menu Link After");
+  do_check_eq(PlacesUtils.bookmarks.getItemTitle(menuItemId),
+              "Menu Link After");
 
   // Check the custom bookmarks exist on toolbar.
-  let toolbarItemId = bs.getIdForItemAt(bs.toolbarFolder, 0);
+  let toolbarItemId =
+    PlacesUtils.bookmarks.getIdForItemAt(PlacesUtils.toolbarFolderId, 0);
   do_check_neq(toolbarItemId, -1);
-  do_check_eq(bs.getItemTitle(toolbarItemId), "Toolbar Link Before");
-  toolbarItemId = bs.getIdForItemAt(bs.toolbarFolder, 1 + DEFAULT_BOOKMARKS_ON_TOOLBAR);
+  do_check_eq(PlacesUtils.bookmarks.getItemTitle(toolbarItemId),
+              "Toolbar Link Before");
+  toolbarItemId =
+    PlacesUtils.bookmarks.getIdForItemAt(PlacesUtils.toolbarFolderId,
+                                         1 + DEFAULT_BOOKMARKS_ON_TOOLBAR);
   do_check_neq(toolbarItemId, -1);
-  do_check_eq(bs.getItemTitle(toolbarItemId), "Toolbar Link After");
+  do_check_eq(PlacesUtils.bookmarks.getItemTitle(toolbarItemId),
+              "Toolbar Link After");
 
   // Check the bmprocessed pref has been created.
-  let ps = Cc["@mozilla.org/preferences-service;1"].
-           getService(Ci.nsIPrefBranch);
-  do_check_true(ps.getBoolPref(PREF_BMPROCESSED));
+  do_check_true(Services.prefs.getBoolPref(PREF_BMPROCESSED));
 
   // Check distribution prefs have been created.
-  do_check_eq(ps.getCharPref(PREF_DISTRIBUTION_ID), "516444");
+  do_check_eq(Services.prefs.getCharPref(PREF_DISTRIBUTION_ID), "516444");
 
   do_test_finished();
 }
 
 do_register_cleanup(function() {
   // Remove the distribution file, even if the test failed, otherwise all
   // next tests will import it.
   let iniFile = Services.dirsvc.get("XCurProcD", Ci.nsIFile);
--- a/browser/components/places/tests/unit/test_browserGlue_migrate.js
+++ b/browser/components/places/tests/unit/test_browserGlue_migrate.js
@@ -1,121 +1,86 @@
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et: */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (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.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Places Unit Test code.
- *
- * The Initial Developer of the Original Code is Mozilla Foundation.
- * Portions created by the Initial Developer are Copyright (C) 2009
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *  Marco Bonardo <mak77@bonardo.net>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /**
  * Tests that nsBrowserGlue does not overwrite bookmarks imported from the
  * migrators.  They usually run before nsBrowserGlue, so if we find any
  * bookmark on init, we should not try to import.
  */
 
-Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
-
-XPCOMUtils.defineLazyServiceGetter(this, "bs",
-                                   "@mozilla.org/browser/nav-bookmarks-service;1",
-                                   "nsINavBookmarksService");
-XPCOMUtils.defineLazyServiceGetter(this, "anno",
-                                   "@mozilla.org/browser/annotation-service;1",
-                                   "nsIAnnotationService");
-
-let bookmarksObserver = {
-  onBeginUpdateBatch: function() {},
-  onEndUpdateBatch: function() {
-    let itemId = bs.getIdForItemAt(bs.toolbarFolder, 0);
-    do_check_neq(itemId, -1);
-    if (anno.itemHasAnnotation(itemId, "Places/SmartBookmark"))
-      continue_test();
-  },
-  onItemAdded: function() {},
-  onBeforeItemRemoved: function(id) {},
-  onItemRemoved: function(id, folder, index, itemType) {},
-  onItemChanged: function() {},
-  onItemVisited: function(id, visitID, time) {},
-  onItemMoved: function() {},
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsINavBookmarkObserver])
-};
-
 const PREF_SMART_BOOKMARKS_VERSION = "browser.places.smartBookmarksVersion";
 
 function run_test() {
   do_test_pending();
 
   // Create our bookmarks.html copying bookmarks.glue.html to the profile
-  // folder.  It will be ignored.
+  // folder.  It should be ignored.
   create_bookmarks_html("bookmarks.glue.html");
 
   // Remove current database file.
   let db = gProfD.clone();
   db.append("places.sqlite");
   if (db.exists()) {
     db.remove(false);
     do_check_false(db.exists());
   }
 
-  // Initialize Places through the History Service.
-  let hs = Cc["@mozilla.org/browser/nav-history-service;1"].
-           getService(Ci.nsINavHistoryService);
-  // Check a new database has been created.
-  // nsBrowserGlue uses databaseStatus to manage initialization.
-  do_check_eq(hs.databaseStatus, hs.DATABASE_STATUS_CREATE);
+  // Initialize Places through the History Service and check that a new
+  // database has been created.
+  do_check_eq(PlacesUtils.history.databaseStatus,
+              PlacesUtils.history.DATABASE_STATUS_CREATE);
 
   // A migrator would run before nsBrowserGlue, so we mimic that behavior
   // adding a bookmark.
-  bs.insertBookmark(bs.bookmarksMenuFolder, uri("http://mozilla.org/"),
-                    bs.DEFAULT_INDEX, "migrated");
+  PlacesUtils.bookmarks.insertBookmark(PlacesUtils.bookmarks.bookmarksMenuFolder, uri("http://mozilla.org/"),
+                    PlacesUtils.bookmarks.DEFAULT_INDEX, "migrated");
 
   // Initialize nsBrowserGlue.
   let bg = Cc["@mozilla.org/browser/browserglue;1"].
            getService(Ci.nsIBrowserGlue);
 
+  let bookmarksObserver = {
+    onBeginUpdateBatch: function() {},
+    onEndUpdateBatch: function() {
+      // Check if the currently finished batch created the smart bookmarks.
+      let itemId =
+        PlacesUtils.bookmarks.getIdForItemAt(PlacesUtils.toolbarFolderId, 0);
+      do_check_neq(itemId, -1);
+      if (PlacesUtils.annotations
+                     .itemHasAnnotation(itemId, "Places/SmartBookmark")) {
+        do_execute_soon(onSmartBookmarksCreation);
+      }
+    },
+    onItemAdded: function() {},
+    onBeforeItemRemoved: function(id) {},
+    onItemRemoved: function(id, folder, index, itemType) {},
+    onItemChanged: function() {},
+    onItemVisited: function(id, visitID, time) {},
+    onItemMoved: function() {},
+    QueryInterface: XPCOMUtils.generateQI([Ci.nsINavBookmarkObserver])
+  };
   // The test will continue once import has finished and smart bookmarks
   // have been created.
-  bs.addObserver(bookmarksObserver, false);
+  PlacesUtils.bookmarks.addObserver(bookmarksObserver, false);
 }
 
-function continue_test() {
+function onSmartBookmarksCreation() {
   // Check the created bookmarks still exist.
-  let itemId = bs.getIdForItemAt(bs.bookmarksMenuFolder, SMART_BOOKMARKS_ON_MENU);
-  do_check_eq(bs.getItemTitle(itemId), "migrated");
+  let itemId =
+    PlacesUtils.bookmarks.getIdForItemAt(PlacesUtils.bookmarksMenuFolderId,
+                                         SMART_BOOKMARKS_ON_MENU);
+  do_check_eq(PlacesUtils.bookmarks.getItemTitle(itemId), "migrated");
 
   // Check that we have not imported any new bookmark.
-  do_check_eq(bs.getIdForItemAt(bs.bookmarksMenuFolder, SMART_BOOKMARKS_ON_MENU + 1), -1);
-  do_check_eq(bs.getIdForItemAt(bs.toolbarFolder, SMART_BOOKMARKS_ON_MENU), -1);
+  itemId =
+    PlacesUtils.bookmarks.getIdForItemAt(PlacesUtils.bookmarksMenuFolderId,
+                                         SMART_BOOKMARKS_ON_MENU + 1)
+  do_check_eq(itemId, -1);
+  itemId =
+    PlacesUtils.bookmarks.getIdForItemAt(PlacesUtils.toolbarFolderId,
+                                         SMART_BOOKMARKS_ON_MENU)
+  do_check_eq(itemId, -1);
 
   remove_bookmarks_html();
 
   do_test_finished();
 }
--- a/browser/components/places/tests/unit/test_browserGlue_prefs.js
+++ b/browser/components/places/tests/unit/test_browserGlue_prefs.js
@@ -1,287 +1,265 @@
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et: */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (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.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Places Unit Test code.
- *
- * The Initial Developer of the Original Code is Mozilla Foundation.
- * Portions created by the Initial Developer are Copyright (C) 2009
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *  Marco Bonardo <mak77@bonardo.net>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /**
  * Tests that nsBrowserGlue is correctly interpreting the preferences settable
  * by the user or by other components.
  */
 
-/** Bug 539067
- * Test is disabled due to random failures and timeouts, see run_test.
- * This is commented out to avoid leaks.
-// Initialize browserGlue.
-let bg = Cc["@mozilla.org/browser/browserglue;1"].
-         getService(Ci.nsIBrowserGlue);
-*/
-
-// Initialize Places through Bookmarks Service.
-let bs = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
-         getService(Ci.nsINavBookmarksService);
-
-// Get other services.
-let ps = Cc["@mozilla.org/preferences-service;1"].
-         getService(Ci.nsIPrefBranch);
-let os = Cc["@mozilla.org/observer-service;1"].
-         getService(Ci.nsIObserverService);
-
 const PREF_IMPORT_BOOKMARKS_HTML = "browser.places.importBookmarksHTML";
 const PREF_RESTORE_DEFAULT_BOOKMARKS = "browser.bookmarks.restore_default_bookmarks";
 const PREF_SMART_BOOKMARKS_VERSION = "browser.places.smartBookmarksVersion";
 const PREF_AUTO_EXPORT_HTML = "browser.bookmarks.autoExportHTML";
 
-let tests = [];
-//------------------------------------------------------------------------------
+const TOPIC_BROWSERGLUE_TEST = "browser-glue-test";
+const TOPICDATA_FORCE_PLACES_INIT = "force-places-init";
+
+let bg = Cc["@mozilla.org/browser/browserglue;1"].
+         getService(Ci.nsIBrowserGlue);
+
+let gTests = [
+
+  // This test must be the first one.
+  function test_checkPreferences() {
+    // Initialize Places through the History Service and check that a new
+    // database has been created.
+    do_check_eq(PlacesUtils.history.databaseStatus,
+                PlacesUtils.history.DATABASE_STATUS_CREATE);
+
+    // Wait for Places init notification.
+    Services.obs.addObserver(function(aSubject, aTopic, aData) {
+      Services.obs.removeObserver(arguments.callee,
+                                  PlacesUtils.TOPIC_INIT_COMPLETE);
+      do_execute_soon(function () {
+        // Ensure preferences status.
+        do_check_false(Services.prefs.getBoolPref(PREF_AUTO_EXPORT_HTML));
 
-tests.push({
-  description: "Import from bookmarks.html if importBookmarksHTML is true.",
-  exec: function() {
+        try {
+          do_check_false(Services.prefs.getBoolPref(PREF_IMPORT_BOOKMARKS_HTML));
+          do_throw("importBookmarksHTML pref should not exist");
+        }
+        catch(ex) {}
+
+        try {
+          do_check_false(Services.prefs.getBoolPref(PREF_RESTORE_DEFAULT_BOOKMARKS));
+          do_throw("importBookmarksHTML pref should not exist");
+        }
+        catch(ex) {}
+
+        run_next_test();
+      });
+    }, PlacesUtils.TOPIC_INIT_COMPLETE, false);
+  },
+
+  function test_import()
+  {
+    do_log_info("Import from bookmarks.html if importBookmarksHTML is true.");
+
+    remove_all_bookmarks();
     // Sanity check: we should not have any bookmark on the toolbar.
-    do_check_eq(bs.getIdForItemAt(bs.toolbarFolder, 0), -1);
+    let itemId =
+      PlacesUtils.bookmarks.getIdForItemAt(PlacesUtils.toolbarFolderId, 0);
+    do_check_eq(itemId, -1);
 
     // Set preferences.
-    ps.setBoolPref(PREF_IMPORT_BOOKMARKS_HTML, true);
-
-    // Force nsBrowserGlue::_initPlaces().
-    print("Simulate Places init");
-    bg.QueryInterface(Ci.nsIObserver).observe(null,
-                                              PlacesUtils.TOPIC_INIT_COMPLETE,
-                                              null);
-    // Check bookmarks.html has been imported, and a smart bookmark has been
-    // created.
-    let itemId = bs.getIdForItemAt(bs.toolbarFolder,
-                                   SMART_BOOKMARKS_ON_TOOLBAR);
-    do_check_eq(bs.getItemTitle(itemId), "example");
-    // Check preferences have been reverted.
-    do_check_false(ps.getBoolPref(PREF_IMPORT_BOOKMARKS_HTML));
-
-    next_test();
-  }
-});
-
-//------------------------------------------------------------------------------
-
-tests.push({
-  description: "import from bookmarks.html, but don't create smart bookmarks if they are disabled",
-  exec: function() {
-    // Sanity check: we should not have any bookmark on the toolbar.
-    do_check_eq(bs.getIdForItemAt(bs.toolbarFolder, 0), -1);
-
-    // Set preferences.
-    ps.setIntPref(PREF_SMART_BOOKMARKS_VERSION, -1);
-    ps.setBoolPref(PREF_IMPORT_BOOKMARKS_HTML, true);
+    Services.prefs.setBoolPref(PREF_IMPORT_BOOKMARKS_HTML, true);
 
     // Force nsBrowserGlue::_initPlaces().
     print("Simulate Places init");
     bg.QueryInterface(Ci.nsIObserver).observe(null,
-                                              PlacesUtils.TOPIC_INIT_COMPLETE,
-                                              null);
+                                              TOPIC_BROWSERGLUE_TEST,
+                                              TOPICDATA_FORCE_PLACES_INIT);
+
+    // Check bookmarks.html has been imported, and a smart bookmark has been
+    // created.
+    itemId = PlacesUtils.bookmarks.getIdForItemAt(PlacesUtils.toolbarFolderId,
+                                                  SMART_BOOKMARKS_ON_TOOLBAR);
+    do_check_eq(PlacesUtils.bookmarks.getItemTitle(itemId), "example");
+    // Check preferences have been reverted.
+    do_check_false(Services.prefs.getBoolPref(PREF_IMPORT_BOOKMARKS_HTML));
+
+    run_next_test();
+  },
+
+  function test_import_noSmartBookmarks()
+  {
+    do_log_info("import from bookmarks.html, but don't create smart bookmarks \
+                 if they are disabled");
+
+    remove_all_bookmarks();
+    // Sanity check: we should not have any bookmark on the toolbar.
+    let itemId =
+      PlacesUtils.bookmarks.getIdForItemAt(PlacesUtils.toolbarFolderId, 0);
+    do_check_eq(itemId, -1);
+
+    // Set preferences.
+    Services.prefs.setIntPref(PREF_SMART_BOOKMARKS_VERSION, -1);
+    Services.prefs.setBoolPref(PREF_IMPORT_BOOKMARKS_HTML, true);
+
+    // Force nsBrowserGlue::_initPlaces().
+    print("Simulate Places init");
+    bg.QueryInterface(Ci.nsIObserver).observe(null,
+                                              TOPIC_BROWSERGLUE_TEST,
+                                              TOPICDATA_FORCE_PLACES_INIT);
+
     // Check bookmarks.html has been imported, but smart bookmarks have not
     // been created.
-    let itemId = bs.getIdForItemAt(bs.toolbarFolder, 0);
-    do_check_eq(bs.getItemTitle(itemId), "example");
+    itemId =
+      PlacesUtils.bookmarks.getIdForItemAt(PlacesUtils.toolbarFolderId, 0);
+    do_check_eq(PlacesUtils.bookmarks.getItemTitle(itemId), "example");
     // Check preferences have been reverted.
-    do_check_false(ps.getBoolPref(PREF_IMPORT_BOOKMARKS_HTML));
-
-    next_test();
-  }
-});
+    do_check_false(Services.prefs.getBoolPref(PREF_IMPORT_BOOKMARKS_HTML));
 
-//------------------------------------------------------------------------------
-
-tests.push({
-  description: "Import from bookmarks.html, but don't create smart bookmarks if autoExportHTML is true and they are at latest version",
-  exec: function() {
-    // Sanity check: we should not have any bookmark on the toolbar.
-    do_check_eq(bs.getIdForItemAt(bs.toolbarFolder, 0), -1);
-    // Set preferences.
-    ps.setIntPref(PREF_SMART_BOOKMARKS_VERSION, 999);
-    ps.setBoolPref(PREF_AUTO_EXPORT_HTML, true);
-    ps.setBoolPref(PREF_IMPORT_BOOKMARKS_HTML, true);
+    run_next_test();
+  },
 
-    // Force nsBrowserGlue::_initPlaces()
-    print("Simulate Places init");
-    bg.QueryInterface(Ci.nsIObserver).observe(null,
-                                              PlacesUtils.TOPIC_INIT_COMPLETE,
-                                              null);
-    // Check bookmarks.html has been imported, but smart bookmarks have not
-    // been created.
-    let itemId = bs.getIdForItemAt(bs.toolbarFolder, 0);
-    do_check_eq(bs.getItemTitle(itemId), "example");
-    do_check_false(ps.getBoolPref(PREF_IMPORT_BOOKMARKS_HTML));
-    // Check preferences have been reverted.
-    ps.setBoolPref(PREF_AUTO_EXPORT_HTML, false);
+  function test_import_autoExport_updatedSmartBookmarks()
+  {
+    do_log_info("Import from bookmarks.html, but don't create smart bookmarks \
+                 if autoExportHTML is true and they are at latest version");
 
-    next_test();
-  }
-});
-
-//------------------------------------------------------------------------------
+    remove_all_bookmarks();
+    // Sanity check: we should not have any bookmark on the toolbar.
+    let itemId =
+      PlacesUtils.bookmarks.getIdForItemAt(PlacesUtils.toolbarFolderId, 0);
+    do_check_eq(itemId, -1);
 
-tests.push({
-  description: "Import from bookmarks.html, and create smart bookmarks if autoExportHTML is true and they are not at latest version.",
-  exec: function() {
-    // Sanity check: we should not have any bookmark on the toolbar.
-    do_check_eq(bs.getIdForItemAt(bs.toolbarFolder, 0), -1);
     // Set preferences.
-    ps.setIntPref(PREF_SMART_BOOKMARKS_VERSION, 0);
-    ps.setBoolPref(PREF_AUTO_EXPORT_HTML, true);
-    ps.setBoolPref(PREF_IMPORT_BOOKMARKS_HTML, true);
+    Services.prefs.setIntPref(PREF_SMART_BOOKMARKS_VERSION, 999);
+    Services.prefs.setBoolPref(PREF_AUTO_EXPORT_HTML, true);
+    Services.prefs.setBoolPref(PREF_IMPORT_BOOKMARKS_HTML, true);
 
     // Force nsBrowserGlue::_initPlaces()
     print("Simulate Places init");
     bg.QueryInterface(Ci.nsIObserver).observe(null,
-                                              PlacesUtils.TOPIC_INIT_COMPLETE,
-                                              null);
+                                              TOPIC_BROWSERGLUE_TEST,
+                                              TOPICDATA_FORCE_PLACES_INIT);
+
     // Check bookmarks.html has been imported, but smart bookmarks have not
     // been created.
-    let itemId = bs.getIdForItemAt(bs.toolbarFolder, SMART_BOOKMARKS_ON_TOOLBAR);
-    do_check_eq(bs.getItemTitle(itemId), "example");
-    do_check_false(ps.getBoolPref(PREF_IMPORT_BOOKMARKS_HTML));
+    itemId =
+      PlacesUtils.bookmarks.getIdForItemAt(PlacesUtils.toolbarFolderId, 0);
+    do_check_eq(PlacesUtils.bookmarks.getItemTitle(itemId), "example");
+    do_check_false(Services.prefs.getBoolPref(PREF_IMPORT_BOOKMARKS_HTML));
     // Check preferences have been reverted.
-    ps.setBoolPref(PREF_AUTO_EXPORT_HTML, false);
+    Services.prefs.setBoolPref(PREF_AUTO_EXPORT_HTML, false);
 
-    next_test();
-  }
-});
-
-//------------------------------------------------------------------------------
-tests.push({
-  description: "restore from default bookmarks.html if restore_default_bookmarks is true.",
-  exec: function() {
-    // Sanity check: we should not have any bookmark on the toolbar.
-    do_check_eq(bs.getIdForItemAt(bs.toolbarFolder, 0), -1);
-    // Set preferences.
-    ps.setBoolPref(PREF_RESTORE_DEFAULT_BOOKMARKS, true);
+    run_next_test();
+  },
 
-    // Force nsBrowserGlue::_initPlaces()
-    print("Simulate Places init");
-    bg.QueryInterface(Ci.nsIObserver).observe(null,
-                                              PlacesUtils.TOPIC_INIT_COMPLETE,
-                                              null);
-    // Check bookmarks.html has been restored.
-    let itemId = bs.getIdForItemAt(bs.toolbarFolder, SMART_BOOKMARKS_ON_TOOLBAR + 1);
-    do_check_true(itemId > 0);
-    // Check preferences have been reverted.
-    do_check_false(ps.getBoolPref(PREF_RESTORE_DEFAULT_BOOKMARKS));
+  function test_import_autoExport_oldSmartBookmarks()
+  {
+    do_log_info("Import from bookmarks.html, and create smart bookmarks if \
+                 autoExportHTML is true and they are not at latest version.");
 
-    next_test();
-  }
-});
-
-//------------------------------------------------------------------------------
+    remove_all_bookmarks();
+    // Sanity check: we should not have any bookmark on the toolbar.
+    let itemId =
+      PlacesUtils.bookmarks.getIdForItemAt(PlacesUtils.toolbarFolderId, 0);
+    do_check_eq(itemId, -1);
 
-tests.push({
-  description: "setting both importBookmarksHTML and restore_default_bookmarks should restore defaults.",
-  exec: function() {
-    // Sanity check: we should not have any bookmark on the toolbar.
-    do_check_eq(bs.getIdForItemAt(bs.toolbarFolder, 0), -1);
     // Set preferences.
-    ps.setBoolPref(PREF_IMPORT_BOOKMARKS_HTML, true);
-    ps.setBoolPref(PREF_RESTORE_DEFAULT_BOOKMARKS, true);
+    Services.prefs.setIntPref(PREF_SMART_BOOKMARKS_VERSION, 0);
+    Services.prefs.setBoolPref(PREF_AUTO_EXPORT_HTML, true);
+    Services.prefs.setBoolPref(PREF_IMPORT_BOOKMARKS_HTML, true);
 
     // Force nsBrowserGlue::_initPlaces()
     print("Simulate Places init");
     bg.QueryInterface(Ci.nsIObserver).observe(null,
-                                              PlacesUtils.TOPIC_INIT_COMPLETE,
-                                              null);
+                                              TOPIC_BROWSERGLUE_TEST,
+                                              TOPICDATA_FORCE_PLACES_INIT);
+
+    // Check bookmarks.html has been imported, but smart bookmarks have not
+    // been created.
+    itemId =
+      PlacesUtils.bookmarks.getIdForItemAt(PlacesUtils.toolbarFolderId,
+                                           SMART_BOOKMARKS_ON_TOOLBAR);
+    do_check_eq(PlacesUtils.bookmarks.getItemTitle(itemId), "example");
+    do_check_false(Services.prefs.getBoolPref(PREF_IMPORT_BOOKMARKS_HTML));
+    // Check preferences have been reverted.
+    Services.prefs.setBoolPref(PREF_AUTO_EXPORT_HTML, false);
+
+    run_next_test();
+  },
+
+  function test_restore()
+  {
+    do_log_info("restore from default bookmarks.html if \
+                 restore_default_bookmarks is true.");
+
+    remove_all_bookmarks();
+    // Sanity check: we should not have any bookmark on the toolbar.
+    let itemId =
+      PlacesUtils.bookmarks.getIdForItemAt(PlacesUtils.toolbarFolderId, 0);
+    do_check_eq(itemId, -1);
+
+    // Set preferences.
+    Services.prefs.setBoolPref(PREF_RESTORE_DEFAULT_BOOKMARKS, true);
+
+    // Force nsBrowserGlue::_initPlaces()
+    print("Simulate Places init");
+    bg.QueryInterface(Ci.nsIObserver).observe(null,
+                                              TOPIC_BROWSERGLUE_TEST,
+                                              TOPICDATA_FORCE_PLACES_INIT);
+
     // Check bookmarks.html has been restored.
-    let itemId = bs.getIdForItemAt(bs.toolbarFolder, SMART_BOOKMARKS_ON_TOOLBAR + 1);
+    itemId =
+      PlacesUtils.bookmarks.getIdForItemAt(PlacesUtils.toolbarFolderId,
+                                           SMART_BOOKMARKS_ON_TOOLBAR + 1);
     do_check_true(itemId > 0);
     // Check preferences have been reverted.
-    do_check_false(ps.getBoolPref(PREF_RESTORE_DEFAULT_BOOKMARKS));
-    do_check_false(ps.getBoolPref(PREF_IMPORT_BOOKMARKS_HTML));
+    do_check_false(Services.prefs.getBoolPref(PREF_RESTORE_DEFAULT_BOOKMARKS));
+
+    run_next_test();
+  },
+
+  function test_restore_import()
+  {
+    do_log_info("setting both importBookmarksHTML and \
+                 restore_default_bookmarks should restore defaults.");
+
+    remove_all_bookmarks();
+    // Sanity check: we should not have any bookmark on the toolbar.
+    let itemId =
+      PlacesUtils.bookmarks.getIdForItemAt(PlacesUtils.toolbarFolderId, 0);
+    do_check_eq(itemId, -1);
 
-    do_test_finished();
+    // Set preferences.
+    Services.prefs.setBoolPref(PREF_IMPORT_BOOKMARKS_HTML, true);
+    Services.prefs.setBoolPref(PREF_RESTORE_DEFAULT_BOOKMARKS, true);
+
+    // Force nsBrowserGlue::_initPlaces()
+    print("Simulate Places init");
+    bg.QueryInterface(Ci.nsIObserver).observe(null,
+                                              TOPIC_BROWSERGLUE_TEST,
+                                              TOPICDATA_FORCE_PLACES_INIT);
+
+    // Check bookmarks.html has been restored.
+    itemId =
+      PlacesUtils.bookmarks.getIdForItemAt(PlacesUtils.toolbarFolderId,
+                                           SMART_BOOKMARKS_ON_TOOLBAR + 1);
+    do_check_true(itemId > 0);
+    // Check preferences have been reverted.
+    do_check_false(Services.prefs.getBoolPref(PREF_RESTORE_DEFAULT_BOOKMARKS));
+    do_check_false(Services.prefs.getBoolPref(PREF_IMPORT_BOOKMARKS_HTML));
+
+    run_next_test();
   }
-});
 
-//------------------------------------------------------------------------------
+];
 
-function finish_test() {
-  // Clean up database from all bookmarks.
+do_register_cleanup(function () {
   remove_all_bookmarks();
   remove_bookmarks_html();
   remove_all_JSON_backups();
+});
 
-  do_test_finished();
-}
-var testIndex = 0;
-function next_test() {
-  // Clean up database from all bookmarks.
-  remove_all_bookmarks();
-  // nsBrowserGlue stops observing topics after first notification,
-  // so we add back the observer to test additional runs.
-  os.addObserver(bg.QueryInterface(Ci.nsIObserver),
-                 PlacesUtils.TOPIC_INIT_COMPLETE, false);
-  os.addObserver(bg.QueryInterface(Ci.nsIObserver),
-                 PlacesUtils.TOPIC_DATABASE_LOCKED, false);
-  // Execute next test.
-  let test = tests.shift();
-  print("\nTEST " + (++testIndex) + ": " + test.description);
-  test.exec();
-}
-function run_test() {
-  // Bug 539067: disabled due to random failures and timeouts.
-  return;
-
-  do_test_pending();
-  // Enqueue test, so it will consume the default places-init-complete
-  // notification created at Places init.
-  do_timeout(0, start_tests);
-}
-
-function start_tests() {
-  // Clean up database from all bookmarks.
-  remove_all_bookmarks();
-
-  // Ensure preferences status.
-  do_check_false(ps.getBoolPref(PREF_AUTO_EXPORT_HTML));
-  try {
-  do_check_false(ps.getBoolPref(PREF_IMPORT_BOOKMARKS_HTML));
-    do_throw("importBookmarksHTML pref should not exist");
-  }
-  catch(ex) {}
-  do_check_false(ps.getBoolPref(PREF_RESTORE_DEFAULT_BOOKMARKS));
-
+function run_test()
+{
   // Create our bookmarks.html from bookmarks.glue.html.
   create_bookmarks_html("bookmarks.glue.html");
   // Create our JSON backup from bookmarks.glue.json.
   create_JSON_backup("bookmarks.glue.json");
-  // Kick-off tests.
-  next_test();
+
+  run_next_test();
 }
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_opendir.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_opendir.js
@@ -49,18 +49,17 @@ function test() {
   let file = dir2.clone();
   file.append("pbtest.file");
   file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0600);
 
   const kPrefName = "browser.open.lastDir";
 
   function setupCleanSlate() {
     gLastOpenDirectory.reset();
-    if (gPrefService.prefHasUserValue(kPrefName))
-        gPrefService.clearUserPref(kPrefName);
+    gPrefService.clearUserPref(kPrefName);
   }
 
   setupCleanSlate();
 
   // Test 1: general workflow test
 
   // initial checks
   ok(!gLastOpenDirectory.path,
--- a/browser/components/sessionstore/test/browser/browser_480893.js
+++ b/browser/components/sessionstore/test/browser/browser_480893.js
@@ -72,19 +72,16 @@ function test() {
         browser.addEventListener("load", function(aEvent) {
           browser.removeEventListener("load", arguments.callee, true);
           let doc = browser.contentDocument;
 
           is(doc.URL, homepage, "loaded page is the homepage");
 
           // close tab, restore default values and finish the test
           gBrowser.removeTab(tab);
-          // we need this if-statement because if there is no user set value, 
-          // clearUserPref throws a uncatched exception and finish is not called
-          if (gPrefService.prefHasUserValue("browser.startup.page"))
-            gPrefService.clearUserPref("browser.startup.page");
+          gPrefService.clearUserPref("browser.startup.page");
           gPrefService.clearUserPref("browser.startup.homepage");
           finish();
         }, true);
       }, true);
     }, true);
   }, true);
 }
--- a/build/Makefile.in
+++ b/build/Makefile.in
@@ -67,17 +67,21 @@ DIRS += wince/tools \
 	$(DEPTH)/memory/mozalloc \
 	$(NULL)
 endif
 endif
 
 DIRS += pgo
 
 ifeq (Android,$(OS_TARGET))
-  DIRS += mobile/sutagent/android
+  DIRS += mobile/sutagent/android \
+          mobile/sutagent/android/watcher \
+          mobile/sutagent/android/ffxcp \
+          mobile/sutagent/android/fencp \
+          $(NULL)
 endif
 
 include $(topsrcdir)/config/rules.mk
 
 # we install to _leaktest/
 TARGET_DEPTH = ..
 include $(srcdir)/automation-build.mk
 
--- a/build/mobile/sutagent/android/ASMozStub.java
+++ b/build/mobile/sutagent/android/ASMozStub.java
@@ -1,122 +1,215 @@
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (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.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Android SUTAgent code.
- *
- * The Initial Developer of the Original Code is
- * Bob Moss.
- * Portions created by the Initial Developer are Copyright (C) 2010
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *  Bob Moss <bmoss@mozilla.com>
- * 
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-package com.mozilla.SUTAgentAndroid.service;
-
-import java.net.ServerSocket;
-import java.util.Timer;
-
-import android.app.NotificationManager;
-import android.content.Context;
-import android.content.Intent;
-// import android.os.Binder;
-import android.os.Handler;
-import android.os.IBinder;
-import android.widget.Toast;
-
-public class ASMozStub extends android.app.Service {
-	
-	private ServerSocket cmdChnl = null;
-	private ServerSocket dataChnl = null;
-	private Handler handler = new Handler();
-	RunCmdThread runCmdThrd = null;
-	RunDataThread runDataThrd = null;
-	Thread monitor = null;
-	Timer timer = null;
-	
-	@Override
-	public IBinder onBind(Intent intent)
-		{
-		return null;
-		}
-	
-	@Override
-	public void onCreate() {
-		super.onCreate();
-		Toast.makeText(this, "Listener Service created...", Toast.LENGTH_LONG).show();
-		}
-
-	public void onStart(Intent intent, int startId) {
-		super.onStart(intent, startId);
-		
-		try {
-			cmdChnl = new ServerSocket(20701);
-			runCmdThrd = new RunCmdThread(cmdChnl, this, handler);
-			runCmdThrd.start();
-			Toast.makeText(this, "Command channel port 20701 ...", Toast.LENGTH_LONG).show();
-			
-			dataChnl = new ServerSocket(20700);
-			runDataThrd = new RunDataThread(dataChnl, this);
-			runDataThrd.start();
-			Toast.makeText(this, "Data channel port 20700 ...", Toast.LENGTH_LONG).show();
-			} 
-		catch (Exception e) {
-//			Toast.makeText(getApplication().getApplicationContext(), e.toString(), Toast.LENGTH_LONG).show();
-			}
-		
-		return;
-		}
-	
-	public void onDestroy()
-		{
-		super.onDestroy();
-		if (runCmdThrd.isAlive())
-			{
-			runCmdThrd.StopListening();
-			}
-		
-		if (runDataThrd.isAlive())
-			{
-			runDataThrd.StopListening();
-			}
-		
-		NotificationManager notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
-		notificationManager.cancel(1959);
-		
-		Toast.makeText(this, "Listener Service destroyed...", Toast.LENGTH_LONG).show();
-		
-		System.exit(0);
-		}
-	
-	public void SendToDataChannel(String strToSend)
-		{
-		if (runDataThrd.isAlive())
-			{
-			runDataThrd.SendToDataChannel(strToSend);
-			}
-		}
-}
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (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.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Android SUTAgent code.
+ *
+ * The Initial Developer of the Original Code is
+ * Bob Moss.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Bob Moss <bmoss@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package com.mozilla.SUTAgentAndroid.service;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.ServerSocket;
+import java.util.Timer;
+
+import com.mozilla.SUTAgentAndroid.R;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.util.Log;
+import android.view.Gravity;
+import android.widget.Toast;
+
+public class ASMozStub extends android.app.Service {
+
+    private ServerSocket cmdChnl = null;
+    private ServerSocket dataChnl = null;
+    private Handler handler = new Handler();
+    RunCmdThread runCmdThrd = null;
+    RunDataThread runDataThrd = null;
+    Thread monitor = null;
+    Timer timer = null;
+
+    @SuppressWarnings("unchecked")
+    private static final Class[] mStartForegroundSignature = new Class[] {
+        int.class, Notification.class};
+    @SuppressWarnings("unchecked")
+    private static final Class[] mStopForegroundSignature = new Class[] {
+        boolean.class};
+
+    private NotificationManager mNM;
+    private Method mStartForeground;
+    private Method mStopForeground;
+    private Object[] mStartForegroundArgs = new Object[2];
+    private Object[] mStopForegroundArgs = new Object[1];
+
+    @Override
+    public IBinder onBind(Intent intent)
+        {
+        return null;
+        }
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+
+        mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
+        try {
+            mStartForeground = getClass().getMethod("startForeground", mStartForegroundSignature);
+            mStopForeground = getClass().getMethod("stopForeground", mStopForegroundSignature);
+            }
+        catch (NoSuchMethodException e) {
+            // Running on an older platform.
+            mStartForeground = mStopForeground = null;
+            }
+
+        doToast("Listener Service created...");
+        }
+
+    public void onStart(Intent intent, int startId) {
+        super.onStart(intent, startId);
+
+        try {
+            cmdChnl = new ServerSocket(20701);
+            runCmdThrd = new RunCmdThread(cmdChnl, this, handler);
+            runCmdThrd.start();
+            doToast("Command channel port 20701 ...");
+
+            dataChnl = new ServerSocket(20700);
+            runDataThrd = new RunDataThread(dataChnl, this);
+            runDataThrd.start();
+            doToast("Data channel port 20700 ...");
+
+            Notification notification = new Notification();
+            startForegroundCompat(R.string.foreground_service_started, notification);
+            }
+        catch (Exception e) {
+            doToast(e.toString());
+//            Toast.makeText(getApplication().getApplicationContext(), e.toString(), Toast.LENGTH_LONG).show();
+            }
+
+        return;
+        }
+
+    public void onDestroy()
+        {
+        super.onDestroy();
+
+        if (runCmdThrd.isAlive())
+            {
+            runCmdThrd.StopListening();
+            }
+
+        if (runDataThrd.isAlive())
+            {
+            runDataThrd.StopListening();
+            }
+
+        NotificationManager notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
+        notificationManager.cancel(1959);
+
+        stopForegroundCompat(R.string.foreground_service_started);
+
+        doToast("Listener Service destroyed...");
+
+        System.exit(0);
+        }
+
+    public void SendToDataChannel(String strToSend)
+        {
+        if (runDataThrd.isAlive())
+            runDataThrd.SendToDataChannel(strToSend);
+        }
+
+    public void doToast(String sMsg) {
+        Toast toast = Toast.makeText(this, sMsg, Toast.LENGTH_LONG);
+        toast.setGravity(Gravity.TOP|Gravity.CENTER_HORIZONTAL, 0, 100);
+        toast.show();
+    }
+
+    /**
+     * This is a wrapper around the new startForeground method, using the older
+     * APIs if it is not available.
+     */
+    void startForegroundCompat(int id, Notification notification) {
+        // If we have the new startForeground API, then use it.
+        if (mStartForeground != null) {
+            mStartForegroundArgs[0] = Integer.valueOf(id);
+            mStartForegroundArgs[1] = notification;
+            try {
+                mStartForeground.invoke(this, mStartForegroundArgs);
+            } catch (InvocationTargetException e) {
+                // Should not happen.
+                Log.w("ScreenOnWidget", "Unable to invoke startForeground", e);
+            } catch (IllegalAccessException e) {
+                // Should not happen.
+                Log.w("ScreenOnWidget", "Unable to invoke startForeground", e);
+            }
+            return;
+        }
+
+        // Fall back on the old API.
+        setForeground(true);
+        mNM.notify(id, notification);
+    }
+
+    /**
+     * This is a wrapper around the new stopForeground method, using the older
+     * APIs if it is not available.
+     */
+    void stopForegroundCompat(int id) {
+        // If we have the new stopForeground API, then use it.
+        if (mStopForeground != null) {
+            mStopForegroundArgs[0] = Boolean.TRUE;
+            try {
+                mStopForeground.invoke(this, mStopForegroundArgs);
+            } catch (InvocationTargetException e) {
+                // Should not happen.
+                Log.w("ScreenOnWidget", "Unable to invoke stopForeground", e);
+            } catch (IllegalAccessException e) {
+                // Should not happen.
+                Log.w("ScreenOnWidget", "Unable to invoke stopForeground", e);
+            }
+            return;
+        }
+
+        // Fall back on the old API.  Note to cancel BEFORE changing the
+        // foreground state, since we could be killed at that point.
+        mNM.cancel(id);
+        setForeground(false);
+    }
+}
--- a/build/mobile/sutagent/android/AlertLooperThread.java
+++ b/build/mobile/sutagent/android/AlertLooperThread.java
@@ -1,96 +1,96 @@
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (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.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Android SUTAgent code.
- *
- * The Initial Developer of the Original Code is
- * Bob Moss.
- * Portions created by the Initial Developer are Copyright (C) 2010
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *  Bob Moss <bmoss@mozilla.com>
- * 
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-package com.mozilla.SUTAgentAndroid.service;
-
-import java.util.Timer;
-
-import android.content.ContextWrapper;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-
-class AlertLooperThread extends Thread
-	{
-	public Handler mHandler;
-	private Looper looper = null;
-	private DoAlert da	= null;
-	private Timer alertTimer = null;
-	private ContextWrapper contextWrapper = null;
-	
-	AlertLooperThread(ContextWrapper ctxW)
-		{
-		this.contextWrapper = ctxW;
-		}
-	
-	public Timer getAlertTimer()
-		{
-		return alertTimer;
-		}
-
-	public void term()
-		{
-		if (da != null)
-			da.term();
-		}
-
-	public void quit()
-		{
-		if (looper != null)
-			looper.quit();
-		}
-
-	public void run()
-		{
-		Looper.prepare();
-    
-		looper = Looper.myLooper();
-      
-		mHandler = new Handler()
-    		{
-			public void handleMessage(Message msg)
-        		{
-				// process incoming messages here
-        		}
-    		};
-      
-    	alertTimer = new Timer();
-    	da = new DoAlert(contextWrapper);
-    	alertTimer.scheduleAtFixedRate(da, 0, 5000);
-    	Looper.loop();
-		}
-	}
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (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.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Android SUTAgent code.
+ *
+ * The Initial Developer of the Original Code is
+ * Bob Moss.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Bob Moss <bmoss@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package com.mozilla.SUTAgentAndroid.service;
+
+import java.util.Timer;
+
+import android.content.ContextWrapper;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+
+class AlertLooperThread extends Thread
+    {
+    public Handler mHandler;
+    private Looper looper = null;
+    private DoAlert da    = null;
+    private Timer alertTimer = null;
+    private ContextWrapper contextWrapper = null;
+
+    AlertLooperThread(ContextWrapper ctxW)
+        {
+        this.contextWrapper = ctxW;
+        }
+
+    public Timer getAlertTimer()
+        {
+        return alertTimer;
+        }
+
+    public void term()
+        {
+        if (da != null)
+            da.term();
+        }
+
+    public void quit()
+        {
+        if (looper != null)
+            looper.quit();
+        }
+
+    public void run()
+        {
+        Looper.prepare();
+
+        looper = Looper.myLooper();
+
+        mHandler = new Handler()
+            {
+            public void handleMessage(Message msg)
+                {
+                // process incoming messages here
+                }
+            };
+
+        alertTimer = new Timer();
+        da = new DoAlert(contextWrapper);
+        alertTimer.scheduleAtFixedRate(da, 0, 5000);
+        Looper.loop();
+        }
+    }
--- a/build/mobile/sutagent/android/AndroidManifest.xml
+++ b/build/mobile/sutagent/android/AndroidManifest.xml
@@ -1,13 +1,12 @@
 <?xml version="1.0" encoding="utf-8"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
       package="com.mozilla.SUTAgentAndroid"
-      android:versionCode="1"
-      android:versionName="1.0" android:sharedUserId="org.mozilla.sharedID">
+      android:versionCode="1" android:versionName="1.01">
     <application android:icon="@drawable/icon" android:label="@string/app_name" android:debuggable="true">
         <activity android:name=".SUTAgentAndroid"
                   android:screenOrientation="nosensor"
                   android:label="@string/app_name">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
@@ -18,18 +17,17 @@
                  <category android:value="android.intent.category.HOME" android:name="android.intent.category.HOME"/>
             </intent-filter>
         </receiver>
         <service android:name=".service.ASMozStub">
 		    <intent-filter>
 			    <action android:name="com.mozilla.SUTAgentAndroid.service.LISTENER_SERVICE" />
 		    </intent-filter>
 	    </service>
-
-    </application>
+	</application>
     
     <uses-sdk android:minSdkVersion="5" android:targetSdkVersion="8"/>
 
 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
 <uses-permission android:name="android.permission.INTERNET"></uses-permission>
 <uses-permission android:name="android.permission.REBOOT"></uses-permission>
 <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"></uses-permission>
 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
@@ -38,34 +36,22 @@
 <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"></uses-permission>
 <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"></uses-permission>
 <uses-permission android:name="android.permission.CHANGE_CONFIGURATION"></uses-permission>
 <uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission>
 <uses-permission android:name="android.permission.BATTERY_STATS"></uses-permission>
 <uses-permission android:name="android.permission.DEVICE_POWER"></uses-permission>
 <uses-permission android:name="android.permission.DISABLE_KEYGUARD"></uses-permission>
 <uses-permission android:name="android.permission.WAKE_LOCK"></uses-permission>
-
 <uses-permission android:name="android.permission.WRITE_SETTINGS"></uses-permission>
 <uses-permission android:name="android.permission.READ_SYNC_SETTINGS"></uses-permission>
-
 <uses-permission android:name="android.permission.BLUETOOTH"></uses-permission>
-
 <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"></uses-permission>
-
 <uses-permission android:name="android.permission.INSTALL_PACKAGES"></uses-permission>
-
-
-
-
 <uses-permission android:name="android.permission.STATUS_BAR"></uses-permission>
-
 <uses-permission android:name="android.permission.VIBRATE"></uses-permission>
-
-
-
 <uses-permission android:name="android.permission.SET_TIME"></uses-permission>
-
-
-
 <uses-permission android:name="android.permission.SET_TIME_ZONE"></uses-permission>
 
+<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"></uses-permission>
+<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS"></uses-permission>
+
 </manifest> 
\ No newline at end of file
--- a/build/mobile/sutagent/android/CmdWorkerThread.java
+++ b/build/mobile/sutagent/android/CmdWorkerThread.java
@@ -1,199 +1,199 @@
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (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.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Android SUTAgent code.
- *
- * The Initial Developer of the Original Code is
- * Bob Moss.
- * Portions created by the Initial Developer are Copyright (C) 2010
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *  Bob Moss <bmoss@mozilla.com>
- * 
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-package com.mozilla.SUTAgentAndroid.service;
-
-import java.io.BufferedInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.PrintWriter;
-import java.net.Socket;
-import java.net.SocketTimeoutException;
-
-// import com.mozilla.SUTAgentAndroid.DoCommand;
-
-public class CmdWorkerThread extends Thread
-{
-	private RunCmdThread theParent = null;
-	private Socket socket	= null;
-	private String prompt = null;
-	boolean bListening	= true;
-
-	public CmdWorkerThread(RunCmdThread theParent, Socket workerSocket)
-		{
-		super("CmdWorkerThread");
-		this.theParent = theParent;
-		this.socket = workerSocket;
-		byte pr [] = new byte [3];
-		pr[0] = '$';
-		pr[1] = '>';
-		pr[2] = 0;
-		prompt = new String(pr,0,3);
-		}
-
-	public void StopListening()
-		{
-		bListening = false;
-		}
-	
-	private String readLine(BufferedInputStream in)
-		{
-		String sRet = "";
-		int nByte = 0;
-		char cChar = 0;
-		
-		try 
-			{
-			nByte = in.read();
-			while (nByte != -1)
-				{
-				cChar = ((char)(nByte & 0xFF));
-				if ((cChar != '\r') && (cChar != '\n'))
-					sRet += cChar;
-				else
-					break;
-				nByte = in.read();
-				}
-			
-			if ((in.available() > 0) && (cChar != '\n'))
-				{
-				in.mark(1024);
-				nByte = in.read();
-				
-				if (nByte != -1)
-					{
-					cChar = ((char)(nByte & 0xFF));
-					if (cChar != '\n')
-						{
-						in.reset();
-						}
-					}
-				}
-			}
-		catch (IOException e)
-			{
-			// TODO Auto-generated catch block
-			e.printStackTrace();
-			}
-		
-		if (sRet.length() == 0)
-			sRet = null;
-		
-		return(sRet);
-		}
-
-	public void run()
-		{
-		try {
-			OutputStream cmdOut = socket.getOutputStream();
-			InputStream cmdIn = socket.getInputStream();
-			PrintWriter out = new PrintWriter(cmdOut, true);
-			BufferedInputStream in = new BufferedInputStream(cmdIn);
-			String inputLine, outputLine;
-			DoCommand dc = new DoCommand(theParent.svc);
-
-			int nAvail = cmdIn.available();
-			cmdIn.skip(nAvail);
-				
-			out.print(prompt);
-			out.flush();
-
-			while (bListening)
-				{
-				if (!(in.available() > 0))
-					{
-					socket.setSoTimeout(500);
-					try {
-						int nRead = cmdIn.read();
-						if (nRead == -1)
-							{
-							bListening = false;
-							continue;
-							}
-						else
-							{
-							inputLine = ((char)nRead) + "";
-							socket.setSoTimeout(120000);
-							}
-						}
-					catch(SocketTimeoutException toe)
-						{
-						continue;
-						}
-					}
-				else
-					inputLine = "";
-				
-				if ((inputLine += readLine(in)) != null)
-					{
-					outputLine = dc.processCommand(inputLine, out, in, cmdOut);
-					if (outputLine.length() > 0)
-						{
-						out.print(outputLine + "\n" + prompt);
-						}
-					else
-						out.print(prompt);
-					out.flush();
-					if (outputLine.equals("exit"))
-						{
-						theParent.StopListening();
-						bListening = false;
-						}
-					if (outputLine.equals("quit"))
-						{
-						bListening = false;
-						}
-					outputLine = null;
-					System.gc();
-					}
-				else
-					break;
-				}
-			out.close();
-			out = null;
-			in.close();
-			in = null;
-			socket.close();
-		}
-	catch (IOException e)
-		{
-		// TODO Auto-generated catch block
-		e.printStackTrace();
-		}
-	}
-}
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (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.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Android SUTAgent code.
+ *
+ * The Initial Developer of the Original Code is
+ * Bob Moss.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Bob Moss <bmoss@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package com.mozilla.SUTAgentAndroid.service;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.net.Socket;
+import java.net.SocketTimeoutException;
+
+// import com.mozilla.SUTAgentAndroid.DoCommand;
+
+public class CmdWorkerThread extends Thread
+{
+    private RunCmdThread theParent = null;
+    private Socket socket    = null;
+    private String prompt = null;
+    boolean bListening    = true;
+
+    public CmdWorkerThread(RunCmdThread theParent, Socket workerSocket)
+        {
+        super("CmdWorkerThread");
+        this.theParent = theParent;
+        this.socket = workerSocket;
+        byte pr [] = new byte [3];
+        pr[0] = '$';
+        pr[1] = '>';
+        pr[2] = 0;
+        prompt = new String(pr,0,3);
+        }
+
+    public void StopListening()
+        {
+        bListening = false;
+        }
+
+    private String readLine(BufferedInputStream in)
+        {
+        String sRet = "";
+        int nByte = 0;
+        char cChar = 0;
+
+        try
+            {
+            nByte = in.read();
+            while (nByte != -1)
+                {
+                cChar = ((char)(nByte & 0xFF));
+                if ((cChar != '\r') && (cChar != '\n'))
+                    sRet += cChar;
+                else
+                    break;
+                nByte = in.read();
+                }
+
+            if ((in.available() > 0) && (cChar != '\n'))
+                {
+                in.mark(1024);
+                nByte = in.read();
+
+                if (nByte != -1)
+                    {
+                    cChar = ((char)(nByte & 0xFF));
+                    if (cChar != '\n')
+                        {
+                        in.reset();
+                        }
+                    }
+                }
+            }
+        catch (IOException e)
+            {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+            }
+
+        if (sRet.length() == 0)
+            sRet = null;
+
+        return(sRet);
+        }
+
+    public void run()
+        {
+        try {
+            OutputStream cmdOut = socket.getOutputStream();
+            InputStream cmdIn = socket.getInputStream();
+            PrintWriter out = new PrintWriter(cmdOut, true);
+            BufferedInputStream in = new BufferedInputStream(cmdIn);
+            String inputLine, outputLine;
+            DoCommand dc = new DoCommand(theParent.svc);
+
+            int nAvail = cmdIn.available();
+            cmdIn.skip(nAvail);
+
+            out.print(prompt);
+            out.flush();
+
+            while (bListening)
+                {
+                if (!(in.available() > 0))
+                    {
+                    socket.setSoTimeout(500);
+                    try {
+                        int nRead = cmdIn.read();
+                        if (nRead == -1)
+                            {
+                            bListening = false;
+                            continue;
+                            }
+                        else
+                            {
+                            inputLine = ((char)nRead) + "";
+                            socket.setSoTimeout(120000);
+                            }
+                        }
+                    catch(SocketTimeoutException toe)
+                        {
+                        continue;
+                        }
+                    }
+                else
+                    inputLine = "";
+
+                if ((inputLine += readLine(in)) != null)
+                    {
+                    outputLine = dc.processCommand(inputLine, out, in, cmdOut);
+                    if (outputLine.length() > 0)
+                        {
+                        out.print(outputLine + "\n" + prompt);
+                        }
+                    else
+                        out.print(prompt);
+                    out.flush();
+                    if (outputLine.equals("exit"))
+                        {
+                        theParent.StopListening();
+                        bListening = false;
+                        }
+                    if (outputLine.equals("quit"))
+                        {
+                        bListening = false;
+                        }
+                    outputLine = null;
+                    System.gc();
+                    }
+                else
+                    break;
+                }
+            out.close();
+            out = null;
+            in.close();
+            in = null;
+            socket.close();
+        }
+    catch (IOException e)
+        {
+        // TODO Auto-generated catch block
+        e.printStackTrace();
+        }
+    }
+}
--- a/build/mobile/sutagent/android/DataWorkerThread.java
+++ b/build/mobile/sutagent/android/DataWorkerThread.java
@@ -1,237 +1,237 @@
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (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.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Android SUTAgent code.
- *
- * The Initial Developer of the Original Code is
- * Bob Moss.
- * Portions created by the Initial Developer are Copyright (C) 2010
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *  Bob Moss <bmoss@mozilla.com>
- * 
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-package com.mozilla.SUTAgentAndroid.service;
-
-import java.io.BufferedInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.PrintWriter;
-import java.net.Socket;
-import java.net.SocketTimeoutException;
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
-
-// import com.mozilla.SUTAgentAndroid.DoCommand;
-import com.mozilla.SUTAgentAndroid.SUTAgentAndroid;
-
-public class DataWorkerThread extends Thread
-{
-	private RunDataThread theParent = null;
-	private Socket socket	= null;
-	boolean bListening	= true;
-	PrintWriter out = null;
-	SimpleDateFormat sdf = null;
-
-	public DataWorkerThread(RunDataThread theParent, Socket workerSocket)
-		{
-		super("DataWorkerThread");
-		this.theParent = theParent;
-		this.socket = workerSocket;
-		this.sdf = new SimpleDateFormat("yyyyMMdd-HH:mm:ss");
-		}
-
-	public void StopListening()
-		{
-		bListening = false;
-		}
-	
-	public void SendString(String strToSend)
-		{
-		if (this.out != null)
-			{
-			Calendar cal = Calendar.getInstance();
-			String strOut = sdf.format(cal.getTime());
-			strOut += " " + strToSend + "\r\n";
-		
-			out.write(strOut);
-			out.flush();
-			}
-		}
-
-	private String readLine(BufferedInputStream in)
-		{
-		String sRet = "";
-		int nByte = 0;
-		char cChar = 0;
-	
-		try 
-			{
-			nByte = in.read();
-			while (nByte != -1)
-				{
-				cChar = ((char)(nByte & 0xFF));
-				if ((cChar != '\r') && (cChar != '\n'))
-					sRet += cChar;
-				else
-					break;
-				nByte = in.read();
-				}
-		
-			if (in.available() > 0)
-				{
-				in.mark(1024);
-				nByte = in.read();
-		
-				while (nByte != -1)
-					{
-					cChar = ((char)(nByte & 0xFF));
-					if ((cChar == '\r') || (cChar == '\n'))
-						{
-						if (in.available() > 0)
-							{
-							in.mark(1024);
-							nByte = in.read();
-							}
-						else
-							nByte = -1;
-						}
-					else
-						{
-						in.reset();
-						break;
-						}
-					}
-				}
-			}
-		catch (IOException e)
-			{
-			// TODO Auto-generated catch block
-			e.printStackTrace();
-			}
-	
-		if (sRet.length() == 0)
-			sRet = null;
-	
-		return(sRet);
-		}
-
-	public void run()
-		{
-		String	sRet = "";
-		long lEndTime = System.currentTimeMillis() + 60000;
-		
-		try {
-			while(bListening)
-				{
-				OutputStream cmdOut = socket.getOutputStream();
-				InputStream cmdIn = socket.getInputStream();
-				this.out = new PrintWriter(cmdOut, true);
-				BufferedInputStream in = new BufferedInputStream(cmdIn);
-				String inputLine, outputLine;
-				DoCommand dc = new DoCommand(theParent.svc);
-				
-	    		Calendar cal = Calendar.getInstance();
-	    		sRet = sdf.format(cal.getTime());
-	    		sRet += " trace output";
-
-				out.println(sRet);
-				out.flush();
-				int nAvail = cmdIn.available();
-				cmdIn.skip(nAvail);
-				
-				while (bListening)
-					{
-					if (System.currentTimeMillis() > lEndTime)
-						{
-						cal = Calendar.getInstance();
-			    		sRet = sdf.format(cal.getTime());
-			    		sRet += " Thump thump - " + SUTAgentAndroid.sUniqueID + "\r\n";
-
-			    		out.write(sRet);
-			    		out.flush();
-						
-						lEndTime = System.currentTimeMillis() + 60000;
-						}
-					
-					if (!(in.available() > 0))
-						{
-						socket.setSoTimeout(500);
-						try {
-							int nRead = cmdIn.read();
-							if (nRead == -1)
-								{
-								bListening = false;
-								continue;
-								}
-							else
-								inputLine = (char)nRead + ""; 
-							}
-						catch(SocketTimeoutException toe)
-							{
-							continue;
-							}
-						}
-					else
-						inputLine = "";
-				
-					if ((inputLine += readLine(in)) != null)
-						{
-						outputLine = dc.processCommand(inputLine, out, in, cmdOut);
-						out.print(outputLine + "\n");
-						out.flush();
-						if (outputLine.equals("exit"))
-							{
-							theParent.StopListening();
-							bListening = false;
-							}
-						if (outputLine.equals("quit"))
-							{
-							bListening = false;
-							}
-						outputLine = null;
-						System.gc();
-						}
-					else
-						break;
-					}
-				
-				out.close();
-				out = null;
-				in.close();
-				in = null;
-				socket.close();
-				}
-			}
-		catch (IOException e)
-			{
-			// TODO Auto-generated catch block
-			e.printStackTrace();
-			}
-		}
-}
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (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.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Android SUTAgent code.
+ *
+ * The Initial Developer of the Original Code is
+ * Bob Moss.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Bob Moss <bmoss@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package com.mozilla.SUTAgentAndroid.service;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.net.Socket;
+import java.net.SocketTimeoutException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+
+// import com.mozilla.SUTAgentAndroid.DoCommand;
+import com.mozilla.SUTAgentAndroid.SUTAgentAndroid;
+
+public class DataWorkerThread extends Thread
+{
+    private RunDataThread theParent = null;
+    private Socket socket    = null;
+    boolean bListening    = true;
+    PrintWriter out = null;
+    SimpleDateFormat sdf = null;
+
+    public DataWorkerThread(RunDataThread theParent, Socket workerSocket)
+        {
+        super("DataWorkerThread");
+        this.theParent = theParent;
+        this.socket = workerSocket;
+        this.sdf = new SimpleDateFormat("yyyyMMdd-HH:mm:ss");
+        }
+
+    public void StopListening()
+        {
+        bListening = false;
+        }
+
+    public void SendString(String strToSend)
+        {
+        if (this.out != null)
+            {
+            Calendar cal = Calendar.getInstance();
+            String strOut = sdf.format(cal.getTime());
+            strOut += " " + strToSend + "\r\n";
+
+            out.write(strOut);
+            out.flush();
+            }
+        }
+
+    private String readLine(BufferedInputStream in)
+        {
+        String sRet = "";
+        int nByte = 0;
+        char cChar = 0;
+
+        try
+            {
+            nByte = in.read();
+            while (nByte != -1)
+                {
+                cChar = ((char)(nByte & 0xFF));
+                if ((cChar != '\r') && (cChar != '\n'))
+                    sRet += cChar;
+                else
+                    break;
+                nByte = in.read();
+                }
+
+            if (in.available() > 0)
+                {
+                in.mark(1024);
+                nByte = in.read();
+
+                while (nByte != -1)
+                    {
+                    cChar = ((char)(nByte & 0xFF));
+                    if ((cChar == '\r') || (cChar == '\n'))
+                        {
+                        if (in.available() > 0)
+                            {
+                            in.mark(1024);
+                            nByte = in.read();
+                            }
+                        else
+                            nByte = -1;
+                        }
+                    else
+                        {
+                        in.reset();
+                        break;
+                        }
+                    }
+                }
+            }
+        catch (IOException e)
+            {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+            }
+
+        if (sRet.length() == 0)
+            sRet = null;
+
+        return(sRet);
+        }
+
+    public void run()
+        {
+        String    sRet = "";
+        long lEndTime = System.currentTimeMillis() + 60000;
+
+        try {
+            while(bListening)
+                {
+                OutputStream cmdOut = socket.getOutputStream();
+                InputStream cmdIn = socket.getInputStream();
+                this.out = new PrintWriter(cmdOut, true);
+                BufferedInputStream in = new BufferedInputStream(cmdIn);
+                String inputLine, outputLine;
+                DoCommand dc = new DoCommand(theParent.svc);
+
+                Calendar cal = Calendar.getInstance();
+                sRet = sdf.format(cal.getTime());
+                sRet += " trace output";
+
+                out.println(sRet);
+                out.flush();
+                int nAvail = cmdIn.available();
+                cmdIn.skip(nAvail);
+
+                while (bListening)
+                    {
+                    if (System.currentTimeMillis() > lEndTime)
+                        {
+                        cal = Calendar.getInstance();
+                        sRet = sdf.format(cal.getTime());
+                        sRet += " Thump thump - " + SUTAgentAndroid.sUniqueID + "\r\n";
+
+                        out.write(sRet);
+                        out.flush();
+
+                        lEndTime = System.currentTimeMillis() + 60000;
+                        }
+
+                    if (!(in.available() > 0))
+                        {
+                        socket.setSoTimeout(500);
+                        try {
+                            int nRead = cmdIn.read();
+                            if (nRead == -1)
+                                {
+                                bListening = false;
+                                continue;
+                                }
+                            else
+                                inputLine = (char)nRead + "";
+                            }
+                        catch(SocketTimeoutException toe)
+                            {
+                            continue;
+                            }
+                        }
+                    else
+                        inputLine = "";
+
+                    if ((inputLine += readLine(in)) != null)
+                        {
+                        outputLine = dc.processCommand(inputLine, out, in, cmdOut);
+                        out.print(outputLine + "\n");
+                        out.flush();
+                        if (outputLine.equals("exit"))
+                            {
+                            theParent.StopListening();
+                            bListening = false;
+                            }
+                        if (outputLine.equals("quit"))
+                            {
+                            bListening = false;
+                            }
+                        outputLine = null;
+                        System.gc();
+                        }
+                    else
+                        break;
+                    }
+
+                out.close();
+                out = null;
+                in.close();
+                in = null;
+                socket.close();
+                }
+            }
+        catch (IOException e)
+            {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+            }
+        }
+}
--- a/build/mobile/sutagent/android/DoAlert.java
+++ b/build/mobile/sutagent/android/DoAlert.java
@@ -1,81 +1,81 @@
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (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.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Android SUTAgent code.
- *
- * The Initial Developer of the Original Code is
- * Bob Moss.
- * Portions created by the Initial Developer are Copyright (C) 2010
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *  Bob Moss <bmoss@mozilla.com>
- * 
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-package com.mozilla.SUTAgentAndroid.service;
-
-import java.util.TimerTask;
-
-import android.content.Context;
-import android.content.ContextWrapper;
-import android.media.Ringtone;
-import android.media.RingtoneManager;
-import android.widget.Toast;
-
-class DoAlert extends TimerTask
-	{
-	int	lcv = 0;
-	Toast toast = null;
-	Ringtone rt = null;
-
-	DoAlert(ContextWrapper contextWrapper)
-		{
-		Context	ctx = contextWrapper.getApplicationContext();
-		this.toast = Toast.makeText(ctx, "Help me!", Toast.LENGTH_LONG);
-		rt = RingtoneManager.getRingtone(ctx, RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM));
-		}
-
-	public void term()
-		{
-		if (rt != null)
-			{
-			if (rt.isPlaying())
-				rt.stop();
-			}
-
-		if (toast != null)
-			toast.cancel();
-		}
-
-	public void run ()
-		{
-		String sText =(((lcv++ % 2) == 0)  ? "Help me!" : "I've fallen down!" );
-		toast.setText(sText);
-		toast.show();
-		if (rt != null)
-			rt.play();
-		}
-	}
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (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.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Android SUTAgent code.
+ *
+ * The Initial Developer of the Original Code is
+ * Bob Moss.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Bob Moss <bmoss@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package com.mozilla.SUTAgentAndroid.service;
+
+import java.util.TimerTask;
+
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.media.Ringtone;
+import android.media.RingtoneManager;
+import android.widget.Toast;
+
+class DoAlert extends TimerTask
+    {
+    int    lcv = 0;
+    Toast toast = null;
+    Ringtone rt = null;
+
+    DoAlert(ContextWrapper contextWrapper)
+        {
+        Context    ctx = contextWrapper.getApplicationContext();
+        this.toast = Toast.makeText(ctx, "Help me!", Toast.LENGTH_LONG);
+        rt = RingtoneManager.getRingtone(ctx, RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM));
+        }
+
+    public void term()
+        {
+        if (rt != null)
+            {
+            if (rt.isPlaying())
+                rt.stop();
+            }
+
+        if (toast != null)
+            toast.cancel();
+        }
+
+    public void run ()
+        {
+        String sText =(((lcv++ % 2) == 0)  ? "Help me!" : "I've fallen down!" );
+        toast.setText(sText);
+        toast.show();
+        if (rt != null)
+            rt.play();
+        }
+    }
--- a/build/mobile/sutagent/android/DoCommand.java
+++ b/build/mobile/sutagent/android/DoCommand.java
@@ -1,2967 +1,3681 @@
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (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.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Android SUTAgent code.
- *
- * The Initial Developer of the Original Code is
- * Bob Moss.
- * Portions created by the Initial Developer are Copyright (C) 2010
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *  Bob Moss <bmoss@mozilla.com>
- * 
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-package com.mozilla.SUTAgentAndroid.service;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
-import java.io.BufferedReader;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.FileReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.PrintWriter;
-import java.lang.reflect.Field;
-import java.net.Socket;
-import java.net.SocketException;
-import java.net.UnknownHostException;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.Collections;
-import java.util.Date;
-import java.util.GregorianCalendar;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.TimeZone;
-import java.util.Timer;
-import java.util.zip.Adler32;
-import java.util.zip.CheckedInputStream;
-import java.util.zip.CheckedOutputStream;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
-import java.util.zip.ZipInputStream;
-import java.util.zip.ZipOutputStream;
-
-import org.apache.commons.net.ftp.FTP;
-import org.apache.commons.net.ftp.FTPClient;
-import org.apache.commons.net.ftp.FTPFile;
-import org.apache.commons.net.ftp.FTPReply;
-import org.apache.http.HttpResponse;
-import org.apache.http.HttpStatus;
-import org.apache.http.client.ClientProtocolException;
-import org.apache.http.client.HttpClient;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.impl.client.DefaultHttpClient;
-
-import com.mozilla.SUTAgentAndroid.SUTAgentAndroid;
-
-import android.app.Activity;
-import android.app.ActivityManager;
-import android.app.AlarmManager;
-import android.content.ActivityNotFoundException;
-import android.content.Context;
-import android.content.ContextWrapper;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.res.Configuration;
-import android.net.Uri;
-import android.os.Build;
-import android.os.Debug;
-import android.os.Environment;
-import android.os.StatFs;
-import android.os.SystemClock;
-import android.provider.Settings;
-import android.util.DisplayMetrics;
-import android.util.Log;
-import android.view.WindowManager;
-
-public class DoCommand {
-	
-	String lineSep = System.getProperty("line.separator");
-	Process	pProc;
-	OutputStream sutIn;
-	InputStream	sutErr;
-	InputStream	sutOut;
-	AlertLooperThread alrt = null;
-	ContextWrapper	contextWrapper = null;
-	
-	String	currentDir = "/";
-	String	sErrorPrefix = "##AGENT-WARNING## ";
-	
-	private final String prgVersion = "SUTAgentAndroid Version 0.87";
-	
-	public enum Command
-		{
-		RUN ("run"),
-		EXEC ("exec"),
-		ENVRUN ("envrun"),
-		KILL ("kill"),
-		PS ("ps"),
-		DEVINFO ("info"),
-		OS ("os"),
-		ID ("id"),
-		UPTIME ("uptime"),
-		SETTIME ("settime"),
-		SYSTIME ("systime"),
-		SCREEN ("screen"),
-		MEMORY ("memory"),
-		POWER ("power"),
-		PROCESS ("process"),
-		GETAPPROOT ("getapproot"),
-		TESTROOT ("testroot"),
-		ALRT ("alrt"),
-		DISK ("disk"),
-		CP ("cp"),
-		TIME ("time"),
-		HASH ("hash"),
-		CD ("cd"),
-		CAT ("cat"),
-		CWD ("cwd"),
-		MV ("mv"),
-		PUSH ("push"),
-		RM ("rm"),
-		PRUNE ("rmdr"),
-		MKDR ("mkdr"),
-		DIRWRITABLE ("dirw"),
-		DEAD ("dead"),
-		MEMS ("mems"),
-		LS ("ls"),
-		TMPD ("tmpd"),
-		PING ("ping"),
-		REBT ("rebt"),
-		UNZP ("unzp"),
-		ZIP ("zip"),
-		CLOK ("clok"),
-		STAT ("stat"),
-		QUIT ("quit"),
-		EXIT ("exit"),
-		HELP ("help"),
-		FTPG ("ftpg"),
-		FTPP ("ftpp"),
-		INST ("inst"),
-		UPDT ("updt"),
-		UNINST ("uninst"),
-		TEST ("test"),
-		VER ("ver"),
-		TZGET ("tzget"),
-		TZSET ("tzset"),
-		UNKNOWN ("unknown");
-		
-		private final String theCmd;
-		
-		Command(String theCmd) { this.theCmd = theCmd; }
-
-		public String theCmd() {return theCmd;}
-		
-		public static Command getCmd(String sCmd)
-			{
-			Command retCmd = UNKNOWN;
-			for (Command cmd : Command.values())
-				{
-				if (cmd.theCmd().equalsIgnoreCase(sCmd))
-					{
-					retCmd = cmd;
-					break;
-					}
-				}
-			return (retCmd);
-			}
-		}
-	
-	public DoCommand(ContextWrapper service)
-		{
-		this.contextWrapper = service;
-		}
-	
-	public String processCommand(String theCmdLine, PrintWriter out, BufferedInputStream in, OutputStream cmdOut)
-		{
-		String 	strReturn = "";
-		Command	cCmd = null;
-		Command cSubCmd = null;
-		
-		String [] Argv = parseCmdLine2(theCmdLine);
-		
-		int Argc = Argv.length;
-		
-		cCmd = Command.getCmd(Argv[0]);
-		
-		switch(cCmd)
-			{
-			case VER:
-				strReturn = prgVersion;
-				break;
-				
-			case CLOK:
-				strReturn = GetClok();
-				break;
-				
-			case TZGET:
-				strReturn = GetTimeZone();
-				break;
-				
-			case TZSET:
-				if (Argc == 2)
-					strReturn = SetTimeZone(Argv[1]);
-				else
-					strReturn = sErrorPrefix + "Wrong number of arguments for settz command!";
-				break;
-				
-			case UPDT:
-				strReturn = StartUpdateOMatic(Argv[1], Argv[2]);
-				break;
-			
-			case SETTIME:
-				strReturn = SetSystemTime(Argv[1], Argv[2], cmdOut);
-				break;
-			
-			case CWD:
-				try {
-					strReturn = new java.io.File(currentDir).getCanonicalPath();
-					} 
-				catch (IOException e)
-					{
-					e.printStackTrace();
-					}
-				break;
-				
-			case CD:
-				if (Argc == 2)
-					strReturn = changeDir(Argv[1]);
-				else
-					strReturn = sErrorPrefix + "Wrong number of arguments for cd command!";
-				break;
-			
-			case LS:
-				strReturn = PrintDir(((Argc > 1) ? Argv[1] : currentDir));
-				break;
-				
-			case GETAPPROOT:
-				if (Argc == 2)
-					strReturn = GetAppRoot(Argv[1]);
-				else
-					strReturn = sErrorPrefix + "Wrong number of arguments for getapproot command!";
-				break;
-				
-			case TESTROOT:
-				strReturn = GetTestRoot();
-				break;
-				
-			case DEAD:
-				if (Argc == 2)
-					strReturn = (IsProcessDead(Argv[1]) ? (Argv[1] + " is hung or unresponsive") : (Argv[1] + " is ok"));
-				else
-					strReturn = sErrorPrefix + "Wrong number of arguments for dead command!";
-				break;
-				
-			case PS:
-				strReturn = GetProcessInfo();
-				break;
-				
-			case PUSH:
-				if (Argc == 3)
-					{
-					long lArg = 0;
-				    try
-				    	{
-				        lArg = Long.parseLong(Argv[2].trim());
-				        System.out.println("long l = " + lArg);
-				    	}
-				    catch (NumberFormatException nfe)
-				    	{
-				        System.out.println("NumberFormatException: " + nfe.getMessage());
-				    	}
-					
-					strReturn = Push(Argv[1], in, lArg);
-					}
-				else
-					strReturn = sErrorPrefix + "Wrong number of arguments for push command!";
-				break;
-				
-			case INST:
-				if (Argc >= 2)
-					strReturn = InstallApp(Argv[1], cmdOut);
-				else
-					strReturn = sErrorPrefix + "Wrong number of arguments for inst command!";
-				break;
-				
-			case UNINST:
-				if (Argc >= 2)
-					strReturn = UnInstallApp(Argv[1], cmdOut);
-				else
-					strReturn = sErrorPrefix + "Wrong number of arguments for inst command!";
-				break;
-				
-			case ALRT:
-				if (Argc == 2)
-					{
-					if (Argv[1].contentEquals("on"))
-						{
-						StartAlert();
-						}
-					else
-						{
-						StopAlert();
-						}
-					}
-				else
-					{
-					strReturn = sErrorPrefix + "Wrong number of arguments for alrt command!";
-					}
-				break;
-				
-			case REBT:
-				RunReboot(cmdOut);
-				break;
-				
-			case TMPD:
-				strReturn = GetTmpDir();
-				break;
-				
-			case DEVINFO:
-				if (Argc == 1)
-					{
-					strReturn += SUTAgentAndroid.sUniqueID;
-					strReturn += "\n";
-					strReturn += GetOSInfo();
-					strReturn += "\n";
-					strReturn += GetSystemTime();
-					strReturn += "\n";
-					strReturn += GetUptime();
-					strReturn += "\n";
-					strReturn += GetScreenInfo();
-					strReturn += "\n";
-					strReturn += GetMemoryInfo();
-					strReturn += "\n";
-					strReturn += GetPowerInfo();
-					strReturn += "\n";
-					strReturn += GetProcessInfo();
-					}
-				else
-					{
-					cSubCmd = Command.getCmd(Argv[1]);
-					switch(cSubCmd)
-						{
-						case ID:
-							strReturn = SUTAgentAndroid.sUniqueID;
-							break;
-							
-						case SCREEN:
-							strReturn = GetScreenInfo();
-							break;
-							
-						case PROCESS:
-							strReturn = GetProcessInfo();
-							break;
-							
-						case OS:
-							strReturn = GetOSInfo();
-							break;
-							
-						case SYSTIME:
-							strReturn = GetSystemTime();
-							break;
-							
-						case UPTIME:
-							strReturn = GetUptime();
-							break;
-							
-						case MEMORY:
-							strReturn = GetMemoryInfo();
-							break;
-							
-						case POWER:
-							strReturn += GetPowerInfo();
-							break;
-							
-						default:
-							break;
-						}
-					}
-				break;
-				
-			case STAT:
-				if (Argc == 2)
-					strReturn = StatProcess(Argv[1]);
-				else
-					strReturn = sErrorPrefix + "Wrong number of arguments for ping command!";
-				break;
-				
-			case PING:
-				if (Argc == 2)
-					strReturn = SendPing(Argv[1], cmdOut);
-				else
-					strReturn = sErrorPrefix + "Wrong number of arguments for ping command!";
-				break;
-				
-			case HASH:
-				if (Argc == 2)
-					strReturn = HashFile(Argv[1]);
-				else
-					strReturn = sErrorPrefix + "Wrong number of arguments for hash command!";
-				break;
-				
-			case PRUNE:
-				if (Argc == 2)
-					strReturn = PruneDir(Argv[1]);
-				else
-					strReturn = sErrorPrefix + "Wrong number of arguments for prune command!";
-				break;
-				
-			case FTPG:
-				if (Argc == 4)
-					strReturn = FTPGetFile(Argv[1], Argv[2], Argv[3], cmdOut);
-				else
-					strReturn = sErrorPrefix + "Wrong number of arguments for ftpg command!";
-				break;
-				
-			case CAT:
-				if (Argc == 2)
-					strReturn = Cat(Argv[1], cmdOut);
-				else
-					strReturn = sErrorPrefix + "Wrong number of arguments for cat command!";
-				break;
-				
-			case DIRWRITABLE:
-				if (Argc == 2)
-					strReturn = IsDirWritable(Argv[1]);
-				else
-					strReturn = sErrorPrefix + "Wrong number of arguments for dirwritable command!";
-				break;
-				
-			case TIME:
-				if (Argc == 2)
-					strReturn = PrintFileTimestamp(Argv[1]);
-				else
-					strReturn = sErrorPrefix + "Wrong number of arguments for time command!";
-				break;
-				
-			case MKDR:
-				if (Argc == 2)
-					strReturn = MakeDir(Argv[1]);
-				else
-					strReturn = sErrorPrefix + "Wrong number of arguments for mkdr command!";
-				break;
-				
-			case RM:
-				if (Argc == 2)
-					strReturn = RemoveFile(Argv[1]);
-				else
-					strReturn = sErrorPrefix + "Wrong number of arguments for mkdr command!";
-				break;
-				
-			case MV:
-				if (Argc == 3)
-					strReturn = Move(Argv[1], Argv[2]);
-				else
-					strReturn = sErrorPrefix + "Wrong number of arguments for mv command!";
-				break;
-				
-			case CP:
-				if (Argc == 3)
-					strReturn = CopyFile(Argv[1], Argv[2]);
-				else
-					strReturn = sErrorPrefix + "Wrong number of arguments for cp command!";
-				break;
-				
-			case QUIT:
-			case EXIT:
-				strReturn = Argv[0];
-				break;
-				
-			case TEST:
-//				boolean bRet = false;
-/*				
-				Configuration userConfig = new Configuration();
-				Settings.System.getConfiguration( contextWrapper.getContentResolver(), userConfig );
-				Calendar cal = Calendar.getInstance( userConfig.locale);
-				TimeZone ctz = cal.getTimeZone();
-				String sctzLongName = ctz.getDisplayName();
-				String pstzName = TimeZone.getDefault().getDisplayName();
-*/
-				String sTimeZoneName = GetTimeZone();
-				
-				TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
-				TimeZone tz2 = TimeZone.getTimeZone("GMT-08:00");
-				int	nOffset = (-8 * 3600000);
-				String [] zoneNames = TimeZone.getAvailableIDs(nOffset);
-				int nNumMatches = zoneNames.length;
-				TimeZone.setDefault(tz);
-				
-				String sOldTZ = System.setProperty("persist.sys.timezone", "America/Los_Angeles");
-				
-/*				
-				byte[] buffer = new byte [4096];
-				int	nRead = 0;
-				long lTotalRead = 0;
-
-				Context ctx = SUTAgentAndroid.me.getApplicationContext();
-
-				FTPClient ftp = new FTPClient();
-				try 
-					{
-					String strRet = "";
-					int	reply = 0;
-					FileOutputStream outStream = null;
-					
-					ftp.connect("ftp.mozilla.org");
-					strRet = ftp.getReplyString();
-					reply = ftp.getReplyCode();
-					
-				    if(!FTPReply.isPositiveCompletion(reply))
-				    	{
-				        ftp.disconnect();
-				        System.err.println("FTP server refused connection.");
-				        System.exit(1);
-				        }
-				    // transfer files
-				    
-				    ftp.login("anonymous", "b@t.com");
-					strRet = ftp.getReplyString();
-					reply = ftp.getReplyCode();
-					
-				    if(!FTPReply.isPositiveCompletion(reply))
-				    	{
-				        ftp.disconnect();
-				        System.err.println("FTP server refused connection.");
-				        System.exit(1);
-				        }
-				    
-				    ftp.enterLocalPassiveMode();
-				    
-				    if (ftp.setFileType(FTP.BINARY_FILE_TYPE))
-				    	{
-				    	File root = Environment.getExternalStorageDirectory();
-				    	if (root.canWrite())
-				    		{
-				    		File outFile = new File(root, "firefox-3.6b4.cab");
-				    		outStream = new FileOutputStream(outFile);
-				    		}
-				    	else
-				    		outStream = ctx.openFileOutput("firefox-3.6b4.cab", Context.MODE_WORLD_READABLE | Context.MODE_WORLD_WRITEABLE);
-//				    	outStream = new FileOutputStream("/sdcard/firefox-3.6b4.cab");
-				    	InputStream ftpIn = ftp.retrieveFileStream("pub/mozilla.org/firefox/releases/3.6b4/wince-arm/en-US/firefox-3.6b4.cab");
-						while ((nRead = ftpIn.read(buffer)) != -1)
-							{
-							lTotalRead += nRead;
-							outStream.write(buffer, 0, nRead);
-							strRet = "\r" + lTotalRead + " bytes received";
-							cmdOut.write(strRet.getBytes());
-							cmdOut.flush();
-							}
-						
-						ftpIn.close();
-						boolean bRet = ftp.completePendingCommand();
-						outStream.flush();
-
-				    	/*				    	
-				    	if (ftp.retrieveFile("pub/mozilla.org/firefox/releases/3.6b4/wince-arm/en-US/firefox-3.6b4.cab", outStream))
-				    		{
-				    		outStream.flush();
-				    		}
-				    	 * /				    		
-			    		outStream.close();
-						strRet = ftp.getReplyString();
-						reply = ftp.getReplyCode();
-				    	}
-					strRet = ftp.getReplyString();
-					reply = ftp.getReplyCode();
-				    ftp.logout();
-				    
-				    strReturn = "\r\n" + strRet; 
-					}
-				catch (SocketException e)
-					{
-					// TODO Auto-generated catch block
-					strReturn = e.getMessage();
-					e.printStackTrace();
-					}
-				catch (IOException e)
-					{
-					// TODO Auto-generated catch block
-					strReturn = e.getMessage();
-					e.printStackTrace();
-					}
-*/				
-//				strReturn = InstallApplication();
-//				strReturn = InstallApp(Argv[1], cmdOut);
-				
-//				strReturn = UninstallApplication();
-//				String sPingCheck = SendPing("www.mozilla.org",null);
-//				if (sPingCheck.contains("3 received"))
-//					strReturn = sPingCheck;
-//				RunReboot(cmdOut);
-/*
-				try 
-					{
-					FileOutputStream outFile = ctx.openFileOutput("test.txt", Context.MODE_WORLD_READABLE | Context.MODE_WORLD_WRITEABLE);
-					OutputStreamWriter outS = new OutputStreamWriter(outFile);
-					outS.write("Hello world 1" + lineSep);
-					outS.write("Hello world 2" + lineSep);
-					outS.write("Hello world 3" + lineSep);
-					outS.write("Hello world 4" + lineSep);
-					outS.flush();
-					outS.close();
-					
-					String [] files = ctx.fileList();
-					File aFile   = ctx.getFilesDir();
-					String aPath = aFile.getCanonicalPath();
-					String hold = aFile.getName();
-					
-					strReturn = PrintDir(aPath);
-					strReturn += "\r\n";
-					
-					String src = aPath + "/test.txt";
-					String dst = aPath + "/test2.txt";
-					strReturn += CopyFile(src, dst);
-					strReturn += "\r\n";
-					
-					strReturn += PrintDir(aPath);
-					strReturn += "\r\n";
-					
-					dst = aPath + "/test3.txt";
-					strReturn += Move(src, dst);
-					strReturn += "\r\n";
-					
-					strReturn += PrintDir(aPath);
-					strReturn += "\r\n";
-
-					src = aPath + "/test2.txt";
-					strReturn += RemoveFile(src);
-					strReturn += "\r\n";
-					strReturn += RemoveFile(dst);
-					strReturn += "\r\n";
-					strReturn += PrintDir(aPath);
-					}
-				catch (FileNotFoundException e)
-					{
-					// TODO Auto-generated catch block
-					e.printStackTrace();
-					} 
-				catch (IOException e) 
-					{
-					// TODO Auto-generated catch block
-					e.printStackTrace();
-					}
-*/
-				break;
-				
-			case ENVRUN:
-				if (Argc >= 2)
-					{
-					String [] theArgs = new String [Argc - 1];
-			
-					for (int lcv = 1; lcv < Argc; lcv++)
-						{
-						theArgs[lcv - 1] = Argv[lcv];
-						}
-			
-					strReturn = StartPrg2(theArgs, cmdOut);
-					}
-				else
-					{
-					strReturn = sErrorPrefix + "Wrong number of arguments for " + Argv[0] + " command!";
-					}
-				break;
-				
-			case EXEC:
-			case RUN:
-				if (Argc >= 2)
-					{
-					String [] theArgs = new String [Argc - 1];
-				
-					for (int lcv = 1; lcv < Argc; lcv++)
-						{
-						theArgs[lcv - 1] = Argv[lcv];
-						}
-				
-					if (Argv[1].contains("/") || Argv[1].contains("\\") || !Argv[1].contains("."))
-						strReturn = StartPrg(theArgs, cmdOut);
-					else
-						strReturn = StartJavaPrg(theArgs);
-					}
-				else
-					{
-					strReturn = sErrorPrefix + "Wrong number of arguments for " + Argv[0] + " command!";
-					}
-				break;
-
-			case KILL:
-				if (Argc == 2)
-//					strReturn = NewKillProc(Argv[1], Argv[2], cmdOut);
-//					strReturn = NewKillProc(Argv[1], cmdOut);
-					strReturn = KillProcess(Argv[1], cmdOut);
-				else
-					strReturn = sErrorPrefix + "Wrong number of arguments for kill command!";
-				break;
-				
-			case DISK:
-				strReturn = GetDiskInfo((Argc == 2 ? Argv[1] : "/"));
-				break;
-				
-			case UNZP:
-				strReturn = Unzip(Argv[1], (Argc == 3 ? Argv[2] : ""));
-				break;
-				
-			case ZIP:
-				strReturn = Zip(Argv[1], (Argc == 3 ? Argv[2] : ""));
-				break;
-				
-			case HELP:
-				strReturn = PrintUsage();
-				break;
-				
-			default:
-				strReturn = sErrorPrefix + "[" + Argv[0] + "] command";
-				if (Argc > 1)
-					{
-					strReturn += " with arg(s) =";
-					for (int lcv = 1; lcv < Argc; lcv++)
-						{
-						strReturn += " [" + Argv[lcv] + "]";
-						}
-					}
-				strReturn += " is currently not implemented.";
-				break;
-			}
-		
-		return(strReturn);
-		}
-/*
-	class AlertLooperThread extends Thread
-		{
-	    public Handler mHandler;
-	    private Looper looper = null;
-	    private DoAlert da	= null;
-	    
-	    public void term()
-	    	{
-	    	if (da != null)
-	    		da.term();
-	    	}
-	    
-	    public void quit()
-	    	{
-	    	if (looper != null)
-	    		looper.quit();
-	    	}
-	    
-	    public void run()
-	    	{
-	        Looper.prepare();
-	        
-	        looper = Looper.myLooper();
-	          
-	        mHandler = new Handler()
-	        	{
-	            public void handleMessage(Message msg)
-	            	{
-	                  // process incoming messages here
-	            	}
-	        	};
-	          
-			alertTimer = new Timer();
-			da = new DoAlert();
-    		alertTimer.scheduleAtFixedRate(da, 0, 5000);
-    		Looper.loop();
-	    	}
-		}
-	
-	class DoAlert extends TimerTask
-		{
-		int	lcv = 0;
-		Toast toast = null;
-		Ringtone rt = null;
-		
-		DoAlert()
-			{
-			Context	ctx = SUTAgentAndroid.me.getApplication().getApplicationContext();
-			this.toast = Toast.makeText(ctx, "Help me!", Toast.LENGTH_LONG);
-			rt = RingtoneManager.getRingtone(ctx, RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM));
-			}
-		
-		public void term()
-			{
-			if (rt != null)
-				{
-				if (rt.isPlaying())
-					rt.stop();
-				}
-			
-			if (toast != null)
-				toast.cancel();
-			}
-	
-		public void run ()
-			{
-			String sText =(((lcv++ % 2) == 0)  ? "Help me!" : "I've fallen down!" );
-			toast.setText(sText);
-			toast.show();
-			if (rt != null)
-				rt.play();
-			}
-		}
-*/
-	public void StartAlert()
-		{
-		// start the alert message
-		alrt = new AlertLooperThread(this.contextWrapper);
-		alrt.start();
-		}
-
-	public void StopAlert()
-		{
-		if (alrt == null)
-			return;
-		
-		Timer alertTimer = alrt.getAlertTimer();
-		// stop the alert message
-		if (alertTimer != null)
-			{
-			// Kill the timer
-			alertTimer.cancel();
-			alertTimer.purge();
-			alertTimer = null;
-			// Clear any messages either queued or on screen
-			alrt.term();
-			// Give the messages a chance to be processed
-			try {
-				Thread.sleep(1000);
-				}
-			catch (InterruptedException e)
-				{
-				e.printStackTrace();
-				}
-			// Kill the thread
-			alrt.quit();
-			alrt = null;
-			System.gc();
-			}
-		}
-
-	public String [] parseCmdLine2(String theCmdLine)
-		{
-		String	cmdString;
-		String	workingString;
-		String	workingString2;
-		String	workingString3;
-		List<String> lst = new ArrayList<String>();
-		int nLength = 0;
-		int nFirstSpace = -1;
-		
-		// Null cmd line
-		if (theCmdLine == null)
-			{
-			String [] theArgs = new String [1];
-			theArgs[0] = new String("");
-			return(theArgs);
-			}
-		else
-			{
-			nLength = theCmdLine.length();
-			nFirstSpace = theCmdLine.indexOf(' ');
-			}
-		
-		if (nFirstSpace == -1)
-			{
-			String [] theArgs = new String [1];
-			theArgs[0] = new String(theCmdLine);
-			return(theArgs);
-			}
-		
-		// Get the command
-		cmdString = new String(theCmdLine.substring(0, nFirstSpace)); 
-		lst.add(cmdString);
-		
-		// Jump past the command and trim
-		workingString = (theCmdLine.substring(nFirstSpace + 1, nLength)).trim();
-		
-		while ((nLength = workingString.length()) > 0)
-			{
-			int nEnd = 0;
-			int	nStart = 0;
-			
-			// if we have a quote
-			if (workingString.startsWith("\""))
-				{
-				// point to the first non quote char
-				nStart = 1;
-				// find the matching quote
-				nEnd = workingString.indexOf('"', nStart);
-				
-				char prevChar;
-				
-				while(nEnd != -1)
-					{
-					// check to see if the quotation mark has been escaped
-					prevChar = workingString.charAt(nEnd - 1);
-					if (prevChar == '\\')
-						{
-						// if escaped, point past this quotation mark and find the next
-						nEnd++;
-						if (nEnd < nLength)
-							nEnd = workingString.indexOf('"', nEnd);
-						else
-							nEnd = -1;
-						}
-					else
-						break;
-					}
-				
-				// there isn't one
-				if (nEnd == -1)
-					{
-					// point at the quote
-					nStart = 0;
-					// so find the next space
-					nEnd = workingString.indexOf(' ', nStart);
-					// there isn't one of those either
-					if (nEnd == -1)
-						nEnd = nLength;	// Just grab the rest of the cmdline
-					}
-				}
-			else // no quote so find the next space
-				{
-				nEnd = workingString.indexOf(' ', nStart);
-				// there isn't one of those
-				if (nEnd == -1)
-					nEnd = nLength;	// Just grab the rest of the cmdline
-				}
-			
-			// get the substring
-			workingString2 = workingString.substring(nStart, nEnd);
-
-			// if we have escaped quotes
-			if (workingString2.contains("\\\""))
-				{
-				do
-					{
-					// replace escaped quote with embedded quote
-					workingString3 = workingString2.replace("\\\"", "\"");
-					workingString2 = workingString3;
-					}
-				while(workingString2.contains("\\\""));
-				}
-
-			// add it to the list
-			lst.add(new String(workingString2));
-			
-			// if we are dealing with a quote
-			if (nStart > 0)
-				nEnd++; //  point past the end one
-			
-			// jump past the substring and trim it
-			workingString = (workingString.substring(nEnd)).trim();
-			}
-		
-		// ok we're done package up the results
-		int nItems = lst.size();
-		
-		String [] theArgs = new String [nItems];
-		
-		for (int lcv = 0; lcv < nItems; lcv++)
-			{
-			theArgs[lcv] = lst.get(lcv);
-			}
-	
-		return(theArgs);
-		}
-	
-	public String [] parseCmdLine(String theCmdLine) {
-		String	cmdString;
-		String	workingString;
-		String	workingString2;
-		List<String> lst = new ArrayList<String>();
-		int nLength = 0;
-		int nFirstSpace = -1;
-		
-		// Null cmd line
-		if (theCmdLine == null)
-			{
-			String [] theArgs = new String [1];
-			theArgs[0] = new String("");
-			return(theArgs);
-			}
-		else
-			{
-			nLength = theCmdLine.length();
-			nFirstSpace = theCmdLine.indexOf(' ');
-			}
-		
-		if (nFirstSpace == -1)
-			{
-			String [] theArgs = new String [1];
-			theArgs[0] = new String(theCmdLine);
-			return(theArgs);
-			}
-		
-		// Get the command
-		cmdString = new String(theCmdLine.substring(0, nFirstSpace)); 
-		lst.add(cmdString);
-		
-		// Jump past the command and trim
-		workingString = (theCmdLine.substring(nFirstSpace + 1, nLength)).trim();
-		
-		while ((nLength = workingString.length()) > 0)
-			{
-			int nEnd = 0;
-			int	nStart = 0;
-			
-			// if we have a quote
-			if (workingString.startsWith("\""))
-				{
-				// point to the first non quote char
-				nStart = 1;
-				// find the matching quote
-				nEnd = workingString.indexOf('"', nStart);
-				// there isn't one
-				if (nEnd == -1)
-					{
-					// point at the quote
-					nStart = 0;
-					// so find the next space
-					nEnd = workingString.indexOf(' ', nStart);
-					// there isn't one of those either
-					if (nEnd == -1)
-						nEnd = nLength;	// Just grab the rest of the cmdline
-					}
-				else
-					{
-					nStart = 0;
-					nEnd++;
-					}
-				}
-			else // no quote so find the next space
-				{
-				nEnd = workingString.indexOf(' ', nStart);
-				// there isn't one of those
-				if (nEnd == -1)
-					nEnd = nLength;	// Just grab the rest of the cmdline
-				}
-			
-			// get the substring
-			workingString2 = workingString.substring(nStart, nEnd);
-			
-			// add it to the list
-			lst.add(new String(workingString2));
-			
-			// if we are dealing with a quote
-//			if (nStart > 0)
-//				nEnd++; //  point past the end one
-			
-			// jump past the substring and trim it
-			workingString = (workingString.substring(nEnd)).trim();
-			}
-		
-		int nItems = lst.size();
-		
-		String [] theArgs = new String [nItems];
-		
-		for (int lcv = 0; lcv < nItems; lcv++)
-			{
-			theArgs[lcv] = lst.get(lcv);
-			}
-	
-		return(theArgs);
-		}
-	
-	public String fixFileName(String fileName)
-		{
-		String	sRet = "";
-		String	sTmpFileName = "";
-		
-		sRet = fileName.replace('\\', '/');
-		
-		if (sRet.startsWith("/"))
-			sTmpFileName = sRet;
-		else
-			sTmpFileName = currentDir + "/" + sRet;
-		
-		sRet = sTmpFileName.replace('\\', '/');
-		sTmpFileName = sRet;
-		sRet = sTmpFileName.replace("//", "/");
-		
-		return(sRet);
-		}
-	
-	public String AddFilesToZip(ZipOutputStream out, String baseDir, String relDir)
-	{
-		final int 			BUFFER 	= 2048;
-		String				sRet	= "";
-		String 				curDir 	= "";
-		String				relFN	= "";
-		BufferedInputStream origin = null;
-	    byte 				data[] = new byte[BUFFER];
-	    
-	    if (relDir.length() > 0)
-	    	curDir = baseDir + "/" + relDir;
-	    else
-	    	curDir = baseDir;
-	    
-		File f = new File(curDir);
-		
-		if (f.isFile())
-			{
-		    try {
-		    	relFN = ((relDir.length() > 0) ? relDir + "/" + f.getName() : f.getName());
-		    	System.out.println("Adding: "+relFN);
-		    	sRet += "Adding: "+	relFN + lineSep;
-		    	FileInputStream fi = new FileInputStream(curDir);
-		    	origin = new BufferedInputStream(fi, BUFFER);
-		    	ZipEntry entry = new ZipEntry(relFN);
-		    	out.putNextEntry(entry);
-		    	int count;
-		    	while((count = origin.read(data, 0, BUFFER)) != -1)
-        			{
-		    		out.write(data, 0, count);
-        			}
-		    	origin.close();
-				}
-		    catch(Exception e)
-		    	{
-			    e.printStackTrace();
-		    	}
-		    
-		    return(sRet);
-			}
-		
-		String	files[] = f.list();
-		
-		if (files != null)
-			{
-			try {
-				for(int i = 0; i < files.length; i++)
-					{
-					f = new File(curDir + "/" + files[i]);
-					if (f.isDirectory())
-						{
-						if (relDir.length() > 0)
-							sRet += AddFilesToZip(out, baseDir, relDir + "/" + files[i]);
-						else
-							sRet += AddFilesToZip(out, baseDir, files[i]);
-						}
-					else
-						{
-						relFN = ((relDir.length() > 0) ? relDir + "/" + files[i] : files[i]);
-						System.out.println("Adding: "+relFN);
-						sRet += "Adding: "+	relFN + lineSep;
-						FileInputStream fi = new FileInputStream(curDir + "/" + files[i]);
-						origin = new BufferedInputStream(fi, BUFFER);
-						ZipEntry entry = new ZipEntry(relFN);
-						out.putNextEntry(entry);
-						int count;
-						while((count = origin.read(data, 0, BUFFER)) != -1)
-		        			{
-							out.write(data, 0, count);
-		        			}
-						origin.close();
-						}
-					}
-	    		}
-			catch(Exception e)
-	    		{
-				e.printStackTrace();
-	    		}
-			}
-
-		return(sRet);
-	}
-	
-	public String Zip(String zipFileName, String srcName)
-		{
-		String	fixedZipFileName = fixFileName(zipFileName);
-		String	fixedSrcName = fixFileName(srcName);
-		String sRet = "";
-		
-		try {
-		    FileOutputStream dest = new FileOutputStream(fixedZipFileName);
-		    CheckedOutputStream checksum = new CheckedOutputStream(dest, new Adler32());
-		    ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(checksum));
-		    out.setMethod(ZipOutputStream.DEFLATED);
-		    
-		    sRet += AddFilesToZip(out, fixedSrcName, "");
-		    
-		    out.close();
-		    System.out.println("checksum:		           "+checksum.getChecksum().getValue());
-	        sRet += "checksum:		           "+checksum.getChecksum().getValue();
-		    }
-		catch(Exception e)
-			{
-		    e.printStackTrace();
-		    }
-		
-		return(sRet);
-	}
-
-	public String Unzip(String zipFileName, String dstDirectory)
-		{
-		String 	sRet = "";
-		String	fixedZipFileName = fixFileName(zipFileName);
-		String	fixedDstDirectory = fixFileName(dstDirectory);
-		String	dstFileName = "";
-		int		nNumExtracted = 0;
-		boolean bRet = false;
-		
-		try {
-			final int BUFFER = 2048;
-			BufferedOutputStream dest = null;
-			ZipFile zipFile = new ZipFile(fixedZipFileName);
-			int nNumEntries = zipFile.size();
-			zipFile.close();
-			
-			FileInputStream fis = new FileInputStream(fixedZipFileName);
-			CheckedInputStream checksum = new CheckedInputStream(fis, new Adler32());
-			ZipInputStream zis = new ZipInputStream(new BufferedInputStream(checksum));
-			ZipEntry entry;
-
-			byte [] data = new byte[BUFFER];
-			
-			while((entry = zis.getNextEntry()) != null)
-        		{
-				System.out.println("Extracting: " + entry);
-				int count;
-				if (fixedDstDirectory.length() > 0)
-					dstFileName = fixedDstDirectory + entry.getName();
-				else
-					dstFileName = entry.getName();
-				
-				String tmpDir = dstFileName.substring(0, dstFileName.lastIndexOf('/'));
-				File tmpFile = new File(tmpDir);
-				if (!tmpFile.exists())
-					{
-					bRet = tmpFile.mkdirs();
-					}
-				else
-					bRet = true;
-				
-				if (bRet)
-					{
-					// if we aren't just creating a directory
-					if (dstFileName.lastIndexOf('/') != (dstFileName.length() - 1))
-						{
-						// write out the file
-						FileOutputStream fos = new FileOutputStream(dstFileName);
-						dest = new BufferedOutputStream(fos, BUFFER);
-						while ((count = zis.read(data, 0, BUFFER)) != -1)
-        					{
-							dest.write(data, 0, count);
-        					}
-						dest.flush();
-						dest.close();
-						dest = null;
-						fos.close();
-						fos = null;
-						}
-					nNumExtracted++;
-					}
-				else
-					sRet += " - failed" + lineSep;
-        		}
-			
-			data = null;
-			zis.close();
-			System.out.println("Checksum:          "+checksum.getChecksum().getValue());
-			sRet += "Checksum:          "+checksum.getChecksum().getValue();
-			sRet += lineSep + nNumExtracted + " of " + nNumEntries + " sucessfully extracted";
-			}
-		catch(Exception e)
-			{
-			e.printStackTrace();
-			}
-		
-		return(sRet);
-		}
-	
-	public String StatProcess(String string)
-		{
-		String sRet = "";
-		ActivityManager aMgr = (ActivityManager) contextWrapper.getSystemService(Activity.ACTIVITY_SERVICE);
-		int	[] nPids = new int [1];
-		
-		nPids[0] = Integer.parseInt(string);
-		
-		android.os.Debug.MemoryInfo[] mi = aMgr.getProcessMemoryInfo(nPids);
-		
-		sRet  = "Dalvik Private Dirty pages         " + mi[0].dalvikPrivateDirty     + " kb\n";
-		sRet += "Dalvik Proportional Set Size       " + mi[0].dalvikPss              + " kb\n";
-		sRet += "Dalvik Shared Dirty pages          " + mi[0].dalvikSharedDirty      + " kb\n\n";
-		sRet += "Native Private Dirty pages heap    " + mi[0].nativePrivateDirty     + " kb\n";
-		sRet += "Native Proportional Set Size heap  " + mi[0].nativePss              + " kb\n";
-		sRet += "Native Shared Dirty pages heap     " + mi[0].nativeSharedDirty      + " kb\n\n";
-		sRet += "Other Private Dirty pages          " + mi[0].otherPrivateDirty      + " kb\n";
-		sRet += "Other Proportional Set Size        " + mi[0].otherPss               + " kb\n";
-		sRet += "Other Shared Dirty pages           " + mi[0].otherSharedDirty       + " kb\n\n";
-		sRet += "Total Private Dirty Memory         " + mi[0].getTotalPrivateDirty() + " kb\n";
-		sRet += "Total Proportional Set Size Memory " + mi[0].getTotalPss()          + " kb\n";
-		sRet += "Total Shared Dirty Memory          " + mi[0].getTotalSharedDirty()  + " kb";
-		
-		
-		return(sRet);
-		}
-	
-	public String GetTestRoot()
-		{
-		String	sRet = null;
-		
-		if (Environment.getExternalStorageState().equalsIgnoreCase(Environment.MEDIA_MOUNTED))
-			{
-			sRet = Environment.getExternalStorageDirectory().getAbsolutePath();
-			}
-		else
-			{
-			sRet = GetTmpDir();			
-			}
-		
-		return(sRet);
-		}
-	
-	public String GetAppRoot(String AppName)
-		{
-		String sRet = "";
-		Context ctx = contextWrapper.getApplicationContext();
-		
-		if (ctx != null)
-			{
-			try {
-				Context appCtx = ctx.createPackageContext(AppName, 0);
-				ContextWrapper appCtxW = new ContextWrapper(appCtx);
-				sRet = appCtxW.getPackageResourcePath();
-				appCtxW = null;
-				appCtx = null;
-				ctx = null;
-				System.gc();
-				}
-			catch (NameNotFoundException e)
-				{
-				e.printStackTrace();
-				}
-			}
-		return(sRet);
-		}
-
-	public String changeDir(String newDir)
-		{
-		String	tmpDir	= fixFileName(newDir);
-		String	sRet = sErrorPrefix + "Couldn't change directory to " + tmpDir;
-		
-		File tmpFile = new java.io.File(tmpDir);
-		
-		if (tmpFile.exists())
-			{
-			try {
-				currentDir = tmpFile.getCanonicalPath();
-				sRet = "";
-				}
-			catch (IOException e)
-				{
-				// TODO Auto-generated catch block
-				e.printStackTrace();
-				}
-			}
-		
-		return(sRet);
-		}
-	
-	static final String HEXES = "0123456789abcdef";
-	
-	public static String getHex( byte [] raw )
-		{
-	    if ( raw == null )
-	    	{
-	    	return null;
-	    	}
-	    
-	    final StringBuilder hex = new StringBuilder( 2 * raw.length );
-	    for ( final byte b : raw )
-	    	{
-	    	hex.append(HEXES.charAt((b & 0xF0) >> 4)).append(HEXES.charAt((b & 0x0F)));
-	    	}
-	    return hex.toString();
-		}
-
-	public String HashFile(String fileName)
-		{
-		String			sTmpFileName = fixFileName(fileName);
-		String			sRet 		= sErrorPrefix + "Couldn't calculate hash for file " + sTmpFileName;
-		byte[] 			buffer 		= new byte [4096];
-		int				nRead 		= 0;
-		long 			lTotalRead 	= 0;
-		MessageDigest	digest 		= null;
-		
-		try {
-			digest = java.security.MessageDigest.getInstance("MD5");
-			}
-		catch (NoSuchAlgorithmException e)
-			{
-			e.printStackTrace();
-			}
-		
-		try {
-			FileInputStream srcFile  = new FileInputStream(sTmpFileName);
-			while((nRead = srcFile.read(buffer)) != -1)
-				{
-				digest.update(buffer, 0, nRead);
-				lTotalRead += nRead;
-				}
-			srcFile.close();
-			byte [] hash = digest.digest();
-			
-			sRet = getHex(hash);
-			}
-		catch (FileNotFoundException e)
-			{
-			sRet += " file not found";
-			e.printStackTrace();
-			}
-		catch (IOException e)
-			{
-			sRet += " io exception";
-			e.printStackTrace();
-			} 
-		return(sRet);
-		}
-	
-	public String RemoveFile(String fileName)
-		{
-		String	sTmpFileName = fixFileName(fileName);
-		String	sRet = sErrorPrefix + "Couldn't delete file " + sTmpFileName;
-		
-		File f = new File(sTmpFileName);
-		
-		if (f.delete())
-			sRet = "deleted " + sTmpFileName;
-		
-		return(sRet);
-		}
-	
-	public String PruneDir(String sDir)
-		{
-		String	sRet = "";
-		int nFiles = 0;
-		String sSubDir = null;
-		String	sTmpDir = fixFileName(sDir);
-		
-		File dir = new File(sTmpDir);
-		
-		if (dir.isDirectory())
-			{
-			sRet = "Deleting file(s) from " + sTmpDir;
-			
-			File [] files = dir.listFiles();
-			if (files != null)
-				{
-				if ((nFiles = files.length) > 0)
-					{
-					for (int lcv = 0; lcv < nFiles; lcv++)
-						{
-						if (files[lcv].isDirectory())
-							{
-							sSubDir = files[lcv].getAbsolutePath();
-							sRet += "\n" + PruneDir(sSubDir);
-							}
-						else
-							{
-							if (files[lcv].delete())
-								{
-								sRet += "\n\tDeleted " + files[lcv].getName();
-								}
-							else
-								{
-								sRet += "\n\tUnable to delete " + files[lcv].getName();
-								}
-							}
-						}
-					}
-				else
-					sRet += "\n\t<empty>";
-				}
-			
-			if (dir.delete())
-				{
-				sRet += "\nDeleting directory " + sTmpDir;
-				}
-			else
-				{
-				sRet += "\nUnable to delete directory " + sTmpDir;
-				}
-			}
-		else
-			{
-			sRet += sErrorPrefix + sTmpDir + " is not a directory";
-			}
-		
-		return(sRet);
-		}
-	
-	public String PrintDir(String sDir)
-		{
-		String	sRet = "";
-		int nFiles = 0;
-		String	sTmpDir = fixFileName(sDir);
-		
-		File dir = new File(sTmpDir);
-		
-		if (dir.isDirectory())
-			{
-			File [] files = dir.listFiles();
-		
-			if (files != null)
-				{
-				if ((nFiles = files.length) > 0)
-					{
-					for (int lcv = 0; lcv < nFiles; lcv++)
-						{
-						sRet += files[lcv].getName();
-						if (lcv < (nFiles - 1))
-							sRet += "\n";
-						}
-					}
-				else
-					sRet = "<empty>";
-				}
-			}
-		else
-			{
-			sRet = sErrorPrefix + sTmpDir + " is not a directory";
-			}
-		
-		return(sRet);
-		}
-	
-	public String Move(String srcFileName, String dstFileName)
-		{
-		String	sTmpSrcFileName = fixFileName(srcFileName);
-		String	sTmpDstFileName = fixFileName(dstFileName);
-		String sRet = sErrorPrefix + "Could not move " + sTmpSrcFileName + " to " + sTmpDstFileName;
-		
-		File srcFile = new File(sTmpSrcFileName);
-		File dstFile = new File(sTmpDstFileName);
-		
-		if (srcFile.renameTo(dstFile))
-			sRet = sTmpSrcFileName + " moved to " + sTmpDstFileName;
-		
-		return (sRet);
-		}
-	
-	public String CopyFile(String srcFileName, String dstFileName)
-		{
-		String	sTmpSrcFileName = fixFileName(srcFileName);
-		String	sTmpDstFileName = fixFileName(dstFileName);
-		String sRet = sErrorPrefix + "Could not copy " + sTmpSrcFileName + " to " + sTmpDstFileName;
-		File destFile = null;
-		byte[] buffer = new byte [4096];
-		int	nRead = 0;
-		long lTotalRead = 0;
-		long lTotalWritten = 0;
-		
-		try 
-			{
-			FileInputStream srcFile  = new FileInputStream(sTmpSrcFileName);
-			FileOutputStream dstFile = new FileOutputStream(sTmpDstFileName);
-			
-			while((nRead = srcFile.read(buffer)) != -1)
-				{
-				lTotalRead += nRead;
-				dstFile.write(buffer, 0, nRead);
-				}
-			dstFile.flush();
-			dstFile.close();
-			
-			destFile = new File(sTmpDstFileName);
-			lTotalWritten = destFile.length();
-
-			if (lTotalWritten == lTotalRead)
-				sRet = sTmpSrcFileName + " copied to " + sTmpDstFileName;
-			else
-				sRet = sErrorPrefix + "Failed to copy " + sTmpSrcFileName + " [length = " + lTotalWritten + "] to " + sTmpDstFileName + " [length = " + lTotalRead + "]";
-			}
-		catch (FileNotFoundException e)
-			{
-			e.printStackTrace();
-			} 
-		catch (IOException e)
-			{
-			e.printStackTrace();
-			}
-
-		return (sRet);
-		}
-	
-	public String IsDirWritable(String sDir)
-		{
-		String sRet = "";
-		String	sTmpDir = fixFileName(sDir);
-		File dir = new File(sTmpDir);
-		
-		if (dir.isDirectory())
-			{
-			sRet = "[" + sDir + "] " + (dir.canWrite() ? "is" : "is not") + " writable";
-			}
-		else
-			{
-			sRet = sErrorPrefix + "[" + sDir + "] is not a directory";
-			}
-		
-		return(sRet);
-		}
-	
-	public String Push(String fileName, BufferedInputStream bufIn, long lSize)
-	{
-		byte []				buffer 			= new byte [8192];
-		int					nRead			= 0;
-		long				lRead			= 0;
-		String				sTmpFileName 	= fixFileName(fileName);
-		String				sRet			= sErrorPrefix + "Push failed!";
-		
-		try {
-			FileOutputStream dstFile = new FileOutputStream(sTmpFileName, false);
-			while((nRead != -1) && (lRead < lSize))
-				{
-				nRead = bufIn.read(buffer);
-				if (nRead != -1)
-					{
-					dstFile.write(buffer, 0, nRead);
-					dstFile.flush();
-					lRead += nRead;
-					}
-				}
-			
-			dstFile.flush();
-			dstFile.close();
-			
-			if (lRead == lSize)
-				{
-				sRet = HashFile(sTmpFileName);
-				}
-			}
-		catch (IOException e)
-			{
-			e.printStackTrace();
-			}
-		
-		buffer = null;
-		
-		return(sRet);
-	}
-	
-	public String FTPGetFile(String sServer, String sSrcFileName, String sDstFileName, OutputStream out)
-		{
-		byte[] buffer = new byte [4096];
-		int	nRead = 0;
-		long lTotalRead = 0;
-		String sRet = sErrorPrefix + "FTP Get failed for " + sSrcFileName;
-		String strRet = "";
-		int	reply = 0;
-		FileOutputStream outStream = null;
-		String	sTmpDstFileName = fixFileName(sDstFileName);
-		
-		FTPClient ftp = new FTPClient();
-		try 
-			{
-			ftp.connect(sServer);
-			reply = ftp.getReplyCode();
-		    if(FTPReply.isPositiveCompletion(reply))
-		    	{
-			    ftp.login("anonymous", "b@t.com");
-				reply = ftp.getReplyCode();
-			    if(FTPReply.isPositiveCompletion(reply))
-			    	{
-				    ftp.enterLocalPassiveMode();
-				    if (ftp.setFileType(FTP.BINARY_FILE_TYPE))
-				    	{
-				    	File dstFile = new File(sTmpDstFileName);
-				    	outStream = new FileOutputStream(dstFile);
-				    	FTPFile [] ftpFiles = ftp.listFiles(sSrcFileName);
-				    	long lFtpSize = ftpFiles[0].getSize();
-				    	if (lFtpSize <= 0)
-				    		lFtpSize = 1;
-				    	
-				    	InputStream ftpIn = ftp.retrieveFileStream(sSrcFileName);
-						while ((nRead = ftpIn.read(buffer)) != -1)
-							{
-							lTotalRead += nRead;
-							outStream.write(buffer, 0, nRead);
-							strRet = "\r" + lTotalRead + " of " + lFtpSize + " bytes received " + ((lTotalRead * 100) / lFtpSize) + "% completed";
-							out.write(strRet.getBytes());
-							out.flush();
-							}
-						ftpIn.close();
-						@SuppressWarnings("unused")
-						boolean bRet = ftp.completePendingCommand();
-						outStream.flush();
-			    		outStream.close();
-						strRet = ftp.getReplyString();
-						reply = ftp.getReplyCode();
-				    	}
-					strRet = ftp.getReplyString();
-					reply = ftp.getReplyCode();
-				    ftp.logout();
-				    ftp.disconnect();
-				    sRet = "\n" + strRet; 
-			    	}
-			    else
-			    	{
-			        ftp.disconnect();
-			        System.err.println("FTP server refused login.");
-			        }
-		    	}
-		    else
-		    	{
-		        ftp.disconnect();
-		        System.err.println("FTP server refused connection.");
-		        }
-			}
-		catch (SocketException e)
-			{
-			sRet = e.getMessage();
-			strRet = ftp.getReplyString();
-			reply = ftp.getReplyCode();
-			sRet += "\n" + strRet;
-			e.printStackTrace();
-			}
-		catch (IOException e)
-			{
-			sRet = e.getMessage();
-			strRet = ftp.getReplyString();
-			reply = ftp.getReplyCode();
-			sRet += "\n" + strRet;
-			e.printStackTrace();
-			}
-		return (sRet);
-	}
-	
-	public String Cat(String fileName, OutputStream out)
-		{
-		String	sTmpFileName = fixFileName(fileName);
-		String	sRet = sErrorPrefix + "Could not read the file " + sTmpFileName;
-		byte[]	buffer = new byte [4096];
-		int		nRead = 0;
-		
-		try {
-			FileInputStream fin = new FileInputStream(sTmpFileName);
-			while ((nRead = fin.read(buffer)) != -1)
-				{
-				out.write(buffer,0,nRead);
-				}
-			out.flush();
-			sRet = "";
-			}
-		catch (FileNotFoundException e)
-			{
-			sRet = e.toString();
-			} 
-		catch (IOException e) 
-			{
-			sRet = e.toString();
-			}
-		return (sRet);
-		}
-	
-	public String MakeDir(String sDir)
-		{
-		String	sTmpDir = fixFileName(sDir);
-		String sRet = sErrorPrefix + "Could not create the directory " + sTmpDir;
-		File dir = new File(sTmpDir);
-		
-		if (dir.mkdirs())
-			sRet = sDir + " successfully created";
-		
-		return (sRet);
-		}
-	// move this to SUTAgentAndroid.java
-	public String GetScreenInfo()
-		{
-		String sRet = "";
-		DisplayMetrics metrics = new DisplayMetrics();
-		WindowManager wMgr = (WindowManager) contextWrapper.getSystemService(Context.WINDOW_SERVICE);
-		wMgr.getDefaultDisplay().getMetrics(metrics);
-		sRet = "X:" + metrics.widthPixels + " Y:" + metrics.heightPixels;
-		return (sRet);
-		}
-	// move this to SUTAgentAndroid.java
-	public int [] GetScreenXY()
-		{
-			int [] nRetXY = new int [2];
-			DisplayMetrics metrics = new DisplayMetrics();
-			WindowManager wMgr = (WindowManager) contextWrapper.getSystemService(Context.WINDOW_SERVICE);
-			wMgr.getDefaultDisplay().getMetrics(metrics);
-			nRetXY[0] = metrics.widthPixels;
-			nRetXY[1] = metrics.heightPixels;
-			return(nRetXY);
-		}
-	
-	public String KillProcess(String sProcName, OutputStream out)
-		{
-		String [] theArgs = new String [3];
-		
-		theArgs[0] = "su";
-		theArgs[1] = "-c";
-		theArgs[2] = "kill";
-
-		String sRet = sErrorPrefix + "Unable to kill " + sProcName + "\n";
-		ActivityManager aMgr = (ActivityManager) contextWrapper.getSystemService(Activity.ACTIVITY_SERVICE);
-		List <ActivityManager.RunningAppProcessInfo> lProcesses = aMgr.getRunningAppProcesses();
-		int lcv = 0;
-		String strProcName = "";
-		int	nPID = 0;
-		
-		for (lcv = 0; lcv < lProcesses.size(); lcv++)
-			{
-			if (lProcesses.get(lcv).processName.contains(sProcName))
-				{
-				strProcName = lProcesses.get(lcv).processName;
-				nPID = lProcesses.get(lcv).pid;
-				sRet = sErrorPrefix + "Failed to kill " + nPID + " " + strProcName + "\n";
-
-				theArgs[2] += " " + nPID;
-				
-				try 
-					{
-					pProc = Runtime.getRuntime().exec(theArgs);
-					RedirOutputThread outThrd = new RedirOutputThread(pProc, out);
-					outThrd.start();
-					outThrd.join(5000);
-					}
-				catch (IOException e) 
-					{
-					sRet = e.getMessage();
-					e.printStackTrace();
-					} 
-				catch (InterruptedException e)
-					{
-					e.printStackTrace();
-					}
-
-				// Give the messages a chance to be processed
-				try {
-					Thread.sleep(2000);
-					}
-				catch (InterruptedException e)
-					{
-					e.printStackTrace();
-					}
-				break;
-				}
-			}
-		
-		if (nPID > 0)
-			{
-			sRet = "Successfully killed " + nPID + " " + strProcName + "\n";
-			lProcesses = aMgr.getRunningAppProcesses();
-			for (lcv = 0; lcv < lProcesses.size(); lcv++)
-				{
-				if (lProcesses.get(lcv).processName.contains(sProcName))
-					{
-					sRet = sErrorPrefix + "Unable to kill " + nPID + " " + strProcName + "\n";
-					break;
-					}
-				}
-			}
-		
-		return (sRet);
-		}
-
-	public boolean IsProcessDead(String sProcName)
-		{
-		boolean bRet = false;
-		ActivityManager aMgr = (ActivityManager) contextWrapper.getSystemService(Activity.ACTIVITY_SERVICE);
-		List <ActivityManager.ProcessErrorStateInfo> lProcesses = aMgr.getProcessesInErrorState();
-		int lcv = 0;
-		
-		if (lProcesses != null)
-			{
-			for (lcv = 0; lcv < lProcesses.size(); lcv++)
-				{
-				if (lProcesses.get(lcv).processName.contentEquals(sProcName) && 
-					lProcesses.get(lcv).condition != ActivityManager.ProcessErrorStateInfo.NO_ERROR)
-					{
-					bRet = true;
-					break;
-					}
-				}
-			}
-	
-		return (bRet);
-		}
-
-	public String GetProcessInfo()
-		{
-		String sRet = "";
-		ActivityManager aMgr = (ActivityManager) contextWrapper.getSystemService(Activity.ACTIVITY_SERVICE);
-		List <ActivityManager.RunningAppProcessInfo> lProcesses = aMgr.getRunningAppProcesses();
-		int	nProcs = lProcesses.size();
-		int lcv = 0;
-		String strProcName = "";
-		int	nPID = 0;
-		int nUser = 0;
-		
-		for (lcv = 0; lcv < nProcs; lcv++)
-			{
-			strProcName = lProcesses.get(lcv).processName;
-			nPID = lProcesses.get(lcv).pid;
-			nUser = lProcesses.get(lcv).uid;
-			sRet += nUser + "\t" + nPID + "\t" + strProcName;
-			if (lcv < (nProcs - 1))
-				sRet += "\n";
-			}
-			
-		return (sRet);
-		}
-	
-	public String GetOSInfo()
-		{
-		String sRet = "";
-		
-		sRet = Build.DISPLAY;
-		
-		return (sRet);
-		}
-	
-	public String GetPowerInfo()
-		{
-		String sRet = "";
-	
-		sRet = "Power status:\n  AC power " + SUTAgentAndroid.sACStatus + "\n";
-		sRet += "  Battery charge " + SUTAgentAndroid.sPowerStatus + "\n";
-		sRet += "  Remaining charge:      " + SUTAgentAndroid.nChargeLevel + "%\n";
-		sRet += "  Battery Temperature:   " + (((float)(SUTAgentAndroid.nBatteryTemp))/10) + " (c)\n";
-		return (sRet);
-		}
-
-	public String GetDiskInfo(String sPath)
-		{
-		String sRet = "";
-		StatFs statFS = new StatFs(sPath);
-		
-		int nBlockCount = statFS.getBlockCount();
-		int nBlockSize = statFS.getBlockSize();
-		int nBlocksAvail = statFS.getAvailableBlocks();
-		int nBlocksFree = statFS.getFreeBlocks();
-	
-		sRet = "total:     " + (nBlockCount * nBlockSize) + "\nfree:      " + (nBlocksFree * nBlockSize) + "\navailable: " + (nBlocksAvail * nBlockSize);
-	
-		return (sRet);
-		}
-
-	public String GetMemoryInfo()
-		{
-		String sRet = "PA:" + GetMemoryConfig();
-		return (sRet);
-		}
-
-	public long GetMemoryConfig()
-		{
-		ActivityManager aMgr = (ActivityManager) contextWrapper.getSystemService(Activity.ACTIVITY_SERVICE);
-		ActivityManager.MemoryInfo outInfo = new ActivityManager.MemoryInfo();
-		aMgr.getMemoryInfo(outInfo);
-		long lMem = outInfo.availMem;
-
-		return (lMem);
-		}
-	
-	public String RegisterTheDevice(String sSrvr, String sPort, String sData)
-		{
-		String sRet = "";
-		String line = "";
-		
-		if (sSrvr != null && sPort != null && sData != null)
-			{
-			try
-				{
-				int nPort = Integer.parseInt(sPort);
-				Socket socket = new Socket(sSrvr, nPort);
-				PrintWriter out = new PrintWriter(socket.getOutputStream(), false);
-				BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
-				out.println(sData);
-				if ( out.checkError() == false )
-					{
-					socket.setSoTimeout(30000);
-					while (socket.isInputShutdown() == false)
-						{
-						line = in.readLine();
-						line = line.toLowerCase();
-						if ((line == null) || (line.contains("ok")))
-							{
-							sRet += line;
-							break;
-							}
-						sRet += line;
-						}
-					}
-				out.close();
-				in.close();
-				socket.close();
-				}
-			catch(NumberFormatException e)
-				{
-				e.printStackTrace();
-				} 
-			catch (UnknownHostException e)
-				{
-				e.printStackTrace();
-				}
-			catch (IOException e)
-				{
-				sRet += "reg exception thrown";
-				e.printStackTrace();
-				}
-			}
-		return(sRet);
-		}
-	
-	public String GetInternetData(String sHost, String sPort, String sURL)
-		{
-		String sRet = "";
-		String sNewURL = "";
-		HttpClient httpClient = new DefaultHttpClient();
-		try 
-			{
-			sNewURL = "http://" + sHost + ((sPort.length() > 0) ? (":" + sPort) : "") + sURL;
-
-			HttpGet request = new HttpGet(sNewURL);
-			HttpResponse response = httpClient.execute(request);
-			int status = response.getStatusLine().getStatusCode();
-			// we assume that the response body contains the error message
-			if (status != HttpStatus.SC_OK)
-				{
-			    ByteArrayOutputStream ostream = new ByteArrayOutputStream();
-			    response.getEntity().writeTo(ostream);
-			    Log.e("HTTP CLIENT", ostream.toString());
-				}
-			else
-				{
-			    InputStream content = response.getEntity().getContent();
-//			    int nAvailable = content.available();
-//			    byte [] data = new byte [nAvailable];
-			    byte [] data = new byte [2048];
-			    int nRead = content.read(data);
-			    sRet = new String(data, 0, nRead);
-			    content.close(); // this will also close the connection
-				}
-			}
-		catch (IllegalArgumentException e)
-			{
-			sRet = e.getLocalizedMessage();
-			e.printStackTrace();
-			}
-		catch (ClientProtocolException e)
-			{
-			sRet = e.getLocalizedMessage();
-			e.printStackTrace();
-			}
-		catch (IOException e)
-			{
-			sRet = e.getLocalizedMessage();
-			e.printStackTrace();
-			}
-		
-		return(sRet);
-		}
-	
-	public String GetTimeZone()
-		{
-		String	sRet = "";
-		TimeZone tz;
-		
-		tz = TimeZone.getDefault();
-		Date now = new Date();
-		sRet = tz.getDisplayName(tz.inDaylightTime(now), TimeZone.LONG);
-		
-		return(sRet);
-		}
-	
-	public String SetTimeZone(String sTimeZone)
-		{
-		String			sRet = "Unable to set timezone to " + sTimeZone;
-		TimeZone 		tz = null;
-		AlarmManager 	amgr = null;
-		
-		if ((sTimeZone.length() > 0) && (sTimeZone.startsWith("GMT")))
-			{
-			amgr = (AlarmManager) contextWrapper.getSystemService(Context.ALARM_SERVICE);
-			if (amgr != null)
-				amgr.setTimeZone(sTimeZone);
-			}
-		else
-			{
-			String [] zoneNames = TimeZone.getAvailableIDs();
-			int nNumMatches = zoneNames.length;
-			int	lcv = 0;
-			
-			for (lcv = 0; lcv < nNumMatches; lcv++)
-				{
-				if (zoneNames[lcv].equalsIgnoreCase(sTimeZone))
-					break;
-				}
-
-			if (lcv < nNumMatches)
-				{
-				amgr = (AlarmManager) contextWrapper.getSystemService(Context.ALARM_SERVICE);
-				if (amgr != null)
-					amgr.setTimeZone(zoneNames[lcv]);
-				}
-			}
-		
-		if (amgr != null)
-			{
-			tz = TimeZone.getDefault();
-			Date now = new Date();
-			sRet = tz.getDisplayName(tz.inDaylightTime(now), TimeZone.LONG);
-			}
-		
-		return(sRet);
-		}
-
-	public String GetSystemTime()
-		{
-		String sRet = "";
-		Calendar cal = Calendar.getInstance();
-		SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss:SSS");
-		sRet = sdf.format(cal.getTime());
-	
-		return (sRet);
-		}
-	
-	public String SetSystemTime(String sDate, String sTime, OutputStream out)
-		{
-		String sRet = "";
-		
-		if (((sDate != null) && (sTime != null)) && 
-			(sDate.contains("/") || sDate.contains(".")) &&
-			(sTime.contains(":")))
-			{
-			int year = Integer.parseInt(sDate.substring(0,4));
-			int month = Integer.parseInt(sDate.substring(5,7));
-			int day = Integer.parseInt(sDate.substring(8,10));
-			
-			int hour = Integer.parseInt(sTime.substring(0,2));
-			int mins = Integer.parseInt(sTime.substring(3,5));
-			int secs = Integer.parseInt(sTime.substring(6,8));
-
-			Calendar cal = new GregorianCalendar(TimeZone.getDefault());
-			cal.set(year, month - 1, day, hour, mins, secs);
-			long lMillisecs = cal.getTime().getTime();
-			
-			String sM = Long.toString(lMillisecs);
-			String sMillis = sM.substring(0, sM.length() - 3) + "." + sM.substring(sM.length() - 3);
-			String [] theArgs = new String [3];
-		
-			theArgs[0] = "su";
-			theArgs[1] = "-c";
-			theArgs[2] = "date -u " + sMillis;
-		
-			try 
-				{
-				pProc = Runtime.getRuntime().exec(theArgs);
-				RedirOutputThread outThrd = new RedirOutputThread(pProc, null);
-				outThrd.start();
-				outThrd.join(10000);
-				sRet = GetSystemTime();
-				}
-			catch (IOException e) 
-				{
-				sRet = e.getMessage();
-				e.printStackTrace();
-				} 
-			catch (InterruptedException e)
-				{
-				e.printStackTrace();
-				}
-			}
-		else
-			{
-			sRet = "Invalid argument(s)";
-			}
-
-		return (sRet);
-		}
-
-	public String GetClok()
-		{
-		long lMillisecs = System.currentTimeMillis();
-		String sRet = "";
-		
-		if (lMillisecs > 0)
-			sRet = Long.toString(lMillisecs);
-		
-		return(sRet);
-		}
-	
-	public String GetUptime()
-		{
-		String sRet = "";
-		long lHold = 0;
-		long lUptime = SystemClock.elapsedRealtime();
-		int	nDays = 0;
-		int	nHours = 0;
-		int nMinutes = 0;
-		int nSecs = 0;
-		int nMilliseconds = 0;
-		
-		if (lUptime > 0)
-			{
-			nDays = (int)(lUptime / (24L * 60L * 60L * 1000L));
-			lHold = lUptime % (24L * 60L * 60L * 1000L);
-			nHours = (int)(lHold / (60L * 60L * 1000L));
-			lHold %= 60L * 60L * 1000L;
-			nMinutes = (int)(lHold / (60L * 1000L));
-			lHold %= 60L * 1000L;
-			nSecs = (int)(lHold / 1000L);
-			nMilliseconds = (int)(lHold % 1000);
-			sRet = "" + nDays + " days " + nHours + " hours " + nMinutes + " minutes " + nSecs + " seconds " + nMilliseconds + " ms";
-			}
-
-		return (sRet);
-		}
-
-	public String NewKillProc(String sProcId, OutputStream out)
-		{
-		String sRet = "";
-		String [] theArgs = new String [3];
-		
-		theArgs[0] = "su";
-		theArgs[1] = "-c";
-		theArgs[2] = "kill " + sProcId;
-
-		try 
-			{
-			pProc = Runtime.getRuntime().exec(theArgs);
-			RedirOutputThread outThrd = new RedirOutputThread(pProc, out);
-			outThrd.start();
-			outThrd.join(5000);
-			}
-		catch (IOException e) 
-			{
-			sRet = e.getMessage();
-			e.printStackTrace();
-			} 
-		catch (InterruptedException e)
-			{
-			// TODO Auto-generated catch block
-			e.printStackTrace();
-			}
-
-		return(sRet);
-		}
-	
-	public String SendPing(String sIPAddr, OutputStream out)
-		{
-		String sRet = "";
-		String [] theArgs = new String [4];
-		
-		theArgs[0] = "ping";
-		theArgs[1] = "-c";
-		theArgs[2] = "3";
-		theArgs[3] = sIPAddr;
-		
-		try 
-			{
-			pProc = Runtime.getRuntime().exec(theArgs);
-			RedirOutputThread outThrd = new RedirOutputThread(pProc, out);
-			outThrd.start();
-			outThrd.join(5000);
-			if (out == null)
-				sRet = outThrd.strOutput;
-			}
-		catch (IOException e) 
-			{
-			sRet = e.getMessage();
-			e.printStackTrace();
-			} 
-		catch (InterruptedException e)
-			{
-			e.printStackTrace();
-			}
-	
-		return (sRet);
-		}
-	
-	public String GetTmpDir()
-	{
-		String 	sRet = "";
-		Context ctx = contextWrapper.getApplicationContext();
-        File dir = ctx.getFilesDir();
-        ctx = null;
-        try {
-			sRet = dir.getCanonicalPath();
-			} 
-        catch (IOException e)
-        	{
-			e.printStackTrace();
-        	}
-        return(sRet);
-	}
-	
-	public String PrintFileTimestamp(String sFile)
-		{
-		String 	sRet = "";
-		String	sTmpFileName = fixFileName(sFile);
-		File 	theFile = new File(sTmpFileName);
-		
-		if (theFile.exists())
-			{
-			long lModified = theFile.lastModified();
-			Date dtModified = new Date(lModified);
-			SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss:SSS");
-			sRet = "Last modified: " + sdf.format(dtModified);
-			}
-		else
-			{
-			sRet = sErrorPrefix + "[" + sTmpFileName + "] doesn't exist";
-			}
-
-		return(sRet);
-		}
-	
-	public String GetIniData(String sSection, String sKey, String sFile)
-		{
-		String sRet = "";
-		String sComp = "";
-		String sLine = "";
-		boolean bFound = false;
-		BufferedReader in = null;
-		String	sTmpFileName = fixFileName(sFile);
-		
-		try {
-			in = new BufferedReader(new FileReader(sTmpFileName));
-			sComp = "[" + sSection + "]";
-			while ((sLine = in.readLine()) != null)
-				{
-				if (sLine.equalsIgnoreCase(sComp))
-					{
-					bFound = true;
-					break;
-					}
-				}
-			
-			if (bFound)
-				{
-				sComp = (sKey + " =").toLowerCase();
-				while ((sLine = in.readLine()) != null)
-					{
-					if (sLine.toLowerCase().contains(sComp))
-						{
-						String [] temp = null;
-						temp = sLine.split("=");
-						if (temp != null)
-							{
-							sRet = temp[1].trim();
-							}
-						break;
-						}
-					}
-				}
-			in.close();
-			}
-		catch (FileNotFoundException e)
-			{
-			sComp = e.toString();
-			} 
-		catch (IOException e) 
-			{
-			sComp = e.toString();
-			}
-		return (sRet);
-		}
-	
-	public String RunReboot(OutputStream out)
-		{
-		String sRet = "";
-		String [] theArgs = new String [3];
-	
-		theArgs[0] = "su";
-		theArgs[1] = "-c";
-		theArgs[2] = "reboot";
-	
-		try 
-			{
-			// Tell all of the data channels we are rebooting
-			((ASMozStub)this.contextWrapper).SendToDataChannel("Rebooting ...");
-			
-			pProc = Runtime.getRuntime().exec(theArgs);
-			RedirOutputThread outThrd = new RedirOutputThread(pProc, out);
-			outThrd.start();
-			outThrd.join(10000);
-			}
-		catch (IOException e) 
-			{
-			sRet = e.getMessage();
-			e.printStackTrace();
-			} 
-		catch (InterruptedException e)
-			{
-			e.printStackTrace();
-			}
-
-		return (sRet);
-		}
-	
-	public String UnInstallApp(String sApp, OutputStream out)
-		{
-		String sRet = "";
-		String [] theArgs = new String [3];
-
-		theArgs[0] = "su";
-		theArgs[1] = "-c";
-		theArgs[2] = "pm uninstall " + sApp + ";reboot;exit";
-		
-		try 
-			{
-			pProc = Runtime.getRuntime().exec(theArgs);
-		
-			RedirOutputThread outThrd = new RedirOutputThread(pProc, out);
-			outThrd.start();
-			outThrd.join(60000);
-			int nRet = pProc.exitValue();
-			sRet = "\nuninst complete [" + nRet + "]";
-			}
-		catch (IOException e) 
-			{
-			sRet = e.getMessage();
-			e.printStackTrace();
-			} 
-		catch (InterruptedException e)
-			{
-			// TODO Auto-generated catch block
-			e.printStackTrace();
-			}
-		
-		return (sRet);
-	}
-	
-	public String InstallApp(String sApp, OutputStream out)
-		{
-		String sRet = "";
-		String [] theArgs = new String [3];
-		File	srcFile = new File(sApp);
-//		boolean bDone = false;
-//		int		nExitCode;
-
-		theArgs[0] = "su";
-		theArgs[1] = "-c";
-		theArgs[2] = "mv " + GetTmpDir() + "/" + srcFile.getName() + " /data/local/tmp/" + srcFile.getName() + ";exit";
-//		theArgs[2] += ";chmod 666 /data/local/tmp/" + srcFile.getName();
-//		theArgs[2] += ";pm install /data/local/tmp/" + srcFile.getName() + " Cleanup";
-//		theArgs[2] += ";done;exit";
-		
-		sRet = CopyFile(sApp, GetTmpDir() + "/" + srcFile.getName());
-		try {
-			out.write(sRet.getBytes());
-			out.flush();
-		} catch (IOException e1) {
-			// TODO Auto-generated catch block
-			e1.printStackTrace();
-		}
-//		CopyFile(sApp, GetTmpDir() + "/" + srcFile.getName());
-
-		try 
-			{
-			pProc = Runtime.getRuntime().exec(theArgs);
-			
-			RedirOutputThread outThrd = new RedirOutputThread(pProc, out);
-			outThrd.start();
-			outThrd.join(90000);
-			int nRet = pProc.exitValue();
-//			boolean bRet = outThrd.isAlive();
-			sRet = "\nmove complete [" + nRet + "]";
-			try 
-				{
-				out.write(sRet.getBytes());
-				out.flush();
-				}
-			catch (IOException e1)
-				{
-				// TODO Auto-generated catch block
-				e1.printStackTrace();
-				}
-			
-			theArgs[2] = "chmod 666 /data/local/tmp/" + srcFile.getName() + ";exit";
-			pProc = Runtime.getRuntime().exec(theArgs);
-			RedirOutputThread outThrd2 = new RedirOutputThread(pProc, out);
-			outThrd2.start();
-			outThrd2.join(10000);
-			int nRet2 = pProc.exitValue();
-//			bRet = outThrd2.isAlive();
-			sRet = "\npermission change complete [" + nRet2 + "]\n";
-			try {
-				out.write(sRet.getBytes());
-				out.flush();
-				}
-			catch (IOException e1)
-				{
-				// TODO Auto-generated catch block
-				e1.printStackTrace();
-				}
-			
-			theArgs[2] = "pm install /data/local/tmp/" + srcFile.getName() + " Cleanup" + ";exit";
-			pProc = Runtime.getRuntime().exec(theArgs);
-			RedirOutputThread outThrd3 = new RedirOutputThread(pProc, out);
-			outThrd3.start();
-			outThrd3.join(60000);
-			int nRet3 = pProc.exitValue();
-			sRet = "\ninstallation complete [" + nRet3 + "]";
-			try {
-				out.write(sRet.getBytes());
-				out.flush();
-				}
-			catch (IOException e1)
-				{
-				// TODO Auto-generated catch block
-				e1.printStackTrace();
-				}
-			
-			theArgs[2] = "rm /data/local/tmp/" + srcFile.getName() + ";exit";
-			pProc = Runtime.getRuntime().exec(theArgs);
-			RedirOutputThread outThrd4 = new RedirOutputThread(pProc, out);
-			outThrd4.start();
-			outThrd4.join(60000);
-			int nRet4 = pProc.exitValue();
-			sRet = "\ntmp file removed [" + nRet4 + "]";
-			try {
-				out.write(sRet.getBytes());
-				out.flush();
-				}
-			catch (IOException e1)
-				{
-				// TODO Auto-generated catch block
-				e1.printStackTrace();
-				}
-			sRet = "\nSuccess";
-			}
-		catch (IOException e) 
-			{
-			sRet = e.getMessage();
-			e.printStackTrace();
-			} 
-		catch (InterruptedException e)
-			{
-			// TODO Auto-generated catch block
-			e.printStackTrace();
-			}
-
-		return (sRet);
-		}
-
-	public String StartUpdateOMatic(String sPkgName, String sPkgFileName)
-		{
-		String sRet = "";
-	
-		Context ctx = contextWrapper.getApplicationContext();
-		PackageManager pm = ctx.getPackageManager();
-
-		Intent prgIntent = new Intent();
-		prgIntent.setPackage("com.mozilla.UpdateOMatic");
-		prgIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
-		try {
-			PackageInfo pi = pm.getPackageInfo("com.mozilla.UpdateOMatic", PackageManager.GET_ACTIVITIES | PackageManager.GET_INTENT_FILTERS);
-			ActivityInfo [] ai = pi.activities;
-			for (int i = 0; i < ai.length; i++)
-				{
-				ActivityInfo a = ai[i];
-				if (a.name.length() > 0)
-					{
-					prgIntent.setClassName(a.packageName, a.name);
-					break;
-					}
-				}
-			}
-		catch (NameNotFoundException e)
-			{
-			e.printStackTrace();
-			}
-		
-		prgIntent.putExtra("pkgName", sPkgName);
-		prgIntent.putExtra("pkgFileName", sPkgFileName);
-
-		try 
-			{
-			contextWrapper.startActivity(prgIntent);
-			sRet = "exit";
-			}
-		catch(ActivityNotFoundException anf)
-			{
-			anf.printStackTrace();
-			} 
-	
-		ctx = null;
-		return (sRet);
-		}
-
-	public String StartJavaPrg(String [] sArgs)
-		{
-		String sRet = "";
-		String sArgList = "";
-		String sUrl = "";
-		String sRedirFileName = "";
-		
-		Context ctx = contextWrapper.getApplicationContext();
-		PackageManager pm = ctx.getPackageManager();
-
-		Intent prgIntent = new Intent();
-		prgIntent.setPackage(sArgs[0]);
-		prgIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
-		try {
-			PackageInfo pi = pm.getPackageInfo(sArgs[0], PackageManager.GET_ACTIVITIES | PackageManager.GET_INTENT_FILTERS);
-			ActivityInfo [] ai = pi.activities;
-			for (int i = 0; i < ai.length; i++)
-				{
-				ActivityInfo a = ai[i];
-				if (a.name.length() > 0)
-					{
-					prgIntent.setClassName(a.packageName, a.name);
-					break;
-					}
-				}
-			}
-		catch (NameNotFoundException e)
-			{
-			e.printStackTrace();
-			}
-		
-		if (sArgs.length > 1)
-			{
-//			if (sArgs[0].contains("android.browser"))
-				prgIntent.setAction(Intent.ACTION_VIEW);
-			
-			if (sArgs[0].contains("fennec"))
-				{
-				sArgList = "";
-				sUrl = "";
-				
-				for (int lcv = 1; lcv < sArgs.length; lcv++)
-					{
-					if (sArgs[lcv].contains("://"))
-						sUrl = sArgs[lcv];
-					else
-						{
-						if (sArgs[lcv].equals(">"))
-							{
-							lcv++;
-							if (lcv < sArgs.length)
-								sRedirFileName = sArgs[lcv++];
-							}
-						else
-							sArgList += " " + sArgs[lcv];
-						}
-					}
-				
-				if (sArgList.length() > 0)
-					prgIntent.putExtra("args", sArgList.trim());
-				
-				if (sUrl.length() > 0)
-					prgIntent.setData(Uri.parse(sUrl.trim()));
-				}
-			else
-				{
-				for (int lcv = 1; lcv < sArgs.length; lcv++)
-					sArgList += " " + sArgs[lcv];
-				
-				prgIntent.setData(Uri.parse(sArgList.trim()));
-				}
-			}
-		else
-			prgIntent.setData(Uri.parse("about:blank"));
-
-		try 
-			{
-			contextWrapper.startActivity(prgIntent);
-			}
-		catch(ActivityNotFoundException anf)
-			{
-			anf.printStackTrace();
-			}
-		
-		ctx = null;
-		return (sRet);
-		}
-
-	public String StartPrg(String [] progArray, OutputStream out)
-		{
-		String sRet = "";
-		
-		try 
-			{
-			pProc = Runtime.getRuntime().exec(progArray);
-			RedirOutputThread outThrd = new RedirOutputThread(pProc, out);
-			outThrd.start();
-			outThrd.join(10000);
-			int nRetCode = pProc.exitValue();
-			sRet = "return code [" + nRetCode + "]";
-			}
-		catch (IOException e) 
-			{
-			e.printStackTrace();
-			}
-		catch (InterruptedException e)
-			{
-			e.printStackTrace();
-			sRet = "Timed out!";
-			}
-
-		return (sRet);
-		}
-/*	
-	@SuppressWarnings("unchecked")
-	public static void set(String key, String value) throws Exception
-		{
-	    Class[] classes = Collections.class.getDeclaredClasses();
-	    Map env = System.getenv();
-	    for(Class cl : classes)
-	    	{
-	        if("java.util.Collections$UnmodifiableMap".equals(cl.getName()))
-	        	{
-	            Field field = cl.getDeclaredField("m");
-	            field.setAccessible(true);
-	            Object obj = field.get(env);
-	            Map<String, String> map = (Map<String, String>) obj;
-	            map.put(key, value);
-	        	}
-	    	}
-		}
-
-*/	
-	public String StartPrg2(String [] progArray, OutputStream out)
-		{
-		String sRet = "";
-		
-		int	nArraySize = 0;
-		int	nArgs = progArray.length - 1; // 1st arg is the environment string
-		int	lcv	= 0;
-		int	temp = 0;
-
-		String sEnvString = progArray[0];
-
-		// Set up command line args stripping off the environment string
-		String [] theArgs = new String [nArgs];
-		for (lcv = 0; lcv < nArgs; lcv++)
-			{
-			theArgs[lcv] = progArray[lcv + 1];
-			}
-		
-		try 
-			{
-			String [] envStrings = sEnvString.split(",");
-			Map<String, String> newEnv = new HashMap<String, String>();
-			
-			for (lcv = 0; lcv < envStrings.length; lcv++)
-				{
-				temp = envStrings[lcv].indexOf("=");
-				if (temp > 0)
-					{
-					newEnv.put(	envStrings[lcv].substring(0, temp), 
-								envStrings[lcv].substring(temp + 1, envStrings[lcv].length()));
-					}
-				}
-			
-			Map<String, String> sysEnv = System.getenv();
-			
-			nArraySize = sysEnv.size();
-			
-			for (Map.Entry<String, String> entry : newEnv.entrySet())
-				{
-				if (!sysEnv.containsKey(entry.getKey()))
-					{
-					nArraySize++;
-					}
-				}
-			
-			String[] envArray = new String[nArraySize];
-				
-			int		i = 0;
-			int		offset;
-			String	sKey = "";
-			String 	sValue = "";
-			
-	        for (Map.Entry<String, String> entry : sysEnv.entrySet())
-	        	{
-	        	sKey = entry.getKey();
-	        	if (newEnv.containsKey(sKey))
-	        		{
-	        		sValue = newEnv.get(sKey);
-	        		if ((offset = sValue.indexOf("$" + sKey)) != -1)
-	        			{
-	        			envArray[i++] = sKey + 
-	        							"=" + 
-	        							sValue.substring(0, offset) + 
-	        							entry.getValue() + 
-	        							sValue.substring(offset + sKey.length() + 1);
-	        			}
-	        		else
-	        			envArray[i++] = sKey + "=" + sValue;
-	        		newEnv.remove(sKey);
-	        		}
-	        	else
-	        		envArray[i++] = entry.getKey() + "=" + entry.getValue();
-	        	}
-	        
-			for (Map.Entry<String, String> entry : newEnv.entrySet())
-				{
-        		envArray[i++] = entry.getKey() + "=" + entry.getValue();
-				}
-	        
-			pProc = Runtime.getRuntime().exec(theArgs, envArray);
-
-			RedirOutputThread outThrd = new RedirOutputThread(pProc, out);
-			outThrd.start();
-			outThrd.join(10000);
-			int nRetCode = pProc.exitValue();
-			sRet = "return code [" + nRetCode + "]";
-			}
-		catch(UnsupportedOperationException e)
-			{
-			if (e != null)
-				e.printStackTrace();
-			}
-		catch(ClassCastException e)
-			{
-			if (e != null)
-				e.printStackTrace();
-			}
-		catch(IllegalArgumentException e)
-			{
-			if (e != null)
-				e.printStackTrace();
-			}
-		catch(NullPointerException e)
-			{
-			if (e != null)
-				e.printStackTrace();
-			}
-		catch (IOException e) 
-			{
-			e.printStackTrace();
-			}
-		catch (InterruptedException e)
-			{
-			e.printStackTrace();
-			sRet = "Timed out!";
-			}
-
-		return (sRet);
-		}
-/*	
-	public String InstallApplication()
-		{
-		String sRet = "";
-		String sFileName = Environment.getExternalStorageDirectory() + "/org.mozilla.fennec.apk";
-		
-		Intent instIntent = new Intent();
-		
-		instIntent.setAction(android.content.Intent.ACTION_VIEW);
-		instIntent.setDataAndType(Uri.fromFile(new File(sFileName)), "application/vnd.android.package-archive");
-//		instIntent.setDataAndType(Uri.parse("file:///sdcard/org.mozilla.fennec.apk"), "application/vnd.android.package-archive");
-		SUTAgentAndroid.me.startActivity(instIntent);
-		
-//		Instrumentation inst = new Instrumentation();
-//		inst.sendKeyDownUpSync(KeyEvent.KEYCODE_SOFT_LEFT);
-		
-		return(sRet);
-		}
-
-	public String UninstallApplication()
-		{
-		String sRet = "";
-		Uri		pkgURI = Uri.parse("package:" + "org.mozilla.fennec");
-	
-		Intent unInstIntent = new Intent(Intent.ACTION_DELETE, pkgURI);
-	
-		SUTAgentAndroid.me.startActivity(unInstIntent);
-
-		return(sRet);
-		}
-*/
-	private String PrintUsage()
-		{
-		String sRet = 
-			"run [executable] [args]      - start program no wait\n" +
-			"exec [executable] [args]     - start program wait\n" +
-			"fire [executable] [args]     - start program no wait\n" +
-			"envrun [env pairs] [cmdline] - start program no wait\n" +
-			"kill [program name]          - kill program no path\n" +
-			"killall                      - kill all processes started\n" +
-			"ps                           - list of running processes\n" +
-			"info                         - list of device info\n" +
-			"        [os]                 - os version for device\n" +
-			"        [id]                 - unique identifier for device\n" +
-			"        [uptime]             - uptime for device\n" +
-			"        [systime]            - current system time on device\n" +
-			"        [screen]             - width, height and bits per pixel for device\n" +
-			"        [memory]             - physical, free, available, storage memory for device\n" +
-			"        [processes]          - list of running processes see 'ps'\n" +
-			"deadman timeout              - set the duration for the deadman timer\n" +
-			"alrt [on/off]                - start or stop sysalert behavior\n" +
-			"disk [arg]                   - prints disk space info\n" +
-			"cp file1 file2               - copy file1 to file2 on device\n" +
-			"time file                    - timestamp for file on device\n" +
-			"hash file                    - generate hash for file on device\n" +
-			"cd directory                 - change cwd on device\n" +
-			"cat file                     - cat file on device\n" +
-			"cwd                          - display cwd on device\n" +
-			"mv file1 file2               - move file1 to file2 on device\n" +
-			"push filename                - push file to device\n" +
-			"rm file                      - delete file on device\n" +
-			"rmdr directory               - delete directory on device even if not empty\n" +
-			"mkdr directory               - create directory on device\n" +
-			"dirw directory               - tests whether the directory is writable on the device\n" +
-			"stat processid               - stat process on device\n" +
-			"dead processid               - print whether the process is alive or hung on device\n" +
-			"mems                         - dump memory stats on device\n" +
-			"ls                           - print directory on device\n" +
-			"tmpd                         - print temp directory on device\n" +
-			"ping [hostname/ipaddr]       - ping a network device\n" +
-			"unzp zipfile destdir         - unzip the zipfile into the destination dir\n" +
-			"zip zipfile src              - zip the source file/dir into zipfile\n" +
-			"rebt                         - reboot device\n" +
-			"inst /path/filename.apk      - install the referenced apk file\n" +
-			"uninst packagename           - uninstall the referenced package\n" +
-			"updt pkgname pkgfile         - unpdate the referenced package\n" +
-			"clok                         - the current device time expressed as the number of millisecs since epoch\n" +
-			"settime date time            - sets the device date and time (YYYY/MM/DD HH:MM:SS)\n" +
-			"tzset timezone               - sets the device timezone format is GMTxhh:mm x = +/- or a recognized Olsen string\n" +
-			"tzget                        - returns the current timezone set on the device\n" +
-			"rebt                         - reboot device\n" +
-			"quit                         - disconnect SUTAgent\n" +
-			"exit                         - close SUTAgent\n" +
-			"ver                          - SUTAgent version\n" +
-			"help                         - you're reading it";
-		return (sRet);
-		}
-}
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (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.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Android SUTAgent code.
+ *
+ * The Initial Developer of the Original Code is
+ * Bob Moss.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Bob Moss <bmoss@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package com.mozilla.SUTAgentAndroid.service;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TimeZone;
+import java.util.zip.Adler32;
+import java.util.zip.CheckedInputStream;
+import java.util.zip.CheckedOutputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipInputStream;
+import java.util.zip.ZipOutputStream;
+
+import org.apache.commons.net.ftp.FTP;
+import org.apache.commons.net.ftp.FTPClient;
+import org.apache.commons.net.ftp.FTPFile;
+import org.apache.commons.net.ftp.FTPReply;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.DefaultHttpClient;
+
+import com.mozilla.SUTAgentAndroid.NtpMessage;
+import com.mozilla.SUTAgentAndroid.R;
+import com.mozilla.SUTAgentAndroid.SUTAgentAndroid;
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.AlarmManager;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.ActivityNotFoundException;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Debug;
+import android.os.Environment;
+import android.os.StatFs;
+import android.os.SystemClock;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.WindowManager;
+
+public class DoCommand {
+
+    String lineSep = System.getProperty("line.separator");
+    Process    pProc;
+    OutputStream sutIn;
+    InputStream    sutErr;
+    InputStream    sutOut;
+    AlertLooperThread alrt = null;
+    ContextWrapper    contextWrapper = null;
+
+    String    currentDir = "/";
+    String    sErrorPrefix = "##AGENT-WARNING## ";
+    boolean bTraceOn = false;
+
+    String ffxProvider = "org.mozilla.ffxcp";
+    String fenProvider = "org.mozilla.fencp";
+
+    private final String prgVersion = "SUTAgentAndroid Version 1.01";
+
+    public enum Command
+        {
+        RUN ("run"),
+        EXEC ("exec"),
+        ENVRUN ("envrun"),
+        KILL ("kill"),
+        PS ("ps"),
+        DEVINFO ("info"),
+        OS ("os"),
+        ID ("id"),
+        UPTIME ("uptime"),
+        SETTIME ("settime"),
+        SYSTIME ("systime"),
+        SCREEN ("screen"),
+        MEMORY ("memory"),
+        POWER ("power"),
+        PROCESS ("process"),
+        GETAPPROOT ("getapproot"),
+        TESTROOT ("testroot"),
+        ALRT ("alrt"),
+        DISK ("disk"),
+        CP ("cp"),
+        TIME ("time"),
+        HASH ("hash"),
+        CD ("cd"),
+        CAT ("cat"),
+        CWD ("cwd"),
+        MV ("mv"),
+        PUSH ("push"),
+        PULL ("pull"),
+        RM ("rm"),
+        PRUNE ("rmdr"),
+        MKDR ("mkdr"),
+        DIRWRITABLE ("dirw"),
+        ISDIR ("isdir"),
+        DEAD ("dead"),
+        MEMS ("mems"),
+        LS ("ls"),
+        TMPD ("tmpd"),
+        PING ("ping"),
+        REBT ("rebt"),
+        UNZP ("unzp"),
+        ZIP ("zip"),
+        CLOK ("clok"),
+        STAT ("stat"),
+        QUIT ("quit"),
+        EXIT ("exit"),
+        HELP ("help"),
+        FTPG ("ftpg"),
+        FTPP ("ftpp"),
+        INST ("inst"),
+        UPDT ("updt"),
+        UNINST ("uninst"),
+        TEST ("test"),
+        DBG ("dbg"),
+        TRACE ("trace"),
+        VER ("ver"),
+        TZGET ("tzget"),
+        TZSET ("tzset"),
+        ADB ("adb"),
+        UNKNOWN ("unknown");
+
+        private final String theCmd;
+
+        Command(String theCmd) { this.theCmd = theCmd; }
+
+        public String theCmd() {return theCmd;}
+
+        public static Command getCmd(String sCmd)
+            {
+            Command retCmd = UNKNOWN;
+            for (Command cmd : Command.values())
+                {
+                if (cmd.theCmd().equalsIgnoreCase(sCmd))
+                    {
+                    retCmd = cmd;
+                    break;
+                    }
+                }
+            return (retCmd);
+            }
+        }
+
+    public DoCommand(ContextWrapper service)
+        {
+        this.contextWrapper = service;
+        }
+
+    public String processCommand(String theCmdLine, PrintWriter out, BufferedInputStream in, OutputStream cmdOut)
+        {
+        String     strReturn = "";
+        Command    cCmd = null;
+        Command cSubCmd = null;
+
+        if (bTraceOn)
+            ((ASMozStub)this.contextWrapper).SendToDataChannel(theCmdLine);
+
+        String [] Argv = parseCmdLine2(theCmdLine);
+
+        int Argc = Argv.length;
+
+        cCmd = Command.getCmd(Argv[0]);
+
+        switch(cCmd)
+            {
+            case TRACE:
+                if (Argc == 2)
+                    bTraceOn = (Argv[1].equalsIgnoreCase("on") ? true : false);
+                else
+                    strReturn = sErrorPrefix + "Wrong number of arguments for trace command!";
+                break;
+
+            case VER:
+                strReturn = prgVersion;
+                break;
+
+            case CLOK:
+                strReturn = GetClok();
+                break;
+
+            case TZGET:
+                strReturn = GetTimeZone();
+                break;
+
+            case TZSET:
+                if (Argc == 2)
+                    strReturn = SetTimeZone(Argv[1]);
+                else
+                    strReturn = sErrorPrefix + "Wrong number of arguments for settz command!";
+                break;
+
+            case UPDT:
+                if (Argc >= 2)
+                    strReturn = StrtUpdtOMatic(Argv[1], Argv[2], (Argc > 3 ? Argv[3] : null), (Argc > 4 ? Argv[4] : null));
+                else
+                    strReturn = sErrorPrefix + "Wrong number of arguments for updt command!";
+                break;
+
+            case SETTIME:
+                strReturn = SetSystemTime(Argv[1], (Argc > 2 ? Argv[2] : null), cmdOut);
+                break;
+
+            case CWD:
+                try {
+                    strReturn = new java.io.File(currentDir).getCanonicalPath();
+                    }
+                catch (IOException e)
+                    {
+                    e.printStackTrace();
+                    }
+                break;
+
+            case CD:
+                if (Argc == 2)
+                    strReturn = changeDir(Argv[1]);
+                else
+                    strReturn = sErrorPrefix + "Wrong number of arguments for cd command!";
+                break;
+
+            case LS:
+                strReturn = PrintDir(((Argc > 1) ? Argv[1] : currentDir));
+                break;
+
+            case GETAPPROOT:
+                if (Argc == 2)
+                    strReturn = GetAppRoot(Argv[1]);
+                else
+                    strReturn = sErrorPrefix + "Wrong number of arguments for getapproot command!";
+                break;
+
+            case ISDIR:
+                if (Argc == 2)
+                    strReturn = isDirectory(Argv[1]);
+                else
+                    strReturn = sErrorPrefix + "Wrong number of arguments for isdir command!";
+                break;
+
+            case TESTROOT:
+                strReturn = GetTestRoot();
+                break;
+
+            case DEAD:
+                if (Argc == 2)
+                    strReturn = (IsProcessDead(Argv[1]) ? (Argv[1] + " is hung or unresponsive") : (Argv[1] + " is ok"));
+                else
+                    strReturn = sErrorPrefix + "Wrong number of arguments for dead command!";
+                break;
+
+            case PS:
+                strReturn = GetProcessInfo();
+                break;
+
+            case PULL:
+                if (Argc >= 2) {
+                    long lOff = 0;
+                    long lLen = -1;
+                    if (Argc > 2) {
+                        try {
+                            lOff = Long.parseLong(Argv[2].trim());
+                            System.out.println("offset = " + lOff);
+                        } catch (NumberFormatException nfe) {
+                            lOff = 0;
+                            System.out.println("NumberFormatException: " + nfe.getMessage());
+                        }
+                    }
+                    if (Argc == 4) {
+                        try {
+                            lLen = Long.parseLong(Argv[3].trim());
+                            System.out.println("length = " + lLen);
+                        } catch (NumberFormatException nfe) {
+                            lLen = -1;
+                            System.out.println("NumberFormatException: " + nfe.getMessage());
+                        }
+                    }
+                    strReturn = Pull(Argv[1], lOff, lLen, cmdOut);
+                } else {
+                    strReturn = sErrorPrefix + "Wrong number of arguments for pull command!";
+                }
+                break;
+
+            case PUSH:
+                if (Argc == 3)
+                    {
+                    long lArg = 0;
+                    try
+                        {
+                        lArg = Long.parseLong(Argv[2].trim());
+                        System.out.println("long l = " + lArg);
+                        }
+                    catch (NumberFormatException nfe)
+                        {
+                        System.out.println("NumberFormatException: " + nfe.getMessage());
+                        }
+
+                    strReturn = Push(Argv[1], in, lArg);
+                    }
+                else
+                    strReturn = sErrorPrefix + "Wrong number of arguments for push command!";
+                break;
+
+            case INST:
+                if (Argc >= 2)
+                    strReturn = InstallApp(Argv[1], cmdOut);
+                else
+                    strReturn = sErrorPrefix + "Wrong number of arguments for inst command!";
+                break;
+
+            case UNINST:
+                if (Argc >= 2)
+                    strReturn = UnInstallApp(Argv[1], cmdOut);
+                else
+                    strReturn = sErrorPrefix + "Wrong number of arguments for inst command!";
+                break;
+
+            case ALRT:
+                if (Argc > 1)
+                    {
+                    if (Argv[1].contentEquals("on"))
+                        {
+                        String sTitle = "Agent Alert";
+                        String sMsg = "The Agent Alert System has been activated!";
+                        if (Argc == 3) {
+                            sTitle = Argv[2];
+                            sMsg = "";
+                        } else if (Argc == 4) {
+                            sTitle = Argv[2];
+                            sMsg = Argv[3];
+                        }
+                        StartAlert(sTitle, sMsg);
+                        }
+                    else
+                        {
+                        StopAlert();
+                        }
+                    }
+                else
+                    {
+                    strReturn = sErrorPrefix + "Wrong number of arguments for alrt command!";
+                    }
+                break;
+
+            case REBT:
+                if (Argc >= 1)
+                    strReturn = RunReboot(cmdOut, (Argc > 1 ? Argv[1] : null), (Argc > 2 ? Argv[2] : null));
+                else
+                    strReturn = sErrorPrefix + "Wrong number of arguments for rebt command!";
+//                RunReboot(cmdOut);
+                break;
+
+            case TMPD:
+                strReturn = GetTmpDir();
+                break;
+
+            case DEVINFO:
+                if (Argc == 1)
+                    {
+                    strReturn += SUTAgentAndroid.sUniqueID;
+                    strReturn += "\n";
+                    strReturn += GetOSInfo();
+                    strReturn += "\n";
+                    strReturn += GetSystemTime();
+                    strReturn += "\n";
+                    strReturn += GetUptime();
+                    strReturn += "\n";
+                    strReturn += GetScreenInfo();
+                    strReturn += "\n";
+                    strReturn += GetMemoryInfo();
+                    strReturn += "\n";
+                    strReturn += GetPowerInfo();
+                    strReturn += "\n";
+                    strReturn += GetProcessInfo();
+                    }
+                else
+                    {
+                    cSubCmd = Command.getCmd(Argv[1]);
+                    switch(cSubCmd)
+                        {
+                        case ID:
+                            strReturn = SUTAgentAndroid.sUniqueID;
+                            break;
+
+                        case SCREEN:
+                            strReturn = GetScreenInfo();
+                            break;
+
+                        case PROCESS:
+                            strReturn = GetProcessInfo();
+                            break;
+
+                        case OS:
+                            strReturn = GetOSInfo();
+                            break;
+
+                        case SYSTIME:
+                            strReturn = GetSystemTime();
+                            break;
+
+                        case UPTIME:
+                            strReturn = GetUptime();
+                            break;
+
+                        case MEMORY:
+                            strReturn = GetMemoryInfo();
+                            break;
+
+                        case POWER:
+                            strReturn += GetPowerInfo();
+                            break;
+
+                        default:
+                            break;
+                        }
+                    }
+                break;
+
+            case STAT:
+                if (Argc == 2)
+                    strReturn = StatProcess(Argv[1]);
+                else
+                    strReturn = sErrorPrefix + "Wrong number of arguments for ping command!";
+                break;
+
+            case PING:
+                if (Argc == 2)
+                    strReturn = SendPing(Argv[1], cmdOut);
+                else
+                    strReturn = sErrorPrefix + "Wrong number of arguments for ping command!";
+                break;
+
+            case HASH:
+                if (Argc == 2)
+                    strReturn = HashFile(Argv[1]);
+                else
+                    strReturn = sErrorPrefix + "Wrong number of arguments for hash command!";
+                break;
+
+            case PRUNE:
+                if (Argc == 2)
+                    strReturn = PruneDir(Argv[1]);
+                else
+                    strReturn = sErrorPrefix + "Wrong number of arguments for prune command!";
+                break;
+
+            case FTPG:
+                if (Argc == 4)
+                    strReturn = FTPGetFile(Argv[1], Argv[2], Argv[3], cmdOut);
+                else
+                    strReturn = sErrorPrefix + "Wrong number of arguments for ftpg command!";
+                break;
+
+            case CAT:
+                if (Argc == 2)
+                    strReturn = Cat(Argv[1], cmdOut);
+                else
+                    strReturn = sErrorPrefix + "Wrong number of arguments for cat command!";
+                break;
+
+            case DIRWRITABLE:
+                if (Argc == 2)
+                    strReturn = IsDirWritable(Argv[1]);
+                else
+                    strReturn = sErrorPrefix + "Wrong number of arguments for dirwritable command!";
+                break;
+
+            case TIME:
+                if (Argc == 2)
+                    strReturn = PrintFileTimestamp(Argv[1]);
+                else
+                    strReturn = sErrorPrefix + "Wrong number of arguments for time command!";
+                break;
+
+            case MKDR:
+                if (Argc == 2)
+                    strReturn = MakeDir(Argv[1]);
+                else
+                    strReturn = sErrorPrefix + "Wrong number of arguments for mkdr command!";
+                break;
+
+            case RM:
+                if (Argc == 2)
+                    strReturn = RemoveFile(Argv[1]);
+                else
+                    strReturn = sErrorPrefix + "Wrong number of arguments for rm command!";
+                break;
+
+            case MV:
+                if (Argc == 3)
+                    strReturn = Move(Argv[1], Argv[2]);
+                else
+                    strReturn = sErrorPrefix + "Wrong number of arguments for mv command!";
+                break;
+
+            case CP:
+                if (Argc == 3)
+                    strReturn = CopyFile(Argv[1], Argv[2]);
+                else
+                    strReturn = sErrorPrefix + "Wrong number of arguments for cp command!";
+                break;
+
+            case QUIT:
+            case EXIT:
+                strReturn = Argv[0];
+                break;
+
+            case DBG:
+                Debug.waitForDebugger();
+                strReturn = "waitForDebugger on";
+                break;
+
+            case ADB:
+                if (Argc == 2) {
+                    if (Argv[1].contains("ip") || Argv[1].contains("usb")) {
+                        strReturn = SetADB(Argv[1]);
+                    } else {
+                        strReturn = sErrorPrefix + "Unrecognized argument for adb command!";
+                    }
+                } else {
+                    strReturn = sErrorPrefix + "Wrong number of arguments for adb command!";
+                }
+                break;
+
+            case TEST:
+                long lFreeMemory = Runtime.getRuntime().freeMemory();
+                long lTotMemory = Runtime.getRuntime().totalMemory();
+                long lMaxMemory = Runtime.getRuntime().maxMemory();
+
+
+                if (lFreeMemory > 0) {
+                    strReturn = "Max memory: " + lMaxMemory + "\nTotal Memory: " + lTotMemory + "\nFree memory: " + lFreeMemory;
+                    break;
+                }
+
+                ContentResolver cr = contextWrapper.getContentResolver();
+                Uri ffxFiles = null;
+
+                if (Argv[1].contains("fennec")) {
+                    ffxFiles = Uri.parse("content://" + fenProvider + "/dir");
+                } else if (Argv[1].contains("firefox")) {
+                    ffxFiles = Uri.parse("content://" + ffxProvider + "/dir");
+                }
+
+//                Uri ffxFiles = Uri.parse("content://org.mozilla.fencp/file");
+                String[] columns = new String[] {
+                        "_id",
+                        "isdir",
+                        "filename",
+                        "length"
+                    };
+//                String[] columns = new String[] {
+//                        "_id",
+//                        "chunk"
+//                     };
+                Cursor myCursor = cr.query(    ffxFiles,
+                                            columns,                         // Which columns to return
+                                            (Argc > 1 ? Argv[1] : null),    // Which rows to return (all rows)
+                                            null,                           // Selection arguments (none)
+                                            null);                            // Put the results in ascending order by name
+/*
+                if (myCursor != null) {
+                    int nRows = myCursor.getCount();
+                    String [] colNames = myCursor.getColumnNames();
+                    int    nID = 0;
+                    int nBytesRecvd = 0;
+
+                    for (int lcv = 0; lcv < nRows; lcv++) {
+                        if  (myCursor.moveToPosition(lcv)) {
+                            nID = myCursor.getInt(0);
+                            byte [] buf = myCursor.getBlob(1);
+                            if (buf != null) {
+                                nBytesRecvd += buf.length;
+                                strReturn += new String(buf);
+                                buf = null;
+                            }
+                        }
+                    }
+                    strReturn += "[eof - " + nBytesRecvd + "]";
+                    myCursor.close();
+                }
+
+*/
+                if (myCursor != null)
+                    {
+                    int nRows = myCursor.getCount();
+                    int    nID = 0;
+                    String sFileName = "";
+                    long lFileSize = 0;
+                    boolean bIsDir = false;
+
+                    for (int lcv = 0; lcv < nRows; lcv++)
+                        {
+                        if  (myCursor.moveToPosition(lcv))
+                            {
+                            nID = myCursor.getInt(0);
+                            bIsDir = (myCursor.getInt(1) == 1 ? true : false);
+                            sFileName = myCursor.getString(2);
+                            lFileSize = myCursor.getLong(3);
+                            strReturn += "" + nID + "\t" + (bIsDir ? "<dir> " : "      ") + sFileName + "\t" + lFileSize + "\n";
+                            }
+                        }
+                    myCursor.close();
+                    }
+                break;
+
+            case EXEC:
+            case ENVRUN:
+                if (Argc >= 2)
+                    {
+                    String [] theArgs = new String [Argc - 1];
+
+                    for (int lcv = 1; lcv < Argc; lcv++)
+                        {
+                        theArgs[lcv - 1] = Argv[lcv];
+                        }
+
+                    strReturn = StartPrg2(theArgs, cmdOut);
+                    }
+                else
+                    {
+                    strReturn = sErrorPrefix + "Wrong number of arguments for " + Argv[0] + " command!";
+                    }
+                break;
+
+            case RUN:
+                if (Argc >= 2)
+                    {
+                    String [] theArgs = new String [Argc - 1];
+
+                    for (int lcv = 1; lcv < Argc; lcv++)
+                        {
+                        theArgs[lcv - 1] = Argv[lcv];
+                        }
+
+                    if (Argv[1].contains("/") || Argv[1].contains("\\") || !Argv[1].contains("."))
+                        strReturn = StartPrg(theArgs, cmdOut);
+                    else
+                        strReturn = StartJavaPrg(theArgs, null);
+                    }
+                else
+                    {
+                    strReturn = sErrorPrefix + "Wrong number of arguments for " + Argv[0] + " command!";
+                    }
+                break;
+
+            case KILL:
+                if (Argc == 2)
+                    strReturn = KillProcess(Argv[1], cmdOut);
+                else
+                    strReturn = sErrorPrefix + "Wrong number of arguments for kill command!";
+                break;
+
+            case DISK:
+                strReturn = GetDiskInfo((Argc == 2 ? Argv[1] : "/"));
+                break;
+
+            case UNZP:
+                strReturn = Unzip(Argv[1], (Argc == 3 ? Argv[2] : ""));
+                break;
+
+            case ZIP:
+                strReturn = Zip(Argv[1], (Argc == 3 ? Argv[2] : ""));
+                break;
+
+            case HELP:
+                strReturn = PrintUsage();
+                break;
+
+            default:
+                strReturn = sErrorPrefix + "[" + Argv[0] + "] command";
+                if (Argc > 1)
+                    {
+                    strReturn += " with arg(s) =";
+                    for (int lcv = 1; lcv < Argc; lcv++)
+                        {
+                        strReturn += " [" + Argv[lcv] + "]";
+                        }
+                    }
+                strReturn += " is currently not implemented.";
+                break;
+            }
+
+        return(strReturn);
+        }
+
+    private void SendNotification(String tickerText, String expandedText) {
+        NotificationManager notificationManager = (NotificationManager)contextWrapper.getSystemService(Context.NOTIFICATION_SERVICE);
+        int icon = R.drawable.ateamlogo;
+        long when = System.currentTimeMillis();
+
+        Notification notification = new Notification(icon, tickerText, when);
+
+        notification.flags |= (Notification.FLAG_INSISTENT | Notification.FLAG_AUTO_CANCEL);
+        notification.defaults |= Notification.DEFAULT_SOUND;
+        notification.defaults |= Notification.DEFAULT_VIBRATE;
+        notification.defaults |= Notification.DEFAULT_LIGHTS;
+
+        Context context = contextWrapper.getApplicationContext();
+
+        // Intent to launch an activity when the extended text is clicked
+        Intent intent2 = new Intent(contextWrapper, SUTAgentAndroid.class);
+        PendingIntent launchIntent = PendingIntent.getActivity(context, 0, intent2, 0);
+
+        notification.setLatestEventInfo(context, tickerText, expandedText, launchIntent);
+
+        notificationManager.notify(1959, notification);
+    }
+
+private void CancelNotification()
+    {
+    NotificationManager notificationManager = (NotificationManager)contextWrapper.getSystemService(Context.NOTIFICATION_SERVICE);
+    notificationManager.cancel(1959);
+    }
+
+    public void StartAlert(String sTitle, String sMsg)
+        {
+        // start the alert message
+        SendNotification(sTitle, sMsg);
+        }
+
+    public void StopAlert()
+        {
+        CancelNotification();
+        }
+
+    public String [] parseCmdLine2(String theCmdLine)
+        {
+        String    cmdString;
+        String    workingString;
+        String    workingString2;
+        String    workingString3;
+        List<String> lst = new ArrayList<String>();
+        int nLength = 0;
+        int nFirstSpace = -1;
+
+        // Null cmd line
+        if (theCmdLine == null)
+            {
+            String [] theArgs = new String [1];
+            theArgs[0] = new String("");
+            return(theArgs);
+            }
+        else
+            {
+            nLength = theCmdLine.length();
+            nFirstSpace = theCmdLine.indexOf(' ');
+            }
+
+        if (nFirstSpace == -1)
+            {
+            String [] theArgs = new String [1];
+            theArgs[0] = new String(theCmdLine);
+            return(theArgs);
+            }
+
+        // Get the command
+        cmdString = new String(theCmdLine.substring(0, nFirstSpace));
+        lst.add(cmdString);
+
+        // Jump past the command and trim
+        workingString = (theCmdLine.substring(nFirstSpace + 1, nLength)).trim();
+
+        while ((nLength = workingString.length()) > 0)
+            {
+            int nEnd = 0;
+            int    nStart = 0;
+
+            // if we have a quote
+            if (workingString.startsWith("\""))
+                {
+                // point to the first non quote char
+                nStart = 1;
+                // find the matching quote
+                nEnd = workingString.indexOf('"', nStart);
+
+                char prevChar;
+
+                while(nEnd != -1)
+                    {
+                    // check to see if the quotation mark has been escaped
+                    prevChar = workingString.charAt(nEnd - 1);
+                    if (prevChar == '\\')
+                        {
+                        // if escaped, point past this quotation mark and find the next
+                        nEnd++;
+                        if (nEnd < nLength)
+                            nEnd = workingString.indexOf('"', nEnd);
+                        else
+                            nEnd = -1;
+                        }
+                    else
+                        break;
+                    }
+
+                // there isn't one
+                if (nEnd == -1)
+                    {
+                    // point at the quote
+                    nStart = 0;
+                    // so find the next space
+                    nEnd = workingString.indexOf(' ', nStart);
+                    // there isn't one of those either
+                    if (nEnd == -1)
+                        nEnd = nLength;    // Just grab the rest of the cmdline
+                    }
+                }
+            else // no quote so find the next space
+                {
+                nEnd = workingString.indexOf(' ', nStart);
+                // there isn't one of those
+                if (nEnd == -1)
+                    nEnd = nLength;    // Just grab the rest of the cmdline
+                }
+
+            // get the substring
+            workingString2 = workingString.substring(nStart, nEnd);
+
+            // if we have escaped quotes
+            if (workingString2.contains("\\\""))
+                {
+                do
+                    {
+                    // replace escaped quote with embedded quote
+                    workingString3 = workingString2.replace("\\\"", "\"");
+                    workingString2 = workingString3;
+                    }
+                while(workingString2.contains("\\\""));
+                }
+
+            // add it to the list
+            lst.add(new String(workingString2));
+
+            // if we are dealing with a quote
+            if (nStart > 0)
+                nEnd++; //  point past the end one
+
+            // jump past the substring and trim it
+            workingString = (workingString.substring(nEnd)).trim();
+            }
+
+        // ok we're done package up the results
+        int nItems = lst.size();
+
+        String [] theArgs = new String [nItems];
+
+        for (int lcv = 0; lcv < nItems; lcv++)
+            {
+            theArgs[lcv] = lst.get(lcv);
+            }
+
+        return(theArgs);
+        }
+
+    public String [] parseCmdLine(String theCmdLine) {
+        String    cmdString;
+        String    workingString;
+        String    workingString2;
+        List<String> lst = new ArrayList<String>();
+        int nLength = 0;
+        int nFirstSpace = -1;
+
+        // Null cmd line
+        if (theCmdLine == null)
+            {
+            String [] theArgs = new String [1];
+            theArgs[0] = new String("");
+            return(theArgs);
+            }
+        else
+            {
+            nLength = theCmdLine.length();
+            nFirstSpace = theCmdLine.indexOf(' ');
+            }
+
+        if (nFirstSpace == -1)
+            {
+            String [] theArgs = new String [1];
+            theArgs[0] = new String(theCmdLine);
+            return(theArgs);
+            }
+
+        // Get the command
+        cmdString = new String(theCmdLine.substring(0, nFirstSpace));
+        lst.add(cmdString);
+
+        // Jump past the command and trim
+        workingString = (theCmdLine.substring(nFirstSpace + 1, nLength)).trim();
+
+        while ((nLength = workingString.length()) > 0)
+            {
+            int nEnd = 0;
+            int    nStart = 0;
+
+            // if we have a quote
+            if (workingString.startsWith("\""))
+                {
+                // point to the first non quote char
+                nStart = 1;
+                // find the matching quote
+                nEnd = workingString.indexOf('"', nStart);
+                // there isn't one
+                if (nEnd == -1)
+                    {
+                    // point at the quote
+                    nStart = 0;
+                    // so find the next space
+                    nEnd = workingString.indexOf(' ', nStart);
+                    // there isn't one of those either
+                    if (nEnd == -1)
+                        nEnd = nLength;    // Just grab the rest of the cmdline
+                    }
+                else
+                    {
+                    nStart = 0;
+                    nEnd++;
+                    }
+                }
+            else // no quote so find the next space
+                {
+                nEnd = workingString.indexOf(' ', nStart);
+
+                // there isn't one of those
+                if (nEnd == -1)
+                    nEnd = nLength;    // Just grab the rest of the cmdline
+                }
+
+            // get the substring
+            workingString2 = workingString.substring(nStart, nEnd);
+
+            // add it to the list
+            lst.add(new String(workingString2));
+
+            // jump past the substring and trim it
+            workingString = (workingString.substring(nEnd)).trim();
+            }
+
+        int nItems = lst.size();
+
+        String [] theArgs = new String [nItems];
+
+        for (int lcv = 0; lcv < nItems; lcv++)
+            {
+            theArgs[lcv] = lst.get(lcv);
+            }
+
+        return(theArgs);
+        }
+
+    public String fixFileName(String fileName)
+        {
+        String    sRet = "";
+        String    sTmpFileName = "";
+
+        sRet = fileName.replace('\\', '/');
+
+        if (sRet.startsWith("/"))
+            sTmpFileName = sRet;
+        else
+            sTmpFileName = currentDir + "/" + sRet;
+
+        sRet = sTmpFileName.replace('\\', '/');
+        sTmpFileName = sRet;
+        sRet = sTmpFileName.replace("//", "/");
+
+        return(sRet);
+        }
+
+    public String AddFilesToZip(ZipOutputStream out, String baseDir, String relDir)
+    {
+        final int             BUFFER     = 2048;
+        String                sRet    = "";
+        String                 curDir     = "";
+        String                relFN    = "";
+        BufferedInputStream origin = null;
+        byte                 data[] = new byte[BUFFER];
+
+        if (relDir.length() > 0)
+            curDir = baseDir + "/" + relDir;
+        else
+            curDir = baseDir;
+
+        File f = new File(curDir);
+
+        if (f.isFile())
+            {
+            try {
+                relFN = ((relDir.length() > 0) ? relDir + "/" + f.getName() : f.getName());
+                System.out.println("Adding: "+relFN);
+                sRet += "Adding: "+    relFN + lineSep;
+                FileInputStream fi = new FileInputStream(curDir);
+                origin = new BufferedInputStream(fi, BUFFER);
+                ZipEntry entry = new ZipEntry(relFN);
+                out.putNextEntry(entry);
+                int count;
+                while((count = origin.read(data, 0, BUFFER)) != -1)
+                    {
+                    out.write(data, 0, count);
+                    }
+                origin.close();
+                }
+            catch(Exception e)
+                {
+                e.printStackTrace();
+                }
+
+            return(sRet);
+            }
+
+        String    files[] = f.list();
+
+        if (files != null)
+            {
+            try {
+                for(int i = 0; i < files.length; i++)
+                    {
+                    f = new File(curDir + "/" + files[i]);
+                    if (f.isDirectory())
+                        {
+                        if (relDir.length() > 0)
+                            sRet += AddFilesToZip(out, baseDir, relDir + "/" + files[i]);
+                        else
+                            sRet += AddFilesToZip(out, baseDir, files[i]);
+                        }
+                    else
+                        {
+                        relFN = ((relDir.length() > 0) ? relDir + "/" + files[i] : files[i]);
+                        System.out.println("Adding: "+relFN);
+                        sRet += "Adding: "+    relFN + lineSep;
+                        FileInputStream fi = new FileInputStream(curDir + "/" + files[i]);
+                        origin = new BufferedInputStream(fi, BUFFER);
+                        ZipEntry entry = new ZipEntry(relFN);
+                        out.putNextEntry(entry);
+                        int count;
+                        while((count = origin.read(data, 0, BUFFER)) != -1)
+                            {
+                            out.write(data, 0, count);
+                            }
+                        origin.close();
+                        }
+                    }
+                }
+            catch(Exception e)
+                {
+                e.printStackTrace();
+                }
+            }
+
+        return(sRet);
+    }
+
+    public String Zip(String zipFileName, String srcName)
+        {
+        String    fixedZipFileName = fixFileName(zipFileName);
+        String    fixedSrcName = fixFileName(srcName);
+        String sRet = "";
+
+        try {
+            FileOutputStream dest = new FileOutputStream(fixedZipFileName);
+            CheckedOutputStream checksum = new CheckedOutputStream(dest, new Adler32());
+            ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(checksum));
+            out.setMethod(ZipOutputStream.DEFLATED);
+
+            sRet += AddFilesToZip(out, fixedSrcName, "");
+
+            out.close();
+            System.out.println("checksum:                   "+checksum.getChecksum().getValue());
+            sRet += "checksum:                   "+checksum.getChecksum().getValue();
+            }
+        catch(Exception e)
+            {
+            e.printStackTrace();
+            }
+
+        return(sRet);
+    }
+
+    public String Unzip(String zipFileName, String dstDirectory)
+        {
+        String     sRet = "";
+        String    fixedZipFileName = fixFileName(zipFileName);
+        String    fixedDstDirectory = fixFileName(dstDirectory);
+        String    dstFileName = "";
+        int        nNumExtracted = 0;
+        boolean bRet = false;
+
+        try {
+            final int BUFFER = 2048;
+            BufferedOutputStream dest = null;
+            ZipFile zipFile = new ZipFile(fixedZipFileName);
+            int nNumEntries = zipFile.size();
+            zipFile.close();
+
+            FileInputStream fis = new FileInputStream(fixedZipFileName);
+            CheckedInputStream checksum = new CheckedInputStream(fis, new Adler32());
+            ZipInputStream zis = new ZipInputStream(new BufferedInputStream(checksum));
+            ZipEntry entry;
+
+            byte [] data = new byte[BUFFER];
+
+            while((entry = zis.getNextEntry()) != null)
+                {
+                System.out.println("Extracting: " + entry);
+                int count;
+                if (fixedDstDirectory.length() > 0)
+                    dstFileName = fixedDstDirectory + entry.getName();
+                else
+                    dstFileName = entry.getName();
+
+                String tmpDir = dstFileName.substring(0, dstFileName.lastIndexOf('/'));
+                File tmpFile = new File(tmpDir);
+                if (!tmpFile.exists())
+                    {
+                    bRet = tmpFile.mkdirs();
+                    }
+                else
+                    bRet = true;
+
+                if (bRet)
+                    {
+                    // if we aren't just creating a directory
+                    if (dstFileName.lastIndexOf('/') != (dstFileName.length() - 1))
+                        {
+                        // write out the file
+                        FileOutputStream fos = new FileOutputStream(dstFileName);
+                        dest = new BufferedOutputStream(fos, BUFFER);
+                        while ((count = zis.read(data, 0, BUFFER)) != -1)
+                            {
+                            dest.write(data, 0, count);
+                            }
+                        dest.flush();
+                        dest.close();
+                        dest = null;
+                        fos.close();
+                        fos = null;
+                        }
+                    nNumExtracted++;
+                    }
+                else
+                    sRet += " - failed" + lineSep;
+                }
+
+            data = null;
+            zis.close();
+            System.out.println("Checksum:          "+checksum.getChecksum().getValue());
+            sRet += "Checksum:          "+checksum.getChecksum().getValue();
+            sRet += lineSep + nNumExtracted + " of " + nNumEntries + " sucessfully extracted";
+            }
+        catch(Exception e)
+            {
+            e.printStackTrace();
+            }
+
+        return(sRet);
+        }
+
+    public String StatProcess(String string)
+        {
+        String sRet = "";
+        ActivityManager aMgr = (ActivityManager) contextWrapper.getSystemService(Activity.ACTIVITY_SERVICE);
+        int    [] nPids = new int [1];
+
+        nPids[0] = Integer.parseInt(string);
+
+        android.os.Debug.MemoryInfo[] mi = aMgr.getProcessMemoryInfo(nPids);
+
+        sRet  = "Dalvik Private Dirty pages         " + mi[0].dalvikPrivateDirty     + " kb\n";
+        sRet += "Dalvik Proportional Set Size       " + mi[0].dalvikPss              + " kb\n";
+        sRet += "Dalvik Shared Dirty pages          " + mi[0].dalvikSharedDirty      + " kb\n\n";
+        sRet += "Native Private Dirty pages heap    " + mi[0].nativePrivateDirty     + " kb\n";
+        sRet += "Native Proportional Set Size heap  " + mi[0].nativePss              + " kb\n";
+        sRet += "Native Shared Dirty pages heap     " + mi[0].nativeSharedDirty      + " kb\n\n";
+        sRet += "Other Private Dirty pages          " + mi[0].otherPrivateDirty      + " kb\n";
+        sRet += "Other Proportional Set Size        " + mi[0].otherPss               + " kb\n";
+        sRet += "Other Shared Dirty pages           " + mi[0].otherSharedDirty       + " kb\n\n";
+        sRet += "Total Private Dirty Memory         " + mi[0].getTotalPrivateDirty() + " kb\n";
+        sRet += "Total Proportional Set Size Memory " + mi[0].getTotalPss()          + " kb\n";
+        sRet += "Total Shared Dirty Memory          " + mi[0].getTotalSharedDirty()  + " kb";
+
+
+        return(sRet);
+        }
+
+    public String GetTestRoot()
+        {
+        String    sRet = null;
+
+        if (Environment.getExternalStorageState().equalsIgnoreCase(Environment.MEDIA_MOUNTED))
+            {
+            sRet = Environment.getExternalStorageDirectory().getAbsolutePath();
+            }
+        else
+            {
+            sRet = GetTmpDir();
+            }
+
+        return(sRet);
+        }
+
+    public String GetAppRoot(String AppName)
+        {
+        String sRet = sErrorPrefix + " internal error [no context]";
+        Context ctx = contextWrapper.getApplicationContext();
+
+        if (ctx != null)
+            {
+            try {
+                Context appCtx = ctx.createPackageContext(AppName, 0);
+                ContextWrapper appCtxW = new ContextWrapper(appCtx);
+                sRet = appCtxW.getPackageResourcePath();
+                appCtxW = null;
+                appCtx = null;
+                ctx = null;
+                System.gc();
+                }
+            catch (NameNotFoundException e)
+                {
+                e.printStackTrace();
+                }
+            }
+        return(sRet);
+        }
+
+    public String isDirectory(String sDir)
+        {
+        String    sRet = sErrorPrefix + sDir + " does not exist";
+        String    tmpDir    = fixFileName(sDir);
+        String [] theArgs = new String [3];
+        int    nFiles = 0;
+
+        if (tmpDir.contains("org.mozilla.fennec") || tmpDir.contains("org.mozilla.firefox")) {
+            ContentResolver cr = contextWrapper.getContentResolver();
+            Uri ffxFiles = Uri.parse("content://" + (tmpDir.contains("fennec") ? fenProvider : ffxProvider) + "/dir");
+
+            String[] columns = new String[] {
+                    "_id",
+                    "isdir",
+                    "filename",
+                    "length"
+                };
+
+            Cursor myCursor = cr.query(    ffxFiles,
+                                        columns,     // Which columns to return
+                                        tmpDir,     // Which rows to return (all rows)
+                                        null,       // Selection arguments (none)
+                                        null);        // Order clause (none)
+            if (myCursor != null) {
+                nFiles = myCursor.getCount();
+
+                // If no entries the dir is empty
+                if (nFiles > 0) {
+                    if  (myCursor.moveToPosition(0)) {
+                        sRet = ((myCursor.getLong(myCursor.getColumnIndex("isdir")) == 1) ? "TRUE" : "FALSE");
+                    }
+                }
+                myCursor.close();
+            }
+        } else {
+            File tmpFile = new java.io.File(tmpDir);
+
+            if (tmpFile.exists()) {
+                sRet = (tmpFile.isDirectory() ? "TRUE" : "FALSE");
+            }
+            else {
+                try {
+                    theArgs[0] = "su";
+                    theArgs[1] = "-c";
+                    theArgs[2] = "ls -l " + sDir;
+
+                    pProc = Runtime.getRuntime().exec(theArgs);
+                    RedirOutputThread outThrd = new RedirOutputThread(pProc, null);
+                    outThrd.start();
+                    outThrd.join(5000);
+                    sRet = outThrd.strOutput;
+                    if (!sRet.contains("No such file or directory") && sRet.startsWith("l"))
+                        sRet = "FALSE";
+                }
+                catch (IOException e) {
+                    sRet = e.getMessage();
+                    e.printStackTrace();
+                }
+                catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+
+        return(sRet);
+        }
+
+
+    public String changeDir(String newDir)
+        {
+        String    tmpDir    = fixFileName(newDir);
+        String    sRet = sErrorPrefix + "Couldn't change directory to " + tmpDir;
+        int    nFiles = 0;
+
+        if (tmpDir.contains("org.mozilla.fennec") || tmpDir.contains("org.mozilla.firefox")) {
+            ContentResolver cr = contextWrapper.getContentResolver();
+            Uri ffxFiles = Uri.parse("content://" + (tmpDir.contains("fennec") ? fenProvider : ffxProvider) + "/dir");
+
+            String[] columns = new String[] {
+                    "_id",
+                    "isdir",
+                    "filename"
+                };
+
+            Cursor myCursor = cr.query(    ffxFiles,
+                                        columns,     // Which columns to return
+                                        tmpDir,     // Which rows to return (all rows)
+                                        null,       // Selection arguments (none)
+                                        null);        // Order clause (none)
+            if (myCursor != null) {
+                nFiles = myCursor.getCount();
+
+                if (nFiles > 0) {
+                    if  (myCursor.moveToPosition(0)) {
+                        if (myCursor.getLong(myCursor.getColumnIndex("isdir")) == 1) {
+                            currentDir = myCursor.getString(myCursor.getColumnIndex("filename"));
+                            sRet = "";
+                        }
+                    }
+                } else {
+                    sRet = sErrorPrefix + tmpDir + " is not a valid directory";
+                }
+                myCursor.close();
+            }
+        } else {
+            File tmpFile = new java.io.File(tmpDir);
+
+            if (tmpFile.exists()) {
+                try {
+                    if (tmpFile.isDirectory()) {
+                        currentDir = tmpFile.getCanonicalPath();
+                        sRet = "";
+                    }
+                else
+                    sRet = sErrorPrefix + tmpDir + " is not a valid directory";
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+
+        return(sRet);
+        }
+
+    static final String HEXES = "0123456789abcdef";
+
+    public static String getHex( byte [] raw )
+        {
+        if ( raw == null )
+            {
+            return null;
+            }
+
+        final StringBuilder hex = new StringBuilder( 2 * raw.length );
+        for ( final byte b : raw )
+            {
+            hex.append(HEXES.charAt((b & 0xF0) >> 4)).append(HEXES.charAt((b & 0x0F)));
+            }
+        return hex.toString();
+        }
+
+    public String HashFile(String fileName)
+        {
+        String            sTmpFileName = fixFileName(fileName);
+        String            sRet         = sErrorPrefix + "Couldn't calculate hash for file " + sTmpFileName;
+        byte[]             buffer         = new byte [4096];
+        int                nRead         = 0;
+        long             lTotalRead     = 0;
+        MessageDigest    digest         = null;
+
+        try {
+            digest = java.security.MessageDigest.getInstance("MD5");
+            }
+        catch (NoSuchAlgorithmException e)
+            {
+            e.printStackTrace();
+            }
+
+        if (sTmpFileName.contains("org.mozilla.fennec") || sTmpFileName.contains("org.mozilla.firefox")) {
+            ContentResolver cr = contextWrapper.getContentResolver();
+            Uri ffxFiles = null;
+
+            ffxFiles = Uri.parse("content://" + (sTmpFileName.contains("fennec") ? fenProvider : ffxProvider) + "/file");
+
+            String[] columns = new String[] {
+                    "_id",
+                    "chunk"
+                    };
+
+            Cursor myCursor = cr.query(    ffxFiles,
+                                        columns,         // Which columns to return
+                                        sTmpFileName,   // Which rows to return (all rows)
+                                        null,           // Selection arguments (none)
+                                        null);            // Order clause (none)
+            if (myCursor != null) {
+                int nRows = myCursor.getCount();
+                int nBytesRecvd = 0;
+
+                for (int lcv = 0; lcv < nRows; lcv++) {
+                    if  (myCursor.moveToPosition(lcv)) {
+                        byte [] buf = myCursor.getBlob(1);
+                        if (buf != null) {
+                            nBytesRecvd += buf.length;
+                            digest.update(buf, 0, buf.length);
+                            lTotalRead += nRead;
+                            buf = null;
+                        }
+                    }
+                }
+                myCursor.close();
+                byte [] hash = digest.digest();
+
+                sRet = getHex(hash);
+            }
+        } else {
+            try {
+                FileInputStream srcFile  = new FileInputStream(sTmpFileName);
+                while((nRead = srcFile.read(buffer)) != -1) {
+                    digest.update(buffer, 0, nRead);
+                    lTotalRead += nRead;
+                }
+                srcFile.close();
+                byte [] hash = digest.digest();
+
+                sRet = getHex(hash);
+            }
+            catch (FileNotFoundException e) {
+                sRet += " file not found";
+                e.printStackTrace();
+            }
+            catch (IOException e) {
+                sRet += " io exception";
+                e.printStackTrace();
+            }
+        }
+        return(sRet);
+    }
+
+    public String RemoveFile(String fileName)
+        {
+        String    sTmpFileName = fixFileName(fileName);
+        String    sRet = sErrorPrefix + "Couldn't delete file " + sTmpFileName;
+
+        if (sTmpFileName.contains("org.mozilla.fennec") || sTmpFileName.contains("org.mozilla.firefox")) {
+            ContentResolver cr = contextWrapper.getContentResolver();
+            Uri ffxFiles = Uri.parse("content://" + (sTmpFileName.contains("fennec") ? fenProvider : ffxProvider) + "/file");
+            if (cr.delete(ffxFiles, sTmpFileName, null) == 1) {
+                sRet = "deleted " + sTmpFileName;
+            }
+        } else {
+            File f = new File(sTmpFileName);
+
+            if (f.delete())
+                sRet = "deleted " + sTmpFileName;
+        }
+
+        return(sRet);
+        }
+
+    public String PruneDir(String sDir)
+        {
+        String    sRet = "";
+        int nFiles = 0;
+        String sSubDir = null;
+        String    sTmpDir = fixFileName(sDir);
+
+        if (sTmpDir.contains("org.mozilla.fennec") || sTmpDir.contains("org.mozilla.firefox")) {
+            ContentResolver cr = contextWrapper.getContentResolver();
+            Uri ffxFiles = Uri.parse("content://" + (sTmpDir.contains("fennec") ? fenProvider : ffxProvider) + "/dir");
+            if (cr.delete(ffxFiles, sTmpDir, null) > 0) {
+                sRet = "deleted " + sTmpDir;
+            }
+        } else {
+            File dir = new File(sTmpDir);
+
+            if (dir.isDirectory()) {
+                sRet = "Deleting file(s) from " + sTmpDir;
+
+                File [] files = dir.listFiles();
+                if (files != null) {
+                    if ((nFiles = files.length) > 0) {
+                        for (int lcv = 0; lcv < nFiles; lcv++) {
+                            if (files[lcv].isDirectory()) {
+                                sSubDir = files[lcv].getAbsolutePath();
+                                sRet += "\n" + PruneDir(sSubDir);
+                            }
+                            else {
+                                if (files[lcv].delete()) {
+                                sRet += "\n\tDeleted " + files[lcv].getName();
+                                }
+                                else {
+                                    sRet += "\n\tUnable to delete " + files[lcv].getName();
+                                }
+                            }
+                        }
+                    }
+                    else
+                        sRet += "\n\t<empty>";
+                }
+
+                if (dir.delete()) {
+                    sRet += "\nDeleting directory " + sTmpDir;
+                }
+                else {
+                    sRet += "\nUnable to delete directory " + sTmpDir;
+                }
+            }
+            else {
+                sRet += sErrorPrefix + sTmpDir + " is not a directory";
+            }
+        }
+
+        return(sRet);
+        }
+
+    public String PrintDir(String sDir)
+        {
+        String    sRet = "";
+        int nFiles = 0;
+        String    sTmpDir = fixFileName(sDir);
+
+        if (sTmpDir.contains("org.mozilla.fennec") || sTmpDir.contains("org.mozilla.firefox")) {
+            ContentResolver cr = contextWrapper.getContentResolver();
+            Uri ffxFiles = null;
+
+            ffxFiles = Uri.parse("content://" + (sTmpDir.contains("fennec") ? fenProvider : ffxProvider) + "/dir");
+
+            String[] columns = new String[] {
+                    "_id",
+                    "isdir",
+                    "filename",
+                    "length"
+                };
+
+            Cursor myCursor = cr.query(    ffxFiles,
+                                        columns,     // Which columns to return
+                                        sTmpDir,    // Which rows to return (all rows)
+                                        null,       // Selection arguments (none)
+                                        null);        // Order clause (none)
+            if (myCursor != null) {
+                nFiles = myCursor.getCount();
+
+                // If only one entry and the index is -1 this is not a directory
+                int nNdx = myCursor.getColumnIndex("_id");
+                // If no entries the dir is empty
+                if (nFiles == 1) {
+                    sRet = "<empty>";
+                } else {
+                    // Show the entries
+                    for (int lcv = 1; lcv < nFiles; lcv++) {
+                        if  (myCursor.moveToPosition(lcv)) {
+                            if ((lcv == 0) && (myCursor.getLong(nNdx) == -1)) {
+                                sRet = sErrorPrefix + sTmpDir + " is not a directory";
+                            } else {
+                                sRet += myCursor.getString(2);
+                                if (lcv < (nFiles - 1))
+                                    sRet += "\n";
+                            }
+                        }
+                    }
+                }
+                myCursor.close();
+            }
+        } else {
+            File dir = new File(sTmpDir);
+
+            if (dir.isDirectory()) {
+                File [] files = dir.listFiles();
+
+                if (files != null) {
+                    if ((nFiles = files.length) > 0) {
+                        for (int lcv = 0; lcv < nFiles; lcv++) {
+                            sRet += files[lcv].getName();
+                            if (lcv < (nFiles - 1)) {
+                                sRet += "\n";
+                            }
+                        }
+                    }
+                    else {
+                        sRet = "<empty>";
+                    }
+                }
+            }
+            else {
+                sRet = sErrorPrefix + sTmpDir + " is not a directory";
+            }
+        }
+        return(sRet);
+    }
+
+    public String Move(String sTmpSrcFileName, String sTmpDstFileName) {
+        String sRet = sErrorPrefix + "Could not move " + sTmpSrcFileName + " to " + sTmpDstFileName;
+        String sTmp = CopyFile(sTmpSrcFileName, sTmpDstFileName);
+        if (sTmp.contains(" copied to ")) {
+            sTmp = RemoveFile(sTmpSrcFileName);
+            if (sTmp.startsWith("deleted ")) {
+                sRet = sTmpSrcFileName + " moved to " + sTmpDstFileName;
+            }
+        }
+
+        return(sRet);
+    }
+
+    public String CopyFile(String sTmpSrcFileName, String sTmpDstFileName) {
+        String sRet = sErrorPrefix + "Could not copy " + sTmpSrcFileName + " to " + sTmpDstFileName;
+        ContentValues cv = null;
+        File destFile = null;
+        Uri ffxSrcFiles = null;
+        Uri ffxDstFiles = null;
+        FileInputStream srcFile  = null;
+        FileOutputStream dstFile  = null;
+        byte[] buffer = new byte [4096];
+        int    nRead = 0;
+        long lTotalRead = 0;
+        long lTotalWritten = 0;
+        ContentResolver crIn = null;
+        ContentResolver crOut = null;
+
+        if (sTmpSrcFileName.contains("org.mozilla.fennec") || sTmpSrcFileName.contains("org.mozilla.firefox")) {
+            ffxSrcFiles = Uri.parse("content://" + (sTmpSrcFileName.contains("fennec") ? fenProvider : ffxProvider) + "/file");
+            crIn = contextWrapper.getContentResolver();
+        } else {
+            try {
+                srcFile  = new FileInputStream(sTmpSrcFileName);
+            } catch (FileNotFoundException e) {
+                e.printStackTrace();
+            }
+        }
+
+        if (sTmpDstFileName.contains("org.mozilla.fennec") || sTmpDstFileName.contains("org.mozilla.firefox")) {
+            ffxDstFiles = Uri.parse("content://" + (sTmpDstFileName.contains("fennec") ? fenProvider : ffxProvider) + "/file");
+            crOut = contextWrapper.getContentResolver();
+            cv = new ContentValues();
+        } else {
+            try {
+                dstFile  = new FileOutputStream(sTmpDstFileName);
+            } catch (FileNotFoundException e) {
+                e.printStackTrace();
+            }
+        }
+
+        if (srcFile != null) {
+            try {
+                while((nRead = srcFile.read(buffer)) != -1)    {
+                    lTotalRead += nRead;
+                    if (dstFile != null) {
+                        dstFile.write(buffer, 0, nRead);
+                        dstFile.flush();
+                    } else {
+                        cv.put("length", nRead);
+                        cv.put("chunk", buffer);
+                        if (crOut.update(ffxDstFiles, cv, sTmpDstFileName, null) == 0)
+                            break;
+                        lTotalWritten += nRead;
+                    }
+                }
+
+                srcFile.close();
+
+                if (dstFile != null) {
+                    dstFile.flush();
+                    dstFile.close();
+
+                    destFile = new File(sTmpDstFileName);
+                    lTotalWritten = destFile.length();
+                }
+
+                if (lTotalWritten == lTotalRead) {
+                    sRet = sTmpSrcFileName + " copied to " + sTmpDstFileName;
+                }
+                else {
+                    sRet = sErrorPrefix + "Failed to copy " + sTmpSrcFileName + " [length = " + lTotalWritten + "] to " + sTmpDstFileName + " [length = " + lTotalRead + "]";
+                }
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+
+        } else {
+            String[] columns = new String[] {
+                    "_id",
+                    "chunk",
+                    "length"
+                    };
+
+            Cursor myCursor = crIn.query(ffxSrcFiles,
+                                        columns,             // Which columns to return
+                                        sTmpSrcFileName,       // Which rows to return (all rows)
+                                        null,               // Selection arguments (none)
+                                        null);                // Order clause (none)
+            if (myCursor != null) {
+                int nRows = myCursor.getCount();
+
+                byte [] buf = null;
+
+                for (int lcv = 0; lcv < nRows; lcv++) {
+                    if  (myCursor.moveToPosition(lcv)) {
+                        buf = myCursor.getBlob(myCursor.getColumnIndex("chunk"));
+                        if (buf != null) {
+                            nRead = buf.length;
+                            try {
+                                lTotalRead += nRead;
+                                if (dstFile != null) {
+                                    dstFile.write(buffer, 0, nRead);
+                                    dstFile.flush();
+                                } else {
+                                    cv.put("length", nRead);
+                                    cv.put("chunk", buffer);
+                                    if (crOut.update(ffxDstFiles, cv, sTmpDstFileName, null) == 0)
+                                        break;
+                                    lTotalWritten += nRead;
+                                }
+                            } catch (IOException e) {
+                                e.printStackTrace();
+                            }
+                            buf = null;
+                        }
+                    }
+                }
+
+                if (nRows == -1) {
+                    sRet = sErrorPrefix + sTmpSrcFileName + ",-1\nNo such file or directory";
+                }
+                else {
+                    myCursor.close();
+
+                    if (dstFile != null) {
+                        try {
+                            dstFile.flush();
+                            dstFile.close();
+
+                            destFile = new File(sTmpDstFileName);
+                            lTotalWritten = destFile.length();
+                        } catch (IOException e) {
+                            e.printStackTrace();
+                        }
+                    }
+
+                    if (lTotalWritten == lTotalRead) {
+                        sRet = sTmpSrcFileName + " copied to " + sTmpDstFileName;
+                    }
+                    else {
+                        sRet = sErrorPrefix + "Failed to copy " + sTmpSrcFileName + " [length = " + lTotalWritten + "] to " + sTmpDstFileName + " [length = " + lTotalRead + "]";
+                    }
+                }
+            }
+            else {
+                sRet = sErrorPrefix + sTmpSrcFileName + ",-1\nUnable to access file (internal error)";
+            }
+        }
+
+        return (sRet);
+    }
+
+    public String IsDirWritable(String sDir)
+        {
+        String    sTmpDir = fixFileName(sDir);
+        String sRet = sErrorPrefix + "[" + sTmpDir + "] is not a directory";
+
+        if (sTmpDir.contains("org.mozilla.fennec") || sTmpDir.contains("org.mozilla.firefox")) {
+            ContentResolver cr = contextWrapper.getContentResolver();
+            Uri ffxFiles = null;
+
+            ffxFiles = Uri.parse("content://" + (sTmpDir.contains("fennec") ? fenProvider : ffxProvider) + "/dir");
+
+            String[] columns = new String[] {
+                    "_id",
+                    "isdir",
+                    "filename",
+                    "length",
+                    "writable"
+                };
+
+            Cursor myCursor = cr.query(    ffxFiles,
+                                        columns,     // Which columns to return
+                                        sTmpDir,    // Which rows to return (all rows)
+                                        null,       // Selection arguments (none)
+                                        null);        // Order clause (none)
+            if (myCursor != null) {
+                if (myCursor.getCount() > 0) {
+                    if (myCursor.moveToPosition(0)) {
+                        if (myCursor.getLong(myCursor.getColumnIndex("isdir")) == 1) {
+                            sRet = "[" + sTmpDir + "] " + ((myCursor.getLong(myCursor.getColumnIndex("writable")) == 1) ? "is" : "is not") + " writable";
+                        }
+                    }
+                }
+            }
+        } else {
+            File dir = new File(sTmpDir);
+
+            if (dir.isDirectory()) {
+                sRet = "[" + sTmpDir + "] " + (dir.canWrite() ? "is" : "is not") + " writable";
+            } else {
+                sRet = sErrorPrefix + "[" + sTmpDir + "] is not a directory";
+            }
+        }
+        return(sRet);
+    }
+
+    public String Push(String fileName, BufferedInputStream bufIn, long lSize)
+    {
+        byte []                buffer             = new byte [8192];
+        int                    nRead            = 0;
+        long                lRead            = 0;
+        String                sTmpFileName     = fixFileName(fileName);
+        FileOutputStream     dstFile            = null;
+        ContentResolver     cr                 = null;
+        ContentValues        cv                = null;
+        Uri                 ffxFiles         = null;
+        String                sRet            = sErrorPrefix + "Push failed!";
+
+        try {
+            if (sTmpFileName.contains("org.mozilla.fennec") || sTmpFileName.contains("org.mozilla.firefox")) {
+                cr = contextWrapper.getContentResolver();
+                ffxFiles = Uri.parse("content://" + (sTmpFileName.contains("fennec") ? fenProvider : ffxProvider) + "/file");
+                cv = new ContentValues();
+            }
+            else {
+                dstFile = new FileOutputStream(sTmpFileName, false);
+            }
+
+            while((nRead != -1) && (lRead < lSize))
+                {
+                nRead = bufIn.read(buffer);
+                if (nRead != -1) {
+                    if (dstFile != null) {
+                        dstFile.write(buffer, 0, nRead);
+                        dstFile.flush();
+                    }
+                    else {
+                        cv.put("offset", lRead);
+                        cv.put("length", nRead);
+                        cv.put("chunk", buffer);
+                        cr.update(ffxFiles, cv, sTmpFileName, null);
+                    }
+                    lRead += nRead;
+                }
+            }
+
+            if (dstFile != null) {
+                dstFile.flush();
+                dstFile.close();
+            }
+
+            if (lRead == lSize)    {
+                sRet = HashFile(sTmpFileName);
+            }
+        }
+        catch (IOException e) {
+            e.printStackTrace();
+        }
+
+        buffer = null;
+
+        return(sRet);
+    }
+
+    public String FTPGetFile(String sServer, String sSrcFileName, String sDstFileName, OutputStream out)
+        {
+        byte[] buffer = new byte [4096];
+        int    nRead = 0;
+        long lTotalRead = 0;
+        String sRet = sErrorPrefix + "FTP Get failed for " + sSrcFileName;
+        String strRet = "";
+        int    reply = 0;
+        FileOutputStream outStream = null;
+        String    sTmpDstFileName = fixFileName(sDstFileName);
+
+        FTPClient ftp = new FTPClient();
+        try
+            {
+            ftp.connect(sServer);
+            reply = ftp.getReplyCode();
+            if(FTPReply.isPositiveCompletion(reply))
+                {
+                ftp.login("anonymous", "b@t.com");
+                reply = ftp.getReplyCode();
+                if(FTPReply.isPositiveCompletion(reply))
+                    {
+                    ftp.enterLocalPassiveMode();
+                    if (ftp.setFileType(FTP.BINARY_FILE_TYPE))
+                        {
+                        File dstFile = new File(sTmpDstFileName);
+                        outStream = new FileOutputStream(dstFile);
+                        FTPFile [] ftpFiles = ftp.listFiles(sSrcFileName);
+                        if (ftpFiles.length > 0)
+                            {
+                            long lFtpSize = ftpFiles[0].getSize();
+                            if (lFtpSize <= 0)
+                                lFtpSize = 1;
+
+                            InputStream ftpIn = ftp.retrieveFileStream(sSrcFileName);
+                            while ((nRead = ftpIn.read(buffer)) != -1)
+                                {
+                                lTotalRead += nRead;
+                                outStream.write(buffer, 0, nRead);
+                                strRet = "\r" + lTotalRead + " of " + lFtpSize + " bytes received " + ((lTotalRead * 100) / lFtpSize) + "% completed";
+                                out.write(strRet.getBytes());
+                                out.flush();
+                                }
+                            ftpIn.close();
+                            @SuppressWarnings("unused")
+                            boolean bRet = ftp.completePendingCommand();
+                            outStream.flush();
+                            outStream.close();
+                            strRet = ftp.getReplyString();
+                            reply = ftp.getReplyCode();
+                            }
+                        else
+                            {
+                            strRet = sRet;
+                            }
+                        }
+                    ftp.logout();
+                    ftp.disconnect();
+                    sRet = "\n" + strRet;
+                    }
+                else
+                    {
+                    ftp.disconnect();
+                    System.err.println("FTP server refused login.");
+                    }
+                }
+            else
+                {
+                ftp.disconnect();
+                System.err.println("FTP server refused connection.");
+                }
+            }
+        catch (SocketException e)
+            {
+            sRet = e.getMessage();
+            strRet = ftp.getReplyString();
+            reply = ftp.getReplyCode();
+            sRet += "\n" + strRet;
+            e.printStackTrace();
+            }
+        catch (IOException e)
+            {
+            sRet = e.getMessage();
+            strRet = ftp.getReplyString();
+            reply = ftp.getReplyCode();
+            sRet += "\n" + strRet;
+            e.printStackTrace();
+            }
+        return (sRet);
+    }
+
+    public String Pull(String fileName, long lOffset, long lLength, OutputStream out)
+        {
+        String    sTmpFileName = fixFileName(fileName);
+        String    sRet = sErrorPrefix + "Could not read the file " + sTmpFileName;
+        byte[]    buffer = new byte [4096];
+        int        nRead = 0;
+        long    lSent = 0;
+
+        if (sTmpFileName.contains("org.mozilla.fennec") || sTmpFileName.contains("org.mozilla.firefox")) {
+            ContentResolver cr = contextWrapper.getContentResolver();
+            Uri ffxFiles = null;
+
+            ffxFiles = Uri.parse("content://" + (sTmpFileName.contains("fennec") ? fenProvider : ffxProvider) + "/file");
+
+            String[] columns = new String[] {
+                    "_id",
+                    "chunk",
+                    "length"
+                    };
+
+            String [] args = new String [2];
+            args[0] = Long.toString(lOffset);
+            args[1] = Long.toString(lLength);
+
+            Cursor myCursor = cr.query(    ffxFiles,
+                                        columns,         // Which columns to return
+                                        sTmpFileName,   // Which rows to return (all rows)
+                                        args,           // Selection arguments (none)
+                                        null);            // Order clause (none)
+            if (myCursor != null) {
+                int nRows = myCursor.getCount();
+                long lFileLength = 0;
+
+                for (int lcv = 0; lcv < nRows; lcv++) {
+                    if  (myCursor.moveToPosition(lcv)) {
+                        if (lcv == 0) {
+                            lFileLength = myCursor.getLong(2);
+                            String sTmp = sTmpFileName + "," + lFileLength + "\n";
+                            try {
+                                out.write(sTmp.getBytes());
+                            } catch (IOException e) {
+                                e.printStackTrace();
+                                break;
+                            }
+                        }
+
+                        if (lLength != 0) {
+                            byte [] buf = myCursor.getBlob(1);
+                            if (buf != null) {
+                                nRead = buf.length;
+                                try {
+                                    if ((lSent + nRead) <= lFileLength)    {
+                                        out.write(buf,0,nRead);
+                                        lSent += nRead;
+                                    }
+                                    else {
+                                        nRead = (int) (lFileLength - lSent);
+                                        out.write(buf,0,nRead);
+                                        Log.d("pull warning", "more bytes read than expected");
+                                        break;
+                                    }
+                                } catch (IOException e) {
+                                    e.printStackTrace();
+                                    sRet = sErrorPrefix + "Could not write to out " + sTmpFileName;
+                                }
+                                buf = null;
+                            }
+                        }
+                    }
+                }
+                if (nRows == 0) {
+                    String sTmp = sTmpFileName + "," + lFileLength + "\n";
+                    try {
+                        out.write(sTmp.getBytes());
+                    } catch (IOException e) {
+                        e.printStackTrace();
+                    }
+                }
+                if (nRows == -1) {
+                    sRet = sErrorPrefix + sTmpFileName + ",-1\nNo such file or directory";
+                }
+                else {
+                    myCursor.close();
+                    sRet = "";
+                }
+            }
+            else {
+                sRet = sErrorPrefix + sTmpFileName + ",-1\nUnable to access file (internal error)";
+            }
+        }
+        else {
+            try {
+                File f = new File(sTmpFileName);
+                long lFileLength = f.length();
+                FileInputStream fin = new FileInputStream(f);
+                if (lFileLength == 0) {
+                    while ((nRead = fin.read(buffer)) != -1) {
+                        lFileLength += nRead;
+                    }
+                    fin.close();
+                    fin = new FileInputStream(f);
+                }
+
+                // lLength == -1 return everything between lOffset and eof
+                // lLength == 0 return file length
+                // lLength > 0 return lLength bytes
+                if (lLength == -1) {
+                    lFileLength = lFileLength - lOffset;
+                } else if (lLength == 0) {
+                    // just return the file length
+                } else {
+                    lFileLength = ((lLength <= (lFileLength - lOffset)) ? lLength : (lFileLength - lOffset));
+                }
+
+                String sTmp = sTmpFileName + "," + lFileLength + "\n";
+                out.write(sTmp.getBytes());
+                if (lLength != 0) {
+                    if  (lOffset > 0) {
+                        fin.skip(lOffset);
+                    }
+                    while ((nRead = fin.read(buffer)) != -1) {
+                        if ((lSent + nRead) <= lFileLength)    {
+                            out.write(buffer,0,nRead);
+                            lSent += nRead;
+                        }
+                        else {
+                            nRead = (int) (lFileLength - lSent);
+                            out.write(buffer,0,nRead);
+                            if (lLength != -1)
+                                Log.d("pull warning", "more bytes read than sent");
+                            break;
+                        }
+                    }
+                }
+                fin.close();
+                out.flush();
+                sRet = "";
+                }
+            catch (FileNotFoundException e)    {
+                sRet = sErrorPrefix + sTmpFileName + ",-1\nNo such file or directory";
+            }
+            catch (IOException e) {
+                sRet = e.toString();
+            }
+        }
+        return (sRet);
+    }
+
+    public String Cat(String fileName, OutputStream out)
+        {
+        String    sTmpFileName = fixFileName(fileName);
+        String    sRet = sErrorPrefix + "Could not read the file " + sTmpFileName;
+        byte[]    buffer = new byte [4096];
+        int        nRead = 0;
+
+        if (sTmpFileName.contains("org.mozilla.fennec") || sTmpFileName.contains("org.mozilla.firefox")) {
+            ContentResolver cr = contextWrapper.getContentResolver();
+            Uri ffxFiles = null;
+
+            ffxFiles = Uri.parse("content://" + (sTmpFileName.contains("fennec") ? fenProvider : ffxProvider) + "/file");
+
+            String[] columns = new String[] {
+                    "_id",
+                    "chunk"
+                    };
+
+            Cursor myCursor = cr.query(    ffxFiles,
+                                        columns,         // Which columns to return
+                                        sTmpFileName,   // Which rows to return (all rows)
+                                        null,           // Selection arguments (none)
+                                        null);            // Order clause (none)
+            if (myCursor != null) {
+                int nRows = myCursor.getCount();
+                int nBytesRecvd = 0;
+
+                for (int lcv = 0; lcv < nRows; lcv++) {
+                    if  (myCursor.moveToPosition(lcv)) {
+                        byte [] buf = myCursor.getBlob(1);
+                        if (buf != null) {
+                            nBytesRecvd += buf.length;
+                            try {
+                                out.write(buf);
+                                sRet = "";
+                            } catch (IOException e) {
+                                e.printStackTrace();
+                                sRet = sErrorPrefix + "Could not write to out " + sTmpFileName;
+                            }
+                            buf = null;
+                        }
+                    }
+                }
+                if (nRows == 0) {
+                    sRet = "";
+                }
+
+                myCursor.close();
+            }
+        } else {
+            try {
+                FileInputStream fin = new FileInputStream(sTmpFileName);
+                while ((nRead = fin.read(buffer)) != -1) {
+                    out.write(buffer,0,nRead);
+                }
+                fin.close();
+                out.flush();
+                sRet = "";
+                }
+            catch (FileNotFoundException e) {
+                sRet = sErrorPrefix + sTmpFileName + " No such file or directory";
+            }
+            catch (IOException e) {
+                sRet = e.toString();
+            }
+        }
+        return (sRet);
+    }
+
+    public String MakeDir(String sDir)
+        {
+        String    sTmpDir = fixFileName(sDir);
+        String sRet = sErrorPrefix + "Could not create the directory " + sTmpDir;
+        if (sTmpDir.contains("org.mozilla.fennec") || sTmpDir.contains("org.mozilla.firefox")) {
+            ContentResolver cr = contextWrapper.getContentResolver();
+            Uri ffxFiles = Uri.parse("content://" + (sTmpDir.contains("fennec") ? fenProvider : ffxProvider) + "/dir");
+            ContentValues cv = new ContentValues();
+
+            if (cr.update(ffxFiles, cv, sTmpDir, null) == 1) {
+                sRet = sDir + " successfully created";
+            }
+        }
+        else {
+            File dir = new File(sTmpDir);
+
+            if (dir.mkdirs())
+                sRet = sDir + " successfully created";
+        }
+
+        return (sRet);
+        }
+    // move this to SUTAgentAndroid.java
+    public String GetScreenInfo()
+        {
+        String sRet = "";
+        DisplayMetrics metrics = new DisplayMetrics();
+        WindowManager wMgr = (WindowManager) contextWrapper.getSystemService(Context.WINDOW_SERVICE);
+        wMgr.getDefaultDisplay().getMetrics(metrics);
+        sRet = "X:" + metrics.widthPixels + " Y:" + metrics.heightPixels;
+        return (sRet);
+        }
+    // move this to SUTAgentAndroid.java
+    public int [] GetScreenXY()
+        {
+            int [] nRetXY = new int [2];
+            DisplayMetrics metrics = new DisplayMetrics();
+            WindowManager wMgr = (WindowManager) contextWrapper.getSystemService(Context.WINDOW_SERVICE);
+            wMgr.getDefaultDisplay().getMetrics(metrics);
+            nRetXY[0] = metrics.widthPixels;
+            nRetXY[1] = metrics.heightPixels;
+            return(nRetXY);
+        }
+
+    public String SetADB(String sWhat) {
+        String sRet = "";
+        String sTmp = "";
+        String [] theArgs = new String [3];
+
+        theArgs[0] = "su";
+        theArgs[1] = "-c";
+
+        if (sWhat.contains("ip")) {
+            theArgs[2] = "setprop service.adb.tcp.port 5555";
+        } else {
+            theArgs[2] = "setprop service.adb.tcp.port -1";
+        }
+
+        try {
+            pProc = Runtime.getRuntime().exec(theArgs);
+            RedirOutputThread outThrd = new RedirOutputThread(pProc, null);
+            outThrd.start();
+            outThrd.join(5000);
+            sTmp = outThrd.strOutput;
+            Log.e("ADB", sTmp);
+            if (outThrd.nExitCode == 0) {
+                theArgs[2] = "stop adbd";
+                pProc = Runtime.getRuntime().exec(theArgs);
+                outThrd = new RedirOutputThread(pProc, null);
+                outThrd.start();
+                outThrd.join(5000);
+                sTmp = outThrd.strOutput;
+                Log.e("ADB", sTmp);
+                if (outThrd.nExitCode == 0) {
+                    theArgs[2] = "start adbd";
+                    pProc = Runtime.getRuntime().exec(theArgs);
+                    outThrd = new RedirOutputThread(pProc, null);
+                    outThrd.start();
+                    outThrd.join(5000);
+                    sTmp = outThrd.strOutput;
+                    Log.e("ADB", sTmp);
+                    if (outThrd.nExitCode == 0) {
+                        sRet = "Successfully set adb to " + sWhat + "\n";
+                    } else {
+                        sRet = sErrorPrefix + "Failed to start adbd\n";
+                    }
+                } else {
+                    sRet = sErrorPrefix + "Failed to stop adbd\n";
+                }
+            } else {
+                sRet = sErrorPrefix + "Failed to setprop service.adb.tcp.port 5555\n";
+            }
+
+        }
+    catch (IOException e)
+        {
+        sRet = e.getMessage();
+        e.printStackTrace();
+        }
+    catch (InterruptedException e)
+        {
+        e.printStackTrace();
+        }
+        return(sRet);
+    }
+
+    public String KillProcess(String sProcName, OutputStream out)
+        {
+        String sTmp = "";
+        String [] theArgs = new String [3];
+
+        theArgs[0] = "su";
+        theArgs[1] = "-c";
+        theArgs[2] = "kill";
+
+        String sRet = sErrorPrefix + "Unable to kill " + sProcName + "\n";
+        ActivityManager aMgr = (ActivityManager) contextWrapper.getSystemService(Activity.ACTIVITY_SERVICE);
+        List <ActivityManager.RunningAppProcessInfo> lProcesses = aMgr.getRunningAppProcesses();
+        int lcv = 0;
+        String strProcName = "";
+        int    nPID = 0;
+
+        for (lcv = 0; lcv < lProcesses.size(); lcv++)
+            {
+            if (lProcesses.get(lcv).processName.contains(sProcName))
+                {
+                strProcName = lProcesses.get(lcv).processName;
+                nPID = lProcesses.get(lcv).pid;
+                sRet = sErrorPrefix + "Failed to kill " + nPID + " " + strProcName + "\n";
+
+                theArgs[2] += " " + nPID;
+
+                try
+                    {
+                    pProc = Runtime.getRuntime().exec(theArgs);
+                    RedirOutputThread outThrd = new RedirOutputThread(pProc, null);
+                    outThrd.start();
+                    outThrd.join(15000);
+                    sTmp = outThrd.strOutput;
+                    Log.e("KILLPROCESS", sTmp);
+                    if (outThrd.nExitCode == 0) {
+                        sRet = "Successfully killed " + nPID + " " + strProcName + "\n";
+                        nPID = 0;
+                        break;
+                    } else {
+                        sRet = sErrorPrefix + "Failed to kill " + nPID + " " + strProcName + "\n";
+                    }
+                    }
+                catch (IOException e)
+                    {
+                    sRet = e.getMessage();
+                    e.printStackTrace();
+                    }
+                catch (InterruptedException e)
+                    {
+                    e.printStackTrace();
+                    }
+
+                // Give the messages a chance to be processed
+                try {
+                    Thread.sleep(2000);
+                    }
+                catch (InterruptedException e)
+                    {
+                    e.printStackTrace();
+                    }
+                break;
+                }
+            }
+
+        if (nPID > 0)
+            {
+            sRet = "Successfully killed " + nPID + " " + strProcName + "\n";
+            lProcesses = aMgr.getRunningAppProcesses();
+            for (lcv = 0; lcv < lProcesses.size(); lcv++)
+                {
+                if (lProcesses.get(lcv).processName.contains(sProcName))
+                    {
+                    sRet = sErrorPrefix + "Unable to kill " + nPID + " " + strProcName + "\n";
+                    break;
+                    }
+                }
+            }
+
+        return (sRet);
+        }
+
+    public boolean IsProcessDead(String sProcName)
+        {
+        boolean bRet = false;
+        ActivityManager aMgr = (ActivityManager) contextWrapper.getSystemService(Activity.ACTIVITY_SERVICE);
+        List <ActivityManager.ProcessErrorStateInfo> lProcesses = aMgr.getProcessesInErrorState();
+        int lcv = 0;
+
+        if (lProcesses != null)
+            {
+            for (lcv = 0; lcv < lProcesses.size(); lcv++)
+                {
+                if (lProcesses.get(lcv).processName.contentEquals(sProcName) &&
+                    lProcesses.get(lcv).condition != ActivityManager.ProcessErrorStateInfo.NO_ERROR)
+                    {
+                    bRet = true;
+                    break;
+                    }
+                }
+            }
+
+        return (bRet);
+        }
+
+    public String GetProcessInfo()
+        {
+        String sRet = "";
+        ActivityManager aMgr = (ActivityManager) contextWrapper.getSystemService(Activity.ACTIVITY_SERVICE);
+        List <ActivityManager.RunningAppProcessInfo> lProcesses = aMgr.getRunningAppProcesses();
+        int    nProcs = lProcesses.size();
+        int lcv = 0;
+        String strProcName = "";
+        int    nPID = 0;
+        int nUser = 0;
+
+        for (lcv = 0; lcv < nProcs; lcv++)
+            {
+            strProcName = lProcesses.get(lcv).processName;
+            nPID = lProcesses.get(lcv).pid;
+            nUser = lProcesses.get(lcv).uid;
+            sRet += nUser + "\t" + nPID + "\t" + strProcName;
+            if (lcv < (nProcs - 1))
+                sRet += "\n";
+            }
+
+        return (sRet);
+        }
+
+    public String GetOSInfo()
+        {
+        String sRet = "";
+
+        sRet = Build.DISPLAY;
+
+        return (sRet);
+        }
+
+    public String GetPowerInfo()
+        {
+        String sRet = "";
+
+        sRet = "Power status:\n  AC power " + SUTAgentAndroid.sACStatus + "\n";
+        sRet += "  Battery charge " + SUTAgentAndroid.sPowerStatus + "\n";
+        sRet += "  Remaining charge:      " + SUTAgentAndroid.nChargeLevel + "%\n";
+        sRet += "  Battery Temperature:   " + (((float)(SUTAgentAndroid.nBatteryTemp))/10) + " (c)\n";
+        return (sRet);
+        }
+
+    // todo
+    public String GetDiskInfo(String sPath)
+        {
+        String sRet = "";
+        StatFs statFS = new StatFs(sPath);
+
+        int nBlockCount = statFS.getBlockCount();
+        int nBlockSize = statFS.getBlockSize();
+        int nBlocksAvail = statFS.getAvailableBlocks();
+        int nBlocksFree = statFS.getFreeBlocks();
+
+        sRet = "total:     " + (nBlockCount * nBlockSize) + "\nfree:      " + (nBlocksFree * nBlockSize) + "\navailable: " + (nBlocksAvail * nBlockSize);
+
+        return (sRet);
+        }
+
+    public String GetMemoryInfo()
+        {
+        String sRet = "PA:" + GetMemoryConfig();
+        return (sRet);
+        }
+
+    public long GetMemoryConfig()
+        {
+        ActivityManager aMgr = (ActivityManager) contextWrapper.getSystemService(Activity.ACTIVITY_SERVICE);
+        ActivityManager.MemoryInfo outInfo = new ActivityManager.MemoryInfo();
+        aMgr.getMemoryInfo(outInfo);
+        long lMem = outInfo.availMem;
+
+        return (lMem);
+        }
+
+    public String UpdateCallBack(String sFileName)
+        {
+        String sRet = sErrorPrefix + "No file specified";
+        String sIP = "";
+        String sPort = "";
+        int nEnd = 0;
+        int nStart = 0;
+
+        if ((sFileName == null) || (sFileName.length() == 0))
+            return(sRet);
+
+        Context ctx = contextWrapper.getApplicationContext();
+        try {
+            FileInputStream fis = ctx.openFileInput(sFileName);
+            int nBytes = fis.available();
+            if (nBytes > 0)
+                {
+                byte [] buffer = new byte [nBytes + 1];
+                int nRead = fis.read(buffer, 0, nBytes);
+                fis.close();
+                ctx.deleteFile(sFileName);
+                if (nRead > 0)
+                    {
+                    String sBuffer = new String(buffer);
+                    nEnd = sBuffer.indexOf(',');
+                    if (nEnd > 0)
+                        {
+                        sIP = (sBuffer.substring(0, nEnd)).trim();
+                        nStart = nEnd + 1;
+                        nEnd = sBuffer.indexOf('\r', nStart);
+                        if (nEnd > 0)
+                            {
+                            sPort = (sBuffer.substring(nStart, nEnd)).trim();
+                            Thread.sleep(5000);
+                            sRet = RegisterTheDevice(sIP, sPort, sBuffer.substring(nEnd + 1));
+                            }
+                        }
+                    }
+                }
+            }
+        catch (FileNotFoundException e)
+            {
+            sRet = sErrorPrefix + "Nothing to do";
+            }
+        catch (IOException e)
+            {
+            sRet = sErrorPrefix + "Couldn't send info to " + sIP + ":" + sPort;
+            }
+        catch (InterruptedException e)
+            {
+            e.printStackTrace();
+            }
+        return(sRet);
+        }
+
+    public String RegisterTheDevice(String sSrvr, String sPort, String sData)
+        {
+        String sRet = "";
+        String line = "";
+
+//        Debug.waitForDebugger();
+
+        if (sSrvr != null && sPort != null && sData != null)
+            {
+            try
+                {
+                int nPort = Integer.parseInt(sPort);
+                Socket socket = new Socket(sSrvr, nPort);
+                PrintWriter out = new PrintWriter(socket.getOutputStream(), false);
+                BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
+                out.println(sData);
+                if ( out.checkError() == false )
+                    {
+                    socket.setSoTimeout(30000);
+                    while (socket.isInputShutdown() == false)
+                        {
+                        line = in.readLine();
+
+                        if (line != null)
+                            {
+                            line = line.toLowerCase();
+                            sRet += line;
+                            // ok means we're done
+                            if (line.contains("ok"))
+                                break;
+                            }
+                        else
+                            {
+                            // end of stream reached
+                            break;
+                            }
+                        }
+                    }
+                out.close();
+                in.close();
+                socket.close();
+                }
+            catch(NumberFormatException e)
+                {
+                sRet += "reg NumberFormatException thrown [" + e.getLocalizedMessage() + "]";
+                e.printStackTrace();
+                }
+            catch (UnknownHostException e)
+                {
+                sRet += "reg UnknownHostException thrown [" + e.getLocalizedMessage() + "]";
+                e.printStackTrace();
+                }
+            catch (IOException e)
+                {
+                sRet += "reg IOException thrown [" + e.getLocalizedMessage() + "]";
+                e.printStackTrace();
+                }
+            }
+        return(sRet);
+        }
+
+    public String GetInternetData(String sHost, String sPort, String sURL)
+        {
+        String sRet = "";
+        String sNewURL = "";
+        HttpClient httpClient = new DefaultHttpClient();
+        try
+            {
+            sNewURL = "http://" + sHost + ((sPort.length() > 0) ? (":" + sPort) : "") + sURL;
+
+            HttpGet request = new HttpGet(sNewURL);
+            HttpResponse response = httpClient.execute(request);
+            int status = response.getStatusLine().getStatusCode();
+            // we assume that the response body contains the error message
+            if (status != HttpStatus.SC_OK)
+                {
+                ByteArrayOutputStream ostream = new ByteArrayOutputStream();
+                response.getEntity().writeTo(ostream);
+                Log.e("HTTP CLIENT", ostream.toString());
+                }
+            else
+                {
+                InputStream content = response.getEntity().getContent();
+                byte [] data = new byte [2048];
+                int nRead = content.read(data);
+                sRet = new String(data, 0, nRead);
+                content.close(); // this will also close the connection
+                }
+            }
+        catch (IllegalArgumentException e)
+            {
+            sRet = e.getLocalizedMessage();
+            e.printStackTrace();
+            }
+        catch (ClientProtocolException e)
+            {
+            sRet = e.getLocalizedMessage();
+            e.printStackTrace();
+            }
+        catch (IOException e)
+            {
+            sRet = e.getLocalizedMessage();
+            e.printStackTrace();
+            }
+
+        return(sRet);
+        }
+
+    public String GetTimeZone()
+        {
+        String    sRet = "";
+        TimeZone tz;
+
+        tz = TimeZone.getDefault();
+        Date now = new Date();
+        sRet = tz.getDisplayName(tz.inDaylightTime(now), TimeZone.LONG);
+
+        return(sRet);
+        }
+
+    public String SetTimeZone(String sTimeZone)
+        {
+        String            sRet = "Unable to set timezone to " + sTimeZone;
+        TimeZone         tz = null;
+        AlarmManager     amgr = null;
+
+        if ((sTimeZone.length() > 0) && (sTimeZone.startsWith("GMT")))
+            {
+            amgr = (AlarmManager) contextWrapper.getSystemService(Context.ALARM_SERVICE);
+            if (amgr != null)
+                amgr.setTimeZone(sTimeZone);
+            }
+        else
+            {
+            String [] zoneNames = TimeZone.getAvailableIDs();
+            int nNumMatches = zoneNames.length;
+            int    lcv = 0;
+
+            for (lcv = 0; lcv < nNumMatches; lcv++)
+                {
+                if (zoneNames[lcv].equalsIgnoreCase(sTimeZone))
+                    break;
+                }
+
+            if (lcv < nNumMatches)
+                {
+                amgr = (AlarmManager) contextWrapper.getSystemService(Context.ALARM_SERVICE);
+                if (amgr != null)
+                    amgr.setTimeZone(zoneNames[lcv]);
+                }
+            }
+
+        if (amgr != null)
+            {
+            tz = TimeZone.getDefault();
+            Date now = new Date();
+            sRet = tz.getDisplayName(tz.inDaylightTime(now), TimeZone.LONG);
+            }
+
+        return(sRet);
+        }
+
+    public String GetSystemTime()
+        {
+        String sRet = "";
+        Calendar cal = Calendar.getInstance();
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss:SSS");
+        sRet = sdf.format(cal.getTime());
+
+        return (sRet);
+        }
+
+    public String SetSystemTime(String sDate, String sTime, OutputStream out) {
+        String sRet = "";
+        String sM = "";
+        String sMillis = "";
+        String [] theArgs = new String [3];
+
+        theArgs[0] = "su";
+        theArgs[1] = "-c";
+
+        if (((sDate != null) && (sTime != null)) &&
+            (sDate.contains("/") || sDate.contains(".")) &&
+            (sTime.contains(":"))) {
+            int year = Integer.parseInt(sDate.substring(0,4));
+            int month = Integer.parseInt(sDate.substring(5,7));
+            int day = Integer.parseInt(sDate.substring(8,10));
+
+            int hour = Integer.parseInt(sTime.substring(0,2));
+            int mins = Integer.parseInt(sTime.substring(3,5));
+            int secs = Integer.parseInt(sTime.substring(6,8));
+
+            Calendar cal = new GregorianCalendar(TimeZone.getDefault());
+            cal.set(year, month - 1, day, hour, mins, secs);
+            long lMillisecs = cal.getTime().getTime();
+
+            sM = Long.toString(lMillisecs);
+            sMillis = sM.substring(0, sM.length() - 3) + "." + sM.substring(sM.length() - 3);
+
+        } else if ((sDate != null) && (sTime == null) && sDate.contains(".")) {
+            String serverName = sDate;
+//            String serverName = "us.pool.ntp.org";
+            sRet = "NTP Server: " + serverName + lineSep;
+            // Send request
+            DatagramSocket socket;
+
+            try {
+                socket = new DatagramSocket();
+                InetAddress address = InetAddress.getByName(serverName);
+                byte[] buf = new NtpMessage().toByteArray();
+                DatagramPacket packet = new DatagramPacket(buf, buf.length, address, 123);
+
+                // Set the transmit timestamp *just* before sending the packet
+                // ToDo: Does this actually improve performance or not?
+                NtpMessage.encodeTimestamp(packet.getData(), 40, (System.currentTimeMillis()/1000.0) + 2208988800.0);
+
+                socket.send(packet);
+
+                // Get response
+                System.out.println("NTP request sent, waiting for response...\n");
+                packet = new DatagramPacket(buf, buf.length);
+                socket.receive(packet);
+
+                // Immediately record the incoming timestamp since 00:00 1-JAN-1900 in secs.
+                double destinationTimestamp = (System.currentTimeMillis()/1000.0) + 2208988800.0;
+
+                // Process response
+                NtpMessage msg = new NtpMessage(packet.getData());
+
+                // Corrected, according to RFC2030 errata
+                double roundTripDelay = (destinationTimestamp-msg.originateTimestamp) - (msg.transmitTimestamp-msg.receiveTimestamp);
+
+                double localClockOffset = ((msg.receiveTimestamp - msg.originateTimestamp) + (msg.transmitTimestamp - destinationTimestamp)) / 2;
+
+                // convert base of timestamp from 00:00 1900/01/01 to 00:00:00 1970/01/01
+                double utc = msg.transmitTimestamp - (2208988800.0);
+
+                // convert from secs to ms
+                long lNewMillisecs = (long)(utc * 1000.0);
+
+                // create a date object using the timestamp this will take into account the timezone and daylight savings settings
+                Date dt = new Date(lNewMillisecs);
+
+                sRet += "  Time: " + new SimpleDateFormat("yyyy/MM/dd hh:mm:ss:SSS").format(dt) + lineSep;
+
+                // get the timestamp
+                long lMillisecs = dt.getTime();
+
+                // format the timestamp as required for the date command
+                sM = Long.toString(lMillisecs);
+                sMillis = sM.substring(0, sM.length() - 3) + "." + sM.substring(sM.length() - 3);
+
+                socket.close();
+            } catch (SocketException e) {
+                e.printStackTrace();
+            } catch (UnknownHostException e) {
+                e.printStackTrace();
+                sRet = sErrorPrefix + "Unknown host";
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        } else {
+            sRet += "Invalid argument(s)";
+        }
+
+        // if we have an argument
+        if (sMillis.length() > 0) {
+            theArgs[2] = "date -u " + sMillis;
+
+            try {
+                pProc = Runtime.getRuntime().exec(theArgs);
+                RedirOutputThread outThrd = new RedirOutputThread(pProc, null);
+                outThrd.start();
+                outThrd.join(10000);
+                sRet += GetSystemTime();
+            } catch (IOException e) {
+                sRet = e.getMessage();
+                e.printStackTrace();
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+        }
+
+        return (sRet);
+    }
+
+    public String GetClok()
+        {
+        long lMillisecs = System.currentTimeMillis();
+        String sRet = "";
+
+        if (lMillisecs > 0)
+            sRet = Long.toString(lMillisecs);
+
+        return(sRet);
+        }
+
+    public String GetUptime()
+        {
+        String sRet = "";
+        long lHold = 0;
+        long lUptime = SystemClock.elapsedRealtime();
+        int    nDays = 0;
+        int    nHours = 0;
+        int nMinutes = 0;
+        int nSecs = 0;
+        int nMilliseconds = 0;
+
+        if (lUptime > 0)
+            {
+            nDays = (int)(lUptime / (24L * 60L * 60L * 1000L));
+            lHold = lUptime % (24L * 60L * 60L * 1000L);
+            nHours = (int)(lHold / (60L * 60L * 1000L));
+            lHold %= 60L * 60L * 1000L;
+            nMinutes = (int)(lHold / (60L * 1000L));
+            lHold %= 60L * 1000L;
+            nSecs = (int)(lHold / 1000L);
+            nMilliseconds = (int)(lHold % 1000);
+            sRet = "" + nDays + " days " + nHours + " hours " + nMinutes + " minutes " + nSecs + " seconds " + nMilliseconds + " ms";
+            }
+
+        return (sRet);
+        }
+
+    public String NewKillProc(String sProcId, OutputStream out)
+        {
+        String sRet = "";
+        String [] theArgs = new String [3];
+
+        theArgs[0] = "su";
+        theArgs[1] = "-c";
+        theArgs[2] = "kill " + sProcId;
+
+        try
+            {
+            pProc = Runtime.getRuntime().exec(theArgs);
+            RedirOutputThread outThrd = new RedirOutputThread(pProc, out);
+            outThrd.start();
+            outThrd.join(5000);
+            }
+        catch (IOException e)
+            {
+            sRet = e.getMessage();
+            e.printStackTrace();
+            }
+        catch (InterruptedException e)
+            {
+            e.printStackTrace();
+            }
+
+        return(sRet);
+        }
+
+    public String SendPing(String sIPAddr, OutputStream out)
+        {
+        String sRet = "";
+        String [] theArgs = new String [4];
+
+        theArgs[0] = "ping";
+        theArgs[1] = "-c";
+        theArgs[2] = "3";
+        theArgs[3] = sIPAddr;
+
+        try
+            {
+            pProc = Runtime.getRuntime().exec(theArgs);
+            RedirOutputThread outThrd = new RedirOutputThread(pProc, out);
+            outThrd.start();
+            outThrd.join(5000);
+            if (out == null)
+                sRet = outThrd.strOutput;
+            }
+        catch (IOException e)
+            {
+            sRet = e.getMessage();
+            e.printStackTrace();
+            }
+        catch (InterruptedException e)
+            {
+            e.printStackTrace();
+            }
+
+        return (sRet);
+        }
+
+    public String GetTmpDir()
+    {
+        String     sRet = "";
+        Context ctx = contextWrapper.getApplicationContext();
+        File dir = ctx.getFilesDir();
+        ctx = null;
+        try {
+            sRet = dir.getCanonicalPath();
+            }
+        catch (IOException e)
+            {
+            e.printStackTrace();
+            }
+        return(sRet);
+    }
+
+    public String PrintFileTimestamp(String sFile)
+        {
+        String     sRet = "";
+        String    sTmpFileName = fixFileName(sFile);
+        long    lModified = -1;
+
+        if (sTmpFileName.contains("org.mozilla.fennec") || sTmpFileName.contains("org.mozilla.firefox")) {
+            ContentResolver cr = contextWrapper.getContentResolver();
+            Uri ffxFiles = Uri.parse("content://" + (sTmpFileName.contains("fennec") ? fenProvider : ffxProvider) + "/dir");
+
+            String[] columns = new String[] {
+                    "_id",
+                    "isdir",
+                    "filename",
+                    "length",
+                    "ts"
+                };
+
+            Cursor myCursor = cr.query(    ffxFiles,
+                                        columns,         // Which columns to return
+                                        sTmpFileName,   // Which rows to return (all rows)
+                                        null,           // Selection arguments (none)
+                                        null);            // Order clause (none)
+            if (myCursor != null) {
+                if (myCursor.getCount() > 0) {
+                    if (myCursor.moveToPosition(0)) {
+                        lModified = myCursor.getLong(myCursor.getColumnIndex("ts"));
+                    }
+                }
+                myCursor.close();
+            }
+        }
+        else {
+            File theFile = new File(sTmpFileName);
+
+            if (theFile.exists()) {
+                lModified = theFile.lastModified();
+            }
+        }
+
+        if (lModified != -1) {
+            Date dtModified = new Date(lModified);
+            SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss:SSS");
+            sRet = "Last modified: " + sdf.format(dtModified);
+        }
+        else {
+            sRet = sErrorPrefix + "[" + sTmpFileName + "] doesn't exist";
+        }
+
+        return(sRet);
+        }
+
+    public String GetIniData(String sSection, String sKey, String sFile)
+        {
+        String sRet = "";
+        String sComp = "";
+        String sLine = "";
+        boolean bFound = false;
+        BufferedReader in = null;
+        String    sTmpFileName = fixFileName(sFile);
+
+        try {
+            in = new BufferedReader(new FileReader(sTmpFileName));
+            sComp = "[" + sSection + "]";
+            while ((sLine = in.readLine()) != null)
+                {
+                if (sLine.equalsIgnoreCase(sComp))
+                    {
+                    bFound = true;
+                    break;
+                    }
+                }
+
+            if (bFound)
+                {
+                sComp = (sKey + " =").toLowerCase();
+                while ((sLine = in.readLine()) != null)
+                    {
+                    if (sLine.toLowerCase().contains(sComp))
+                        {
+                        String [] temp = null;
+                        temp = sLine.split("=");
+                        if (temp != null)
+                            {
+                            if (temp.length > 1)
+                                sRet = temp[1].trim();
+                            }
+                        break;
+                        }
+                    }
+                }
+            in.close();
+            }
+        catch (FileNotFoundException e)
+            {
+            sComp = e.toString();
+            }
+        catch (IOException e)
+            {
+            sComp = e.toString();
+            }
+        return (sRet);
+        }
+
+    public String RunReboot(OutputStream out, String sCallBackIP, String sCallBackPort)
+        {
+        String sRet = "";
+        Context ctx = contextWrapper.getApplicationContext();
+        String [] theArgs = new String [3];
+
+        theArgs[0] = "su";
+        theArgs[1] = "-c";
+        theArgs[2] = "reboot";
+        try {
+            if ((sCallBackIP != null) && (sCallBackPort != null) &&
+                (sCallBackIP.length() > 0) && (sCallBackPort.length() > 0))    {
+                FileOutputStream fos = ctx.openFileOutput("update.info", Context.MODE_WORLD_READABLE | Context.MODE_WORLD_WRITEABLE);
+                String sBuffer = sCallBackIP + "," + sCallBackPort + "\rSystem rebooted\r";
+                fos.write(sBuffer.getBytes());
+                fos.flush();
+                fos.close();
+                fos = null;
+            }
+        } catch (FileNotFoundException e) {
+            sRet = sErrorPrefix + "Callback file creation error [rebt] call failed " + e.getMessage();
+            e.printStackTrace();
+        } catch (IOException e) {
+            sRet = sErrorPrefix + "Callback file error [rebt] call failed " + e.getMessage();
+            e.printStackTrace();
+        }
+
+        try {
+            // Tell all of the data channels we are rebooting
+            ((ASMozStub)this.contextWrapper).SendToDataChannel("Rebooting ...");
+
+            pProc = Runtime.getRuntime().exec(theArgs);
+            RedirOutputThread outThrd = new RedirOutputThread(pProc, out);
+            outThrd.start();
+            outThrd.join(10000);
+        } catch (IOException e) {
+            sRet = e.getMessage();
+            e.printStackTrace();
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+
+        return (sRet);
+        }
+
+    public String UnInstallApp(String sApp, OutputStream out)
+        {
+        String sRet = "";
+        String [] theArgs = new String [3];
+
+        theArgs[0] = "su";
+        theArgs[1] = "-c";
+        theArgs[2] = "pm uninstall " + sApp + ";reboot;exit";
+
+        try
+            {
+            pProc = Runtime.getRuntime().exec(theArgs);
+
+            RedirOutputThread outThrd = new RedirOutputThread(pProc, out);
+            outThrd.start();
+            outThrd.join(60000);
+            int nRet = pProc.exitValue();
+            sRet = "\nuninst complete [" + nRet + "]";
+            }
+        catch (IOException e)
+            {
+            sRet = e.getMessage();
+            e.printStackTrace();
+            }
+        catch (InterruptedException e)
+            {
+            e.printStackTrace();
+            }
+
+        return (sRet);
+    }
+
+    public String InstallApp(String sApp, OutputStream out)
+        {
+        String sRet = "";
+        String [] theArgs = new String [3];
+        File    srcFile = new File(sApp);
+
+        theArgs[0] = "su";
+        theArgs[1] = "-c";
+        theArgs[2] = "mv " + GetTmpDir() + "/" + srcFile.getName() + " /data/local/tmp/" + srcFile.getName() + ";exit";
+
+        sRet = CopyFile(sApp, GetTmpDir() + "/" + srcFile.getName());
+        try {
+            out.write(sRet.getBytes());
+            out.flush();
+            }
+        catch (IOException e1)
+            {
+            e1.printStackTrace();
+            }
+
+        try
+            {
+            pProc = Runtime.getRuntime().exec(theArgs);
+
+            RedirOutputThread outThrd = new RedirOutputThread(pProc, out);
+            outThrd.start();
+            outThrd.join(90000);
+            int nRet = pProc.exitValue();
+            sRet = "\nmove complete [" + nRet + "]";
+            try
+                {
+                out.write(sRet.getBytes());
+                out.flush();
+                }
+            catch (IOException e1)
+                {
+                e1.printStackTrace();
+                }
+
+            theArgs[2] = "chmod 666 /data/local/tmp/" + srcFile.getName() + ";exit";
+            pProc = Runtime.getRuntime().exec(theArgs);
+            RedirOutputThread outThrd2 = new RedirOutputThread(pProc, out);
+            outThrd2.start();
+            outThrd2.join(10000);
+            int nRet2 = pProc.exitValue();
+            sRet = "\npermission change complete [" + nRet2 + "]\n";
+            try {
+                out.write(sRet.getBytes());
+                out.flush();
+                }
+            catch (IOException e1)
+                {
+                e1.printStackTrace();
+                }
+
+            theArgs[2] = "pm install -r /data/local/tmp/" + srcFile.getName() + " Cleanup" + ";exit";
+            pProc = Runtime.getRuntime().exec(theArgs);
+            RedirOutputThread outThrd3 = new RedirOutputThread(pProc, out);
+            outThrd3.start();
+            outThrd3.join(60000);
+            int nRet3 = pProc.exitValue();
+            sRet = "\ninstallation complete [" + nRet3 + "]";
+            try {
+                out.write(sRet.getBytes());
+                out.flush();
+                }
+            catch (IOException e1)
+                {
+                e1.printStackTrace();
+                }
+
+            theArgs[2] = "rm /data/local/tmp/" + srcFile.getName() + ";exit";
+            pProc = Runtime.getRuntime().exec(theArgs);
+            RedirOutputThread outThrd4 = new RedirOutputThread(pProc, out);
+            outThrd4.start();
+            outThrd4.join(60000);
+            int nRet4 = pProc.exitValue();
+            sRet = "\ntmp file removed [" + nRet4 + "]";
+            try {
+                out.write(sRet.getBytes());
+                out.flush();
+                }
+            catch (IOException e1)
+                {
+                e1.printStackTrace();
+                }
+            sRet = "\nSuccess";
+            }
+        catch (IOException e)
+            {
+            sRet = e.getMessage();
+            e.printStackTrace();
+            }
+        catch (InterruptedException e)
+            {
+            e.printStackTrace();
+            }
+
+        return (sRet);
+        }
+
+    public String StrtUpdtOMatic(String sPkgName, String sPkgFileName, String sCallBackIP, String sCallBackPort)
+        {
+        String sRet = "";
+
+        Context ctx = contextWrapper.getApplicationContext();
+        PackageManager pm = ctx.getPackageManager();
+
+        Intent prgIntent = new Intent();
+        prgIntent.setPackage("com.mozilla.watcher");
+
+        try {
+            PackageInfo pi = pm.getPackageInfo("com.mozilla.watcher", PackageManager.GET_SERVICES | PackageManager.GET_INTENT_FILTERS);
+            ServiceInfo [] si = pi.services;
+            for (int i = 0; i < si.length; i++)
+                {
+                ServiceInfo s = si[i];
+                if (s.name.length() > 0)
+                    {
+                    prgIntent.setClassName(s.packageName, s.name);
+                    break;
+                    }
+                }
+            }
+        catch (NameNotFoundException e)
+            {
+            e.printStackTrace();
+            sRet = sErrorPrefix + "watcher is not properly installed";
+            return(sRet);
+            }
+
+        prgIntent.putExtra("command", "updt");
+        prgIntent.putExtra("pkgName", sPkgName);
+        prgIntent.putExtra("pkgFile", sPkgFileName);
+        prgIntent.putExtra("reboot", true);
+
+        try
+            {
+            if ((sCallBackIP != null) && (sCallBackPort != null) &&
+                (sCallBackIP.length() > 0) && (sCallBackPort.length() > 0))
+                {
+                FileOutputStream fos = ctx.openFileOutput("update.info", Context.MODE_WORLD_READABLE | Context.MODE_WORLD_WRITEABLE);
+                String sBuffer = sCallBackIP + "," + sCallBackPort + "\rupdate started " + sPkgName + " " + sPkgFileName + "\r";
+                fos.write(sBuffer.getBytes());
+                fos.flush();
+                fos.close();
+                fos = null;
+                prgIntent.putExtra("outFile", ctx.getFilesDir() + "/update.info");
+                }
+            else {
+                if (prgIntent.hasExtra("outFile")) {
+                    System.out.println("outFile extra unset from intent");
+                    prgIntent.removeExtra("outFile");
+                }
+            }
+
+            ComponentName cn = contextWrapper.startService(prgIntent);
+            if (cn != null)
+                sRet = "exit";
+            else
+                sRet = sErrorPrefix + "Unable to use watcher service";
+            }
+        catch(ActivityNotFoundException anf)
+            {
+            sRet = sErrorPrefix + "Activity Not Found Exception [updt] call failed";
+            anf.printStackTrace();
+            }
+        catch (FileNotFoundException e)
+            {
+            sRet = sErrorPrefix + "File creation error [updt] call failed";
+            e.printStackTrace();
+            }
+        catch (IOException e)
+            {
+            sRet = sErrorPrefix + "File error [updt] call failed";
+            e.printStackTrace();
+            }
+
+        ctx = null;
+
+        return (sRet);
+        }
+
+    public String StartJavaPrg(String [] sArgs, Intent preIntent)
+        {
+        String sRet = "";
+        String sArgList = "";
+        String sUrl = "";
+//        String sRedirFileName = "";
+        Intent prgIntent = null;
+
+        Context ctx = contextWrapper.getApplicationContext();
+        PackageManager pm = ctx.getPackageManager();
+
+        if (preIntent == null)
+            prgIntent = new Intent();
+        else
+            prgIntent = preIntent;
+
+        prgIntent.setPackage(sArgs[0]);
+        prgIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+        try {
+            PackageInfo pi = pm.getPackageInfo(sArgs[0], PackageManager.GET_ACTIVITIES | PackageManager.GET_INTENT_FILTERS);
+            ActivityInfo [] ai = pi.activities;
+            for (int i = 0; i < ai.length; i++)
+                {
+                ActivityInfo a = ai[i];
+                if (a.name.length() > 0)
+                    {
+                    prgIntent.setClassName(a.packageName, a.name);
+                    break;
+                    }
+                }
+            }
+        catch (NameNotFoundException e)
+            {
+            e.printStackTrace();
+            }
+
+        if (sArgs.length > 1)
+            {
+            if (sArgs[0].contains("android.browser"))
+                prgIntent.setAction(Intent.ACTION_VIEW);
+            else
+                prgIntent.setAction(Intent.ACTION_MAIN);
+
+            if (sArgs[0].contains("fennec"))
+                {
+                sArgList = "";
+                sUrl = "";
+
+                for (int lcv = 1; lcv < sArgs.length; lcv++)
+                    {
+                    if (sArgs[lcv].contains("://"))
+                        {
+                        prgIntent.setAction(Intent.ACTION_VIEW);
+                        sUrl = sArgs[lcv];
+                        }
+                    else
+                        {
+                        if (sArgs[lcv].equals(">"))
+                            {
+                            lcv++;
+                            if (lcv < sArgs.length)
+                                lcv++;
+//                                sRedirFileName = sArgs[lcv++];
+                            }
+                        else
+                            sArgList += " " + sArgs[lcv];
+                        }
+                    }
+
+                if (sArgList.length() > 0)
+                    prgIntent.putExtra("args", sArgList.trim());
+
+                if (sUrl.length() > 0)
+                    prgIntent.setData(Uri.parse(sUrl.trim()));
+                }
+            else
+                {
+                for (int lcv = 1; lcv < sArgs.length; lcv++)
+                    sArgList += " " + sArgs[lcv];
+
+                prgIntent.setData(Uri.parse(sArgList.trim()));
+                }
+            }
+        else
+            {
+            prgIntent.setAction(Intent.ACTION_MAIN);
+            }
+
+        try
+            {
+            contextWrapper.startActivity(prgIntent);
+            }
+        catch(ActivityNotFoundException anf)
+            {
+            anf.printStackTrace();
+            }
+
+        ctx = null;
+        return (sRet);
+        }
+
+    public String StartPrg(String [] progArray, OutputStream out)
+        {
+        String sRet = "";
+
+        try
+            {
+            pProc = Runtime.getRuntime().exec(progArray);
+            RedirOutputThread outThrd = new RedirOutputThread(pProc, out);