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