New interactive functions to send commands to a device.

This is still a bit crude but now we can remount,sync,reboot and flash
a device from emacs.

Support product aliases.
diff --git a/ide/emacs/android-common.el b/ide/emacs/android-common.el
index a4cd1e5..8988598 100644
--- a/ide/emacs/android-common.el
+++ b/ide/emacs/android-common.el
@@ -1,20 +1,34 @@
-;;;
-;;; Copyright (C) 2009 The Android Open Source Project
-;;;
-;;; Licensed under the Apache License, Version 2.0 (the "License");
-;;; you may not use this file except in compliance with the License.
-;;; You may obtain a copy of the License at
-;;;
-;;;      http://www.apache.org/licenses/LICENSE-2.0
-;;;
-;;; Unless required by applicable law or agreed to in writing, software
-;;; distributed under the License is distributed on an "AS IS" BASIS,
-;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-;;; See the License for the specific language governing permissions and
-;;; limitations under the License.
+;;; android-common.el --- Common functions/variables to dev Android in Emacs.
+;;
+;; Copyright (C) 2009 The Android Open Source Project
+;;
+;; Licensed under the Apache License, Version 2.0 (the "License");
+;; you may not use this file except in compliance with the License.
+;; You may obtain a copy of the License at
+;;
+;;      http://www.apache.org/licenses/LICENSE-2.0
+;;
+;; Unless required by applicable law or agreed to in writing, software
+;; distributed under the License is distributed on an "AS IS" BASIS,
+;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+;; See the License for the specific language governing permissions and
+;; limitations under the License.
 
-;;; Variables to customize and common function for the android build
-;;; support in Emacs.
+;;; Commentary:
+;;
+;; Variables to customize and common functions for the Android build
+;; support in Emacs.
+;; There should be no interactive function in this module.
+;;
+;; You need to have a proper buildspec.mk file in your root directory
+;; for this module to work (see $TOP/build/buildspec.mk.default).
+;; If the path the product's files/image uses an a product alias, you
+;; need to add a mapping in `android-product-alias-map'. For instance
+;; if TARGET_PRODUCT is foo but the build directory is out/target/product/bar,
+;; you need to add a mapping Target:foo -> Alias:bar
+;;
+
+;;; Code:
 
 (defgroup android nil
   "Support for android development in Emacs."
@@ -26,26 +40,122 @@
   :type 'integer
   :group 'android)
 
+;;;###autoload
+(defcustom android-product-alias-map nil
+  "Alist between product targets (declared in buildspec.mk) and actual
+ product build directory used by `android-product'.
+
+For instance if TARGET_PRODUCT is 'foo' but the build directory
+ is 'out/target/product/bar', you need to add a mapping Target:foo -> Alias:bar."
+  :type '(repeat (list (string :tag "Target")
+                       (string :tag "Alias")))
+  :group 'android)
+
 (defun android-find-build-tree-root ()
   "Ascend the current path until the root of the android build tree is found.
 Similarly to the shell functions in envsetup.sh, for the root both ./Makefile
 and ./build/core/envsetup.mk are exiting files.
-Return the root of the build tree. Signal an error if not found."
+Return the root of the build tree.  Signal an error if not found."
   (let ((default-directory default-directory))
     (while (and (> (length default-directory) 2)
-                (not (file-exists-p (concat default-directory "Makefile")))
-                (not (file-exists-p (concat default-directory "build/core/envsetup.mk"))))
+                (not (file-exists-p (concat default-directory
+                                            "Makefile")))
+                (not (file-exists-p (concat default-directory
+                                            "build/core/envsetup.mk"))))
       (setq default-directory
             (substring default-directory 0
                        (string-match "[^/]+/$" default-directory))))
     (if (> (length default-directory) 2)
         default-directory
-      (error "Not in a valid android tree."))))
+      (error "Not in a valid android tree"))))
 
 (defun android-project-p ()
-"Return nil if not in an android build tree."
+  "Return nil if not in an android build tree."
   (condition-case nil
       (android-find-build-tree-root)
     (error nil)))
 
+(defun android-host ()
+  "Return the <system>-<arch> string (e.g linux-x86).
+Only linux and darwin on x86 architectures are supported."
+  (or (string-match "x86" system-configuration)
+      (string-match "i386" system-configuration)
+      (error "Unknown arch"))
+  (or (and (string-match "darwin" system-configuration) "darwin-x86")
+      (and (string-match "linux" system-configuration) "linux-x86")
+      (error "Unknown system")))
+
+(defun android-product ()
+  "Return the product built according to the buildspec.mk.
+You must have buildspec.mk file in the top directory.
+
+Additional product aliases can be listed in `android-product-alias-map'
+if the product actually built is different from the one listed
+in buildspec.mk"
+  (save-excursion
+    (let* ((buildspec (concat (android-find-build-tree-root) "buildspec.mk"))
+           (product (with-current-buffer (find-file-noselect buildspec)
+                      (goto-char (point-min))
+                      (search-forward "TARGET_PRODUCT:=")
+                      (buffer-substring-no-properties (point)
+                                                      (scan-sexps (point) 1))))
+           (alias (assoc product android-product-alias-map)))
+      ; Post processing, adjust the names.
+      (if (not alias)
+          product
+        (nth 1 alias)))))
+
+(defun android-product-path ()
+  "Return the full path to the product directory.
+
+Additional product aliases can be added in `android-product-alias-map'
+if the product actually built is different from the one listed
+in buildspec.mk"
+  (let ((path (concat (android-find-build-tree-root) "out/target/product/"
+                      (android-product))))
+    (when (not (file-exists-p path))
+      (error (format "%s does not exist. If product %s maps to another one,
+add an entry to android-product-map." path (android-product))))
+    path))
+
+(defun android-find-host-bin (binary)
+  "Return the full path to the host BINARY.
+Binaries don't depend on the device, just on the host type.
+Try first to locate BINARY in the out/host tree.  Fallback using
+the shell exec PATH setup."
+  (if (android-project-p)
+      (let ((path (concat (android-find-build-tree-root) "out/host/"
+                          (android-host) "/bin/" binary)))
+        (if (file-exists-p path)
+            path
+          (error (concat binary " is missing."))))
+    (executable-find binary)))
+
+(defun android-adb ()
+  "Return the path to the adb executable.
+If not in the build tree use the PATH env variable."
+  (android-find-host-bin "adb"))
+
+(defun android-fastboot ()
+  "Return the path to the fastboot executable.
+If not in the build tree use the PATH env variable."
+  ; For fastboot -p is the name of the product, *not* the full path to
+  ; its directory like adb requests sometimes.
+  (concat (android-find-host-bin "fastboot") " -p " (android-product)))
+
+(defun android-adb-command (command &optional product)
+  "Execute 'adb COMMAND'.
+If the optional PRODUCT is not nil, -p (android-product-path) is used
+when adb is invoked."
+  (if product
+      (shell-command (concat (android-adb) " -p " (android-product-path)
+                             " " command))
+    (shell-command (concat (android-adb) " " command))))
+
+(defun android-adb-shell-command (command)
+  "Execute 'adb shell COMMAND'."
+  (android-adb-command (concat " shell " command)))
+
 (provide 'android-common)
+
+;;; android-common.el ends here
diff --git a/ide/emacs/android-host.el b/ide/emacs/android-host.el
new file mode 100644
index 0000000..9b9fe9d
--- /dev/null
+++ b/ide/emacs/android-host.el
@@ -0,0 +1,114 @@
+;;; android-host.el --- Module to use host binaries from an Android dev tree.
+;;
+;; Copyright (C) 2009 The Android Open Source Project
+;;
+;; Licensed under the Apache License, Version 2.0 (the "License");
+;; you may not use this file except in compliance with the License.
+;; You may obtain a copy of the License at
+;;
+;;      http://www.apache.org/licenses/LICENSE-2.0
+;;
+;; Unless required by applicable law or agreed to in writing, software
+;; distributed under the License is distributed on an "AS IS" BASIS,
+;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+;; See the License for the specific language governing permissions and
+;; limitations under the License.
+
+;;; Commentary:
+;;
+;; This module defines interactive functions to send the most common
+;; commands to a device.
+;;
+;; Currently only one device is supported.
+;;
+;; In your .emacs load this file (e.g (require 'android-host)) then
+;; you can either create new shortcuts e.g:
+;;
+;;   (global-set-key [f8] 'android-adb-sync)
+;;
+;; or rely on autocompletion M-x and-sync will expand to
+;; M-x  android-adb-sync
+;;
+;; By default the following key bindings are active:
+;; C-x a a android-adb-root
+;; C-x a r android-adb-remount
+;; C-x a s android-adb-sync
+;; C-x a b android-adb-shell-reboot-bootloader
+;; C-x a f android-fastboot-flashall
+;;
+;; android-fastboot-flashall is still work in progress, check the
+;; associated buffer (*Fastboot*) for errors when you use it.
+
+;;; Code:
+
+(require 'android-common)
+
+(defvar android-host-command-map (make-sparse-keymap))
+
+(defun android-host-key-prefix-set (var val)
+  "Bind the keys shortcuts to the functions.i"
+  ;; TODO: This should go in a minor mode keymap instead of
+  ;; messing with the global one.
+  (define-key global-map (read-kbd-macro val) android-host-command-map)
+  (custom-set-default var val))
+
+(let ((map android-host-command-map))
+  (define-key map (kbd "a") 'android-adb-root)
+  (define-key map (kbd "r") 'android-adb-remount)
+  (define-key map (kbd "s") 'android-adb-sync)
+  (define-key map (kbd "b") 'android-adb-shell-reboot-bootloader)
+  (define-key map (kbd "f") 'android-fastboot-flashall))
+
+(defcustom android-host-key-prefix "C-x a"
+  "Prefix keystrokes for Android commands."
+  :group 'android
+  :type 'string
+  :set 'android-host-key-prefix-set)
+
+(defun android-adb-remount ()
+  "Execute 'adb remount'."
+  (interactive)
+  (android-adb-command "remount"))
+
+(defun android-adb-root ()
+  "Execute 'adb root'."
+  (interactive)
+  (android-adb-command "root"))
+
+(defun android-adb-shell-reboot-bootloader ()
+  "Execute 'adb shell reboot bootloader'."
+  (interactive)
+  (android-adb-shell-command "reboot bootloader"))
+
+(defun android-adb-sync ()
+  "Execute 'adb sync'."
+  (interactive)
+  (android-adb-command "sync" 'p))
+
+(defun android-fastboot-sentinel (process event)
+  "Called when the fastboot process is done."
+  ;; TODO: Should barf if the last lines are not:
+  ;;   OKAY
+  ;;   rebooting...
+  (princ
+   (format "Process: %s had the event `%s'" process event)))
+
+(defun android-fastboot-flashall (arg)
+  "Execute 'fastboot -p <product> flashall'.
+
+With no ARG, don't wipe the user data.
+With ARG, wipe the user data."
+  (interactive "P")
+  (when (get-buffer "*Fastboot*")
+    (with-current-buffer "*Fastboot*" (erase-buffer)))
+  (let ((proc
+         (if arg
+             (start-process-shell-command
+              "fastboot" "*Fastboot*" (concat (android-fastboot) " flashall -w"))
+           (start-process-shell-command
+            "fastboot" "*Fastboot*" (concat (android-fastboot) " flashall")))))
+    (set-process-sentinel proc 'android-fastboot-sentinel)))
+
+
+(provide 'android-host)
+;;; android-host.el ends here