Linux
Android and Java |
Common Programs Web Medicine |
Type | Description | Example |
Absolute | A specific cell independent of location of the referencing cell | $A$1 |
Absolute Column, Relative Row | A cell in a specific column, and in a row relative to the referencing cell | $A1 |
Absolute Row, Relative Column | A cell in a specific row, and in a column relative to the referencing cell | A$1 |
Relative | A cell in a relative row and column to the referencing cell | A1 |
Once you have a cell with a formula, you can select it and drag the outline to fill a column or row. This will put that expression in every cell in the region. Assuming that hte formula uses relative cell references, this means every cell will have a value dependent on relative cells in its own row or column.
NOTE: The first cell uses relative addresses with specific constant names, like "A3" and so on. When you copy this to other cells, Excel will first convert the specific names (like "A3") to relative positions (like, one column to the left and two rows up) and then put the appropriate relative positions in each new cell. So, you define the pattern with a specific example and then Excel generalizes this and makes new specific constants for each new cell.
Besides algebraic expressions, there are a few built-in functions that are handy.
- SUM(A1:A3)
- AVERAGE(A1:A3)
- MAX(A1:A3)
- MIN(A1:A3)
Creating a series of auto-fill data in rows or columns
- Click a cell, which should show a dark frame around the cell, with a box in the lower right corner. Select the box, and drag it to expand the region to a row or column or block of cells.
- Select the "Home" tab, then click the "Fill" combo box, then select the "Series..." item. This lets you control how data is filled in the selected region.
Counting the Number of rows that Meet a Condition
=CountIf(range, criteria)
where
- Range is a range of cells, like "A2:A7"
- Criteria is a quoted algebraic relation, like ">=2001"
Some examples
- =CountIf(A2:A7, ">=2001")
Some extensions
- Combine several COUNTIF expressions in a SUM expression
Booting Linux on a new laptop
Unfortunately, new computers come out of the box configured to boot the pre-installed software (often, Windows) and it's hard to change the boot order, let alone boot from a USB drive. It's harder now than in the good old days when you would just insert a floppy or later a CD and hit the power button.
- Boot and enter the boot manager. On my Dell laptops, this means holding the F12 key during the boot process, while F2 will boot into the BIOS Manager. Make sure you do a full boot, (from powerOff) and not a resume from sleep mode. Here is a good list of hotkeys for different manufacturers
- Turn off Secure Boot. This is usually under the "Security" menu.
- Turn off "UEFI" mode. The alternative on a Dell is called "Legacy" boot mode, and on Toshiba it's "CSM" boot. I cannot get things to work with UEFI, and there may be a solution but I am not going to work on that problem. There is a very good page on UEFI that describes this more. Basically, however, I just turn off UEFI and boot from the good old legacy BIOS.
- In non-UEFI boot mode, you can select the order that different devices are queried for a boot sector. Move the USB device up in the list so it appears before the Hard drive. For some reason, my Dell will let me use the "+" key to move a list item up, but the "-" key does nothing.
A few personal things for installing and configuring Linux
This it is Fedora-specific, which uses yum. Debian and Ubuntu systems will use an alternate system, apt-get.
Yum
yum is a wrapper for the RedHat package manager (rpm) which works on Fedora or Red Hat systems. It runs as root. Here are the common yum commands:
- yum update
- yum list <package name>
- yum list updates
- yum list recent
- yum list installed
- yum search <name> - looks for a string in package names and descriptions
- yum info <package name>
- yum install <package name>
- yum remove <package name>
sudo dnf install git-all
On non-Linux systems, download Git - http://git-scm.com/downloads
- git config --global user.name "John Doe"
- git config --global user.email myEmail
- git config --global core.editor emacs
Once I started using a password manager I wondered how I lived without one. But, I prefer to keep a local file that is password protected rather than a cloud-based service. A local file has a big inconvenience that I can't use it from a laptop while working or travelling. But, really, I don't want to be accessing financial or similar web sites from a coffee shop wifi. Keeping a local file means you first have to break into my house and then break into my computer and then break the file encryption to get my passwords. Sure, that's possible, but it adds another level of security which I prefer. I just fear that web-based password managers are too tempting a target and may some day be broken, particularly by a state agency.
There are lot of password managers, and I used to use PasswordSafe because of its association with Bruce Schneier. However, that is not supported in the latest Fedora, so I changed to KeePass and am happy with it as well.
I installed KeePass XC" through Fedora Software manager. There is also https://keepass.info/
Installing Google Drive for Python on Fedora
- Install pip - go to https://pypi.org/project/pip/
- Set up the Google Drive API for Python at https://developers.google.com/drive/api/v3/quickstart/python
- sudo -i
- pip install --upgrade pip
- pip install --upgrade google-api-python-client
- pip install oauth2client
- pip3 install --upgrade google-api-python-client
- pip3 install --user oauth2client
This is the file system used for camera flash drives and similar devices.
$> su #> yum install exfat-utils.x86_64 #> dnf install fuse-exfatDisable Bell in shell windows Edit the "/etc/inputrc" to add the line:
set bell-style nonePrusa Slicer
To install:
The instructions are here
The GitHub page is here
- Download the file
- chmod ugo+x xxxxxx.AppImage
To install:
- yum install xclip
To install:
- Download file from https://www.blender.org/download/
To install:
On Fedora, I just search for Thunderbird in the software catalog, and this will show a way to install it.
Adding email accounts:
- Click Preferences > Account Settings
- From the Account Actions drop-down (bottom left corner), select Add Mail Account
- Enter your email account information
- Click Continue
- Select IMAP
- Click DONE
See https://www.videolan.org/vlc/download-fedora.html This requires Fedora 22 and later.
This uses rpmfusion, and installs from rpmfusion-free-release-stable.noarch.rpm
This also uses DNF, which is another package manager for all Linux distributions that use rpm.
$> su #> dnf install https://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm #> dnf install vlc
To play local DVD movies, you need to separately install the libdvdcss package. You can find precompiled .rpm packages or Debian install packages
for libdvdcss on https://www.rpmfind.net/linux/rpm2html/search.php?query=libdvdcss.
Installing Zoom on Fedora
See https://support.zoom.us/hc/en-us/articles/204206269-Installing-Zoom-on-Linux
Installing Git on Fedora
sudo dnf install git-all
On non-Linux systems, download Git - http://git-scm.com/downloads
- git config --global user.name "John Doe"
- git config --global user.email myEmail
- git config --global core.editor emacs
git config --list
Installing PrivateInternetAccess VPN on Fedora
See https://www.privateinternetaccess.com/helpdesk/guides/desktop/linux/fedora-openvpn-setup
In a teminal, run
- sudo -i
- dnf -y install wget unzip python NetworkManager-openvpn-gnome util-linux coreutils
- wget https://www.privateinternetaccess.com/installer/pia-nm.sh
- ./pia-nm.sh
Transmission
In a teminal, run
- sudo -i
- yum install transmission
Sample ~/.bashrc - A few common shortcuts that are actually a mix of some uxix and DOS commands.
################################################################################ # .bashrc # ################################################################################ ######################################## # Source global definitions if [ -f /etc/bashrc ]; then . /etc/bashrc fi ######################################## # Global Shell Variables export DD_ROOT="/home/ddean/ddRoot" export DD_BUILD_ROOT="${DD_ROOT}/code" ######################################## # User specific aliases and functions alias cls='clear' alias r='cd ${DD_ROOT}' alias ..='cd ..' alias more='less' ######################################## # Prompt PS1='\w> ' ######################################## # Path. This is originally set in .bash_profile but expanded here # for the command line PATH=$HOME/ddRoot/tools:$PATH ######################################## # Filename colors # eval "dircolors -b ~/.setFileColorsrc cd /home/ddean/ddRoot
My personal setup "to-do" list
- Use the Software Package tool to get the latest system updates
- Use the Software Package tool to install "Gnome Tweak"
- Use the Software Package tool to install Emacs
- Go through Tweak and Settings tools
- Copy ddRoot and latest Archive directories from a recent backup
- Copy .emacs and .bashrc from ddRoot/tools to the home directory
- Install Chrome from https://www.google.com/chrome/browser/desktop/index.html
- Configure Chrome (homePage, font size, show Home button, newTab page)
- yum install ftp
- yum install dvd+rw-tools
- yum install gcc
- yum install gcc-c++
- yum install glibc-static
- yum install libstdc++-static
- dnf install https://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm
- dnf install vlc
- Download the appropriate libdvdcss package from https://www.rpmfind.net/linux/rpm2html/search.php?query=libdvdcss
- cd to the Downloads directory
- dnf install ./the-downloaded-libdvdcss package
- Edit the "/etc/inputrc" to add the line: set bell-style none
- Install a VPN, I use privateinternetaccess, so this is specific to their software. Different VPN's will have different installation steps.
- dnf -y install wget unzip python NetworkManager-openvpn-gnome util-linux coreutils
- wget https://www.privateinternetaccess.com/installer/pia-nm.sh
- chmod ugo+x ./pia-nm.sh
- ./pia-nm.sh
Note, this will prompt you for the user name. - Enable the VPN in Settings, and that will prompt you for the password.
- Install Password Managers (keepassXC and Seahorse)
- Install keePassXC from the Software Manager
- Install seahorse from the Software Manager
- Install and edit public keys. (see my private notes in the tools dir for that)
- Install support for my Backup to Google Drive. This requires installing Python libraries used by my Python scripts.
- Install pip - go to https://pypi.org/project/pip/
- sudo -i
- pip install --upgrade pip
- pip install --upgrade google-api-python-client
- pip install oauth2client
- Automate backups with cron
- dnf install cronie cronie-anacron
- If cron is not running, use this to configure it to run at boot:
systemctl enable crond.service - Add this line to /etc/crontab
0 2 * * * ddean /home/ddean/ddRoot/tools/offsiteBackup.sh
- Install exfat File System
- yum install exfat-utils.x86_64
- dnf install fuse-exfat
- Install startup scripts
- cp ~/ddRoot/tools/ddean.desktop ~/.config/autostart/ddean.desktop
- chmod ugo+x ~/.config/autostart/ddean.desktop
- XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
- Set up Evolution email client
- Copy emailArchive to local ~/ directory
- Go through View menu options (Preview=Vertical, Uncheck group by threads)
- Go through menu Edit>Preferences
- Setup gmail
- Select the menu "Edit>Accounts" and then expand the list item for your email account, then expand the list item for "Mail Accounts" and then select the list item for your email account and click the "Edit" button.
- In the edit dialog, select "Receiving Email" and change the imap.googlemail.com to imap.gmail.com
- In the edit dialog, select "Sending Email" and change the smtp.googlemail.com to smtp.gmail.com
- Create an account for Local Archived files
- Select the menu item File>New>Mail Account
- For the General Dialog, FillName=Local Archive emailAddress=emailArchive@dawsondean.com
- For the Receiving Email Dialog, accountType="Standard Unix mbox spool directory" spoolDirectory=[local archive dir]
- For the Receiving Options Dialog, deselect all options, these messages have already been filtered and saved.
- For the Sending Email Dialog, serverType=None
- For the Account Summary Dialog, name="Local Archive"
- Octave (open source Matlab work-alike)
- dnf install octave
- Pinta (paint)
- yum install pinta
- Install numpy and pytorch
- sudo -i
- python3 -m pip install numpy
- python3 -m pip install https://download.pytorch.org/whl/cpu/torch-1.0.1.post2-cp36-cp36m-linux_x86_64.whl
- python3 -m pip install tables
- python3 -m pip install opencv-python
- python3 -m pip install matplotlib
- python3 -m pip install sklearn
- sudo -i
- dnf install python3-tkinter
- Brother Printer
- Download the driver
- Open URL: http://support.brother.com/g/s/id/linux/en/faq_prn.html?c=us_ot&lang=en&redirect=on#f00104
- visit this URL: https://help.brother-usa.com/app/answers/detail/a_id/52188/p/9214/kw/Linux/session/L3RpbWUvMTU0ODEyOTc4Mi9zaWQvZlVJYjlFYTRNMURCVk11cW9zZVJsYlY4V2ozZl9HYzY5b2NHeE1MS1VMNzdjRV9HR1BsWFdwZkZVNFhqRjFEWmV3eUtLZWpnc3ZoRlpSYjd1WEpoVVVqZFlNZElYUDlIcURCd2lHelBlV3laSm1reWxFbFRucTF3JTIxJTIx
- gunzip linux-brprinter-installer-2.1.1-1.gz
- sudo -i
- cd home dir
- bash ./inux-brprinter-installer-2.1.1-1
- Ctrl-D - exit su
- Open Control Panel
- Select the printer
- Install the scanner
- Downoad the drivers from https://support.brother.com/g/b/downloadlist.aspx?c=us&lang=en&prod=mfcl2750dw_us_eu_as&os=127
- dnf install libnsl
- vi /etc/sane.d/saned.conf
- Add 192.168.1.10 to the config
- brsaneconfig4 -a name=Brother model=MFCL2750DW ip=192.168.1.10
- gscan2pdf
- Download the driver
Here is the file I put in my autostart directory
#!/bin/sh /home/ddean/ddRoot/tools/loginScript.sh
Here is the file I put in my own directory
#!/bin/sh ############################################### # Login Script ############################################### emacs & emacs & thunderbird & google-chrome --new-window /home/ddean/ddRoot/HomePage/main.html &
Installing and configuring Emacs
A few common shortcuts that I personally prefer. The blessing/curse of emacs is that it is so customizable, everyone ends up with a slightly different solution. These are what I have come up with so far, but I am also still trying to tweak it to make it more to my liking. Still, you may not like these design choices.
When testing a .emacs file, you can always use "M-x load-file" and then enter the file name.
This will reload the config file without quitting and restarting the program.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; Emacs Customization ;; Tips and tricks from many sources, collected by Dawson Dean ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Font Size and Type ;; ;; The height is 1/100th of a point, so 100 is a 10pt font. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (set-default-font "DejaVu Sans Mono") (set-face-attribute 'default nil :height 100) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Text Colors ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (set-face-foreground 'font-lock-string-face "black") (set-face-foreground 'font-lock-comment-face "dark green") (set-face-foreground 'font-lock-comment-delimiter-face "dark green") (set-face-foreground 'font-lock-function-name-face "black") (set-face-foreground 'font-lock-variable-name-face "black") (set-face-foreground 'font-lock-keyword-face "dark blue") (set-face-foreground 'font-lock-type-face "black") (set-face-foreground 'font-lock-constant-face "black") (set-face-foreground 'font-lock-builtin-face "black") (set-face-foreground 'font-lock-preprocessor-face "black") ;; The color of the mark region (set-face-attribute 'region nil :background "#BFEFFF") ;; Blue: 0000FF ;; Orange: FFA000 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Custom Key Bindings ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Ctrl-Z is undo. (global-set-key (kbd "C-z") 'undo) (global-set-key (kbd "C-Z") 'undo) ;; Ctrl-/ will goto-line ;; This is totally unique to me, nobody else agrees on this. Lots of people ;; seem to like "Esc-g g" but that's still too many keystrokes for me. (define-key global-map (kbd "C-/") 'goto-line) ;; I sometimes have the Control key held down while doing other things. (define-key global-map (kbd "") (kbd " ")) (define-key global-map (kbd " ") [Double-Mouse-1]) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Basic Editing ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Shift-click will extend the mark region (define-key global-map (kbd " ") 'mouse-save-then-kill) ;; Typing will replace the currently selected text. (delete-selection-mode 1) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Syntax Table Hacking ;; http://www.emacswiki.org/emacs/EmacsSyntaxTable ;; ;; Word operations will not treat "_" as a word-break in C++. This puts ;; the character "_" (which is quoted with ? so it is ?_) in the "word" ;; class of characters (which is identified by "w"). ;; Really, we just want to evaluate this: (modify-syntax-entry ?_ "w") ;; But we add a hook so our customization is not clobbered every time ;; the symbol table is edited. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (add-hook 'text-mode-hook (lambda () (modify-syntax-entry ?_ "w"))) (add-hook 'c-mode-hook (lambda () (modify-syntax-entry ?_ "w"))) (add-hook 'c++-mode-hook (lambda () (modify-syntax-entry ?_ "w"))) (add-hook 'html-mode-hook (lambda () (modify-syntax-entry ?_ "w"))) (add-hook 'xml-mode-hook (lambda () (modify-syntax-entry ?_ "w"))) (add-hook 'java-mode-hook (lambda () (modify-syntax-entry ?_ "w"))) (add-hook 'js-mode-hook (lambda () (modify-syntax-entry ?_ "w"))) (add-hook 'js2-mode-hook (lambda () (modify-syntax-entry ?_ "w"))) (add-hook 'abbrev-mode-hook (lambda () (modify-syntax-entry ?_ "w"))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Select the entire buffer ;; This was copied (with some small changes) from: ;; https://www.gnu.org/software/emacs/manual/html_node/eintr/mark_002dwhole_002dbuffer.html ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun mark-whole-buffer() "Select the entire buffer" (interactive) (message "mark-whole-buffer!") ;; Put point at beginning (push-mark (point)) ;; Put the mark at end of buffer. (push-mark (point-max) nil t) (goto-char (point-min)) ) ;; defun (global-set-key (kbd "C-S-A") 'mark-whole-buffer) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; CUA Mode ;; ;; This makes Ctl-x cut, Ctl-v paste, and Ctl-C copy. ;; This is what you use in Web browsers, so it makes sense for all applications to ;; share a common convention. ;; http://www.emacswiki.org/emacs/CuaMode ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (cua-mode t) (transient-mark-mode 1) ;; Default in Emacs 23 and later. Selected region is only active when highlighted ;;(setq cua-auto-tabify-rectangles nil) ;; Don't tabify after rectangle commands ;;(setq cua-keep-region-after-copy t) ;; Standard Windows behaviour ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; Searching: Find, Find-And-Replace, Grep ;; ;; As I switched back to emacs after years on Microsoft's Visual Studio, I realized ;; that I use search to navigate around a buffer more than Ctl-V and Esc-V or similar ;; things. Here are some functions to find the next and previous instance of the ;; currently selected text. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Find the next instance of the selected text (defun forward-search-selection (beg end) "Search for the current selection" ;; This tells elisp to call this command with the point and mark ;; as arguments parameters bound to beg and end (interactive "r") ;; Save the current selection to a local variable. ;; We want to deactivate the mark, so save a private copy first. (let ( (selection (buffer-substring-no-properties beg end)) ) ;;(message "selection:%s" selection) ;; De-activate the current mark region. We will change the mark later (deactivate-mark) ;; Find the next instance of the string. ;; https://www.gnu.org/software/emacs/manual/html_node/eintr/search_002dforward.html#search_002dforward ;; search-forward takes 4 arguments: ;; The search pattern ;; Optional - limit of search. nil means end of buffer ;; Optional - how to handle failed search. nil means print a message. ;; t means return a result ;; Optional - How many instances to find (when (search-forward selection nil t) ;; If search-forward returned true, then it found a match. ;; Select the match. This is nice for user feedback but it also ;; lets another search-forward find the next occurrence. (setf (mark) (match-beginning 0) (point) (match-end 0)) ) ;; when ) ;; let ) ;; forward-search-selection (define-key global-map (kbd " ") 'forward-search-selection) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Find the previous instance of the selected text (defun reverse-search-selection (beg end) "Search for the current selection" ;; This tells elisp to call this command with the point and mark ;; as arguments parameters bound to beg and end (interactive "r") ;; Save the current selection to a local variable. ;; We want to deactivate the mark, so save a private copy first. (let ( (selection (buffer-substring-no-properties beg end)) ) ;; De-activate the current mark region. We will change the mark later (deactivate-mark) ;; Find the prev instance of the string. ;; This works like search-forward except it runs in reverse ;; search-backward takes 4 arguments: ;; The search pattern ;; Optional - limit of search. nil means end of buffer ;; Optional - how to handle failed search. nil means print a message. ;; t means return a result ;; Optional - How many instances to find (when (search-backward selection nil t) ;; If search-forward returned true, then it found a match. ;; Select the match. This is nice for user feedback but it also ;; lets another search-forward find the next occurrence. (setf (mark) (match-end 0) (point) (match-beginning 0)) ) ;; when ) ;; let ) ;; reverse-search-selection (define-key global-map (kbd " ") 'reverse-search-selection) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Replace Text ;; Replace the next instance of the selected text (defun forward-replace-selection (beg end) "Search for the current selection" ;; This tells elisp to call this command with the point and mark ;; as arguments parameters bound to beg and end (interactive "r") ;; Save the current selection to a local variable. ;; We want to deactivate the mark, so save a private copy first. (let ( (selection (buffer-substring-no-properties beg end)) ) ;; (message "forward-replace-selection:%s" selection) ;; De-activate the current mark region. We will change the mark later (deactivate-mark) (let ( (replaceStr (read-from-minibuffer "Replacement: ")) ) ;;(message "replaceStr:%s" replaceStr) ;; Go to the start of the buffer. ;; search-forward will only start at the current position. (goto-char (point-min)) ;; https://www.gnu.org/software/emacs/manual/html_node/elisp/Search-and-Replace.html (while (search-forward selection nil t) ;; https://www.gnu.org/software/emacs/manual/html_node/elisp/Replacing-Match.html ;; replace-match replacement &optional fixedcase literal string subexp ;; fixedcase says to not change the case of the replacement text ;; to match the text being replaced. (replace-match replaceStr t)) ) ;; let ) ;; let ) ;; forward-replace-selection (define-key global-map (kbd "C-r") 'forward-replace-selection) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Grep ;; Find the next instance of the selected text (defun grep-selection (beg end) "Grep for the current selection" ;; This tells elisp to call this command with the point and mark ;; as arguments parameters bound to beg and end (interactive "r") ;; Save the current selection to a local variable. ;; We want to deactivate the mark, so save a private copy first. (let ( (pattern (buffer-substring-no-properties beg end)) ) (message "ddGrep:%s" pattern) ;; De-activate the current mark region. We will change the mark later (deactivate-mark) ;; grep-find is a built-in emacs elisp function. ;; See: https://www.gnu.org/software/emacs/manual/html_node/emacs/Grep-Searching.html#Grep-Searching ;; See: https://www.gnu.org/software/emacs/manual/html_node/emacs/Grep-Searching.html ;; The options are the normal command line grep options. ;; Here, I use: ;; -e, --regexp=PATTERN use PATTERN for matching ;; -i, --ignore-case ignore case distinctions ;; -n, --line-number print line number with output lines ;; -H, --with-filename print file name with output lines ;; -R, --recursive like --directories=recurse, and also follow all symlinks ;; ;; Some useful topns which are not used now, but may be used later ;; -w, --word-regexp force PATTERN to match only whole words ;; -x, --line-regexp force PATTERN to match only whole lines ;; -m, --max-count=NUM stop after NUM selected lines ;; -h, --no-filename suppress the file name prefix on output ;; -o, --only-matching show only the part of a line matching PATTERN ;; --include=FILE_PATTERN search only files that match FILE_PATTERN ;; -L, --files-without-match print only names of FILEs with no selected lines ;; -l, --files-with-matches print only names of FILEs with selected lines ;; -T, --initial-tab make tabs line up (if needed) ;; -B, --before-context=NUM print NUM lines of leading context ;; -A, --after-context=NUM print NUM lines of trailing context ;; -C, --context=NUM print NUM lines of output context (grep (concat "grep -i -n -H -R -e \"" (shell-quote-argument pattern) "\" /home/ddean/ddRoot/code")) ) ;; let ) ;; grep-selection (define-key global-map (kbd " ") 'grep-selection) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; Parens and Braces ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Find the matching (open or close) paren ;; This was copied (with some small changes) from: ;; https://www.gnu.org/software/emacs/manual/html_node/efaq/Matching-parentheses.html (defun find-match-paren (arg) "Go to the matching paren if on a paren; otherwise insert %." (interactive "p") (cond ((looking-at "\\s(") (forward-list 1) (backward-char 1)) ((looking-at "\\s)") (forward-char 1) (backward-list 1)) ((looking-at "\\s[") (forward-list 1) (backward-char 1)) ((looking-at "\\s]") (forward-char 1) (backward-list 1)) ) ;; cond ) ;; defun (define-key global-map (kbd "C-]") 'find-match-paren) ;; Make braces act like parens, and match opens and closes (modify-syntax-entry ?{ "(}") (modify-syntax-entry ?} "){") ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; Tabs and Indentation ;; ;; http://www.emacswiki.org/emacs/IndentationBasics ;; https://stackoverflow.com/questions/344966/improved-tab-in-emacs ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Tabs are space characters, not a tab character. (setq-default indent-tabs-mode nil) (global-set-key (kbd "TAB") 'tab-to-tab-stop) (setq default-tab-width 4) (setq tab-width 4) ;; tab-width is used when DISPLAYING tabs, while tab-stop-list ;; is needed to determine tab stops when you ADD tabs. ;; From emacs documentation, "The variable tab-stop-list controls these positions. The default value is nil, which means a tab stop every 8 columns." ;;;(setq-default c-basic-offset 4) (setq tab-stop-list (number-sequence 4 200 4)) ;; Be careful. If you set this to newline-and-indent, then emacs ;; will autoindent no matter what you set the autoindent options to. ;;(global-set-key (kbd "RET") 'newline-and-indent) (global-set-key (kbd "RET") 'newline) ;; Don't use tabs to indent code. ;;;(setq-default indent-tabs-mode nil) ;; Stop emacs from trying to second-guess what it thinks I want. (when (fboundp 'electric-indent-mode) (electric-indent-mode -1)) ;;(setq-default electric-indent-inhibit t) ;; Pasting a newline does not cause an indent. (global-set-key "\C-j" 'newline) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; Indenting and Un-Indenting ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun shift-region (distance) (let ((mark (mark))) (save-excursion (indent-rigidly (region-beginning) (region-end) distance) (push-mark mark t t) ;; Tell the command loop not to deactivate the mark ;; for transient mark mode (setq deactivate-mark nil)))) (defun shift-right () (interactive) (shift-region 4)) (defun shift-left () (interactive) (shift-region -4)) ;; C-[ is equivalent to the escape key on US English keyboards ;; Changing C-[ will break things like Esc-x (global-set-key (kbd "C-]") 'shift-right) (global-set-key (kbd "C-.") 'shift-right) (global-set-key (kbd "C-,") 'shift-left) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Backup Files ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (setq backup-directory-alist `(("." . "~/emacsBackupFiles"))) (setq delete-old-versions t kept-new-versions 1 kept-old-versions 1 version-control t) ;; This will turn off all backup files. ;; (setq make-backup-files nil)
vi editor
I used emacs until I went into IDE's. Now that I am back to some linux programming, here are some tips for those times when I do a bit of VI (like when you are running as root and need an editor for a config file).
- Run vi - "vi fileName"
- Enter insert mode - Type "i <RET>". Now any further text you type is entered into the file as data. You can use the arrow keys to move around the file. This command leaves command mode.
- Leave insert mode - Type the <ESC> key. Now you are back in command mode.
- Save changes and exit vi - ":wq <RET>" Type this in command mode
- Exit vi withOUT saving changes - ":q! <RET>" Type this in command mode
- Search for the next occurrence after the cursor of some pattern - "/pattern <RET>" Type this in command mode
- Search for the previous occurrence after the cursor of some pattern - "?pattern <RET>" Type this in command mode
- Find the next occurrence of the pattern - "n <RET>" Type this in command mode
- Save the current file - ":w <RET>" Type this in command mode
- Save the current file to a new file - ":w fileName <RET>" Type this in command mode
Emacs Common Things
For some reason, I always forget these things.
- Conditional-Search-Replace M-% string RET newstring RET
Then, <Space> to replace the current instance, <DEL> to skip the current instance, <RET> to stop search without any more replacements
Burning DVDs on Linux
I use an online backup service, but I still like to burn my home directory to a DVD every few days. It lets me make my own offsite backups, as well as shuttle my home directory between machines and between Linux and Windows. I know I might be able to use some online service for that, but with more complexity, with a monthly subscription fee, with challenges in portability across operating systems, with a dependency on a third party company that may change their UI or features or costs, and with my data sitting on somebody else's computer which may be secure but is also an inviting target for hackers. On Windows, I just used Roxio, but on Linux, here is a quick and dirty solution. I wrote scripts to do this, so I just run the script to burn an image:
This uses growisofs, which requires you install
yum install dvd+rw-tools
Burning a data DVD with a tree of files
su mkisofs -J -R -o /your-temp-directory-name/foo.iso -root your-top-level-dir-name /your-home-dir growisofs -dvd-compat -Z /dev/cdrom=/your-temp-directory-name/foo.iso rm -rf /your-temp-directory-name/foo.iso
Restoring a Directory from a DVD
su umount /dev/cdrom mount -t iso9660 /dev/cdrom your-temp-directory-name rm -r -I your-home-dir cp -r your-temp-directory-name your-home-dir chown -R your-user:your-group your-home-dir chmod -R u+rwx your-home-dir umount /dev/cdromNote, these must run as root.
Burning VOB files to a Video DVD
There are several alternatives.- mkisofs -dvd-video -o mydvd.iso -udf /path/to/filedir/
This will not skrink, so the .iso file will be 8gb - genisoimage -dvd-video -v -o DVD.iso DVD
Compiling Linux programs with static libraries
Linux has adopted the philosophy that programs should be dynamic linked. There are both legal reasons for this (the libraries are built under GPL) and practical. However, suppose you want to compile a program, and then run your program on servers provided by web hosting companies. Your program must be compiled with exactly the same version of the runtime libc as is available on the hosting servers. Do hosting companies guarantee that? Of course not. So, instead your program must be compiled with static libraries. That is the problem I am trying to solve, and here are some notes.
- Compile your programs with static linking.
The compiler uses the flag -static. There are some other flags that I have seen discussed,
but in practice I don't need them. These include the flags -Wl -Bstatic, where -Wl sends a flag
to the linker and -Bstatic is the static link flag
- Install the static libraries
- yum install glibc-static
- yum install libstdc++-static
- Key networking system calls do not seem to work for a statically linked program. Specifically, you cannot lookup a network address if you are statically linked because getaddrinfo and even gethostname do not work. It seems that the name resolution library runs different code depending on host-specific preferences, like whether to use DNS or other network infrastructure. So, rather than writing 1 program that can call out to different local name resolver services (like, via a local pipe or system call), the C library is hard-compiled with the diffreent sources. This means that libc cannot call gethostbyname in a portable way. Instead, you must dynamically link with the local glibc on each different machine. If you really need to run the static glibc, then you cannot use this call.
Installing and configuring mySQL
Installation
I use Fedora, which uses dnf and yum, and the best guide I found (granted after only a cursory look) is at www.if-not-true-then-false.com/2010/install-mysql-on-fedora-centos-red-hat-rhelInstalling and configuring Apache
See https://fedoraproject.org/wiki/Apache_HTTP_Server
- Install Apache
- su
- dnf install httpd
- To have the server start at each boot: systemctl enable httpd.service
- To start the server now: systemctl start httpd.service
- Configuration
- GUI Configuration tool: /usr/bin/system-config-httpd
- Manual edit config files. emacs /etc/httpd/conf/httpd.conf
Using CSS "position" attributes for HTML Layout
Many HTML elements may use CSS to control where they are positioned on a page. This is done with a "position" attribute, that may have two values: "absolute" or "relative". For example:
- style="position:absolute; left:0px; top:0px;"
- style="position:relative; left:0px; top:0px;"
These can be confusing, because they use the terms "absolute" and "relative" to place an element in a position in relation to the "normal position of that element in the HTML layout", and NOT necessarily in relation to another element. So, the browser first lays out an HTML document, which assigns every element in the document to a position on the page. This initial position is referred to as the element's position in the "document flow". Once the browser has completed this initial layout step, then the CSS position attributes may override each element's position and place the element in a different place.
"Relative" means place the element at some offset in relation to where it would normally go in the HTML laytout. So, for example, if a typical HTML page would place an element at x=100,y=200, and the element had an attribute
- style="position:relative; left:50px; top:75px;"
"Absolute" means place the element at some "absolute" position, and just ignore where it would normally go in the HTML laytout. So, for example, if a typical HTML page would place an element at x=100,y=200, and the element had an attribute
- style="position:absolute; left:50px; top:75px;"
However, the confusing part is that an "absolute" coordinate is still in relation to somethng.
It may be in relation to the bottom-left corner of the HTML page, but it may also
be in relation to a containing element, like a div element. So, "position:absolute" means an
absolute position compared to the flow of the document but still relative to the
position of the parent HTML element that contains the element being moved.
Installing Raspberry Pi
Installation with Linux
- Run lsblk to see which devices are NOT the SD card. This will print a list of devices.
- Plug an SD card into the linux box - I use a USB-SD-reader.
- Run "lsblk" again. The USB HDMI is cometimes sdb, but beware. That can differ with different devices.
- sudo -i
- parted /dev/sdb - or whatever the device name of the SD card is.
- (parted) mklabel msdos
- (parted) mkpart primary fat32 1MiB 100%
- (parted) set 1 boot on
- mkfs.vfat /dev/sdb1
- Ctrl-D
- Download the latest noobs OS software from downloads.raspberrypi.org/noobs
- Mount the device. One way to do this is to open Files, which will automount the new device.
- cd ~/Downloads
- unzip NOOBS_v2_8_2.zip -d /run/media/userName/xxxxxx - where userName is your name and XXXX is the volume name of the SD drive
- Plug in the SD card, a USB mouse, a USB Keyboard, a HDMI monitor into the Pi and connect a powersupply.
- Plug the power supply in, and the Pi should boot. It will install an OS from your SD card
- https://www.raspberrypi.org/app/uploads/2012/04/quick-start-guide-v2_1.pdf
- https://www.pcworld.com/article/3176712/linux/how-to-format-an-sd-card-in-linux.html
Copying Files from Linux to a Pi
- Configure the Pi to accept SSH connections.
- sudo systemctl enable ssh
- sudo systemctl start ssh
- On desktop, select menu "Preferences>Raspberry Pi Configuration"
- Select the Interfaces tab
- Select "Enabled" next to SSH
- Select the "OK" button, and the Pi will reboot
- On the Pi, open a terminal window and run "ifconfig". Next to the wlan0 entry, get the IP address
- To copy from Linux to Pi: scp file.txt pi@xxx.xxx.xxx.xxx:destinationDir/
- To copy from Pi to Linux: scp file.txt pi@xxx.xxx.xxx.xxx:
Cross-compiling on Linux and Running on Pi
I am not doing this yet. Currently, I am just maintaining source code on my dev box and copying it to a Pi and compiling it there.- yum install apt-get install git rsync cmake
Note that ia32-libs is no longer supported.
Android Studio
Installation on Linux
- On linux, I needed to install some directories first. For Fedora, this required these installs
yum install compat-libstdc++-296.i686 compat-libstdc++-33.i686 ncurses-libs.i686 compat-libstdc++-33.x86_64 zlib.i686 bzip2-libs.i686 yum install adb dnf install android-tools
- Download and install the Android Development environment. See https://developer.android.com/studio/install.html. This will have instructions for Windows and Linux.
- On Fedora, unzip the downloaded directory, which makes an "android-studio" directory. Then run the installer from the command line from , by running "~/android-studio/bin/studio.sh". I also run the "~/android-studio/bin/studio.sh" to launch the application after it has been installed (really, installation is just done the first time you start the app).
Running Android-Studio and Loading a Project
This assumes you installed the directory "android-studio" in your home directory. If you put it somewhere else, then change the "~" to the parent of your installed directory.- ~/android-studio/bin/studio.sh
- In the "Welcome to Android Studio" window, there is a list of projects on the left side of the window. Click the project to load.
Common Problems
- Cannot Upgrade - No space left on device
On linux, I often get errors when upgrading AndroidStudio. This is because the downloaded upgrade file is copied into /tmp, and that is often only the size of physical memory. If you have several SDK's, then upgrading all of them will download an 8g or more archive file, and that is too big to fit in a small /tmp. To fix this, try first pruning the SDK's you use, and then increase the size of /tmp. As root, edit the /etc/fstab file to change the line for the /tmp file system:tmpfs /tmp tmpfs defaults,size=3g 0 0
You will need to reboot.
Hello World
This creates and runs a simple "Hello, World" app, and is drawn from https://developer.android.com/training/basics/firstapp/index.html- In the "Welcome to Android Studio" window, click the link "Start a new Android Studio project". This will open a dialog box where you provide basic information.
- Enter the app name and your domain, and click "next"
- In the "Target Android Devices" screen, select "Phone and Tablet" and click "next"
- In the Add an Activity to Mobile screen, select Empty Activity and click "next"
- In the "Customize the Activity" screen, keep the default values and click "Finish"
- Enter the app name and your domain, and click "next"
- The first time you run on a physical device, you will need to do some setup.
- Connect the device to your machine with a USB cable
- Open the "Settings" app on the device
- (Only on Android 8.0 or higher) select "System". On my older (ver 4.4) test phone, I select the "More" tab.
- Scroll to the bottom and select "About Device" or "About Phone".
- Scroll to the bottom and tap Build number 7 times.
- Return to the previous screen to find Developer options near the bottom.
- Open Developer options, and then scroll down to find and enable USB debugging.
You may have to change the SDK to fit your device. Be careful to change only the "Min Sdk"
- Select the menu "File>Project Structure". This opens an options dialog.
- Select the "app" entry, below the "Modules" section, in the table-of-contents on the left side
- Select the "Flavors" tab
- Select the "Min Sdk Version" and "Target Sdk Version" combo boxes
Some common problems:
- I was getting an error:
com.android.ddmlib.AdbCommandRejectedException: insufficient permissions for device See [http://developer.android.com/tools/device.html] for more information. Error while Installing APK
Android-studio points you to the web page, "https://developer.android.com/studio/run/device" which does not help. It seems the problem is not with the device, but the development system. Specifically, you need to install a file that allows the PC to access the connected phone.
First, you can manually list all devices connected to use with the command:
> sudo lsusb
This has a list of devices, one per line, and each includes two hex values separated by a colon (for example: 18d1:4e22). This is the manufacturerID:deviceID you need to tell the system to handle. These need to be included in a configuration file names, "/etc/udev/rules.d/51-android.rules" If this file does not exist, you must create it (as root).
I found a template rules file on https://github.com/M0Rf30/android-udev-rules
This has a rules file with vendor andd device id's for many popular phones. I simply copied the 51-android.rules file to my /etc/udev/rules.d dir and rebooted. - If you get an error like "com.android.ddmlib.AdbCommandRejectedException: device unauthorized." then
your phone may have cached connection state for a different computer.
- Revoke the old device permissions on your phone. Go to Settings > Developer options > Revoke USB debugging authorizations
- Disconnect the phone from the USB, then plug it back in.
- Revoke the old device permissions on your phone. Go to Settings > Developer options > Revoke USB debugging authorizations
- Connect the device to your machine with a USB cable
- The first time you run in an emulator you will have to do some installation. Note, you need a CPU which runs SSSE3. I have tried to setup system
images that do not require VM support, but still cannot make it work.
- You have to download the necessary system images
- In Android Studio, open "Android SDK Manager". It may be in the "Tools" menu or the "Tools -> Android -> SDK Manager" sub-menu
- Click the "Show Details" or "Show Package Details" checkbox
- Chose platforms/packages you want to download. For older non-Intel x64 systems, select "ARM EABI v7a System Image" or "ARM 64 v8a System Image"
- Install the images
- In Android Studio, open "Android SDK Manager". It may be in the "Tools" menu or the "Tools -> Android -> SDK Manager" sub-menu
- When installing SDK's or AVD's you may hit an error, "No space left on device Error". In my case, it was because my /tmp file system was too small.
It appears that Android Studio creates large temporary files in /tmp when it unzips downloaded images. You could try to just do a "rm -r -I *" in
the /tmp directory and try again.
However, I find that some of the large zip files are bigger than /tmp will allow. So, in the end, I had to change the /tmp size in my /etc/fstab file.
I do this only when downloading and installing the images, and then comment out the line when I am done so it does not take too much of my ram for
the /tmp file system.
- As root, add the following line to the end of the /etc/fstab
none /tmp tmpfs size=8G 0 0
- Reboot or remount for the changes to take effect
- As root, add the following line to the end of the /etc/fstab
- If, like me, you get an error that says, "An error occurred while creating the AVD. See idea.log for details", you may ask yourself,
"Where are the logs? How do I fix this?"
- The log files are in a directory, /home/>yourUserName</.AndroidStudio2.3/system/log on linux
and C:\Users\yourid\.AndroidStudioPreview\system\log on windows. Be careful, depending on the version of
Android Studio you are using, the "AndroidStudio2.3" directory may have a different version number suffix.
- You may need to install additional libraries onto your system. For example, on Linux I had to run "yum install libgcc_s.so.1". Look in the idea.log file. In my case, I had an error like "WARN - Vdmanager.AvdManagerConnection - error while loading shared libraries: libgcc_s.so.1"
- The log files are in a directory, /home/>yourUserName</.AndroidStudio2.3/system/log on linux
and C:\Users\yourid\.AndroidStudioPreview\system\log on windows. Be careful, depending on the version of
Android Studio you are using, the "AndroidStudio2.3" directory may have a different version number suffix.
- You have to download the necessary system images
- The first time you run, you may have to create an emulator
- In Android Studio, open the "Android AVD Manager" from the menu "Tools" or a submenu "Tools -> Android -> AVD Manager"
- Create an emulator
- In Android Studio, open the "Android AVD Manager" from the menu "Tools" or a submenu "Tools -> Android -> AVD Manager"
- Select the "Run App" item in the "Run" menu. Or, click the green triangle "Play" but on on the toolbar
- In the "Select Deployment Target" window, Select an existing device, or click "Create New Virtual Device"
- To create a new device:
- In the "Select Hardware" window, select the device you want to emulate, and click "next"
- In the "Select Image" window, select the system software you want to emulate, and click "next". You may have to
first dsownload some system images.
- In the "Android Virtual Device (AVD)" window, review your choices and click "Finish"
- To create a new device:
Adding A Button
- Edit the "activity_main.xml" file. This may initially display the XML but you can select the "Design" tab at the bottom of the XML text to show the palette.
- Drag a button fromt he palette side-bar to the GUI
- Select the button, and in the right-hand sidebar, edit the properties. Specifically, you may want to edit
- ID - the ID used to refer to this button from code.
- Text - the text displayed on the button
- Select the MainActivity.java text. You will now add some text code to register and declare an event handler for the button.
General Android Studio Tips
- If you add code that uses a system type that is defined in a library that has not been imported,
you will get an error, "Cannot resolve symbol".
Select the undeclared type and press Alt + Enter (or Option + Return on Mac) and you will get a popup menu to select which library to import. The system will then insert the appropriate "import" statements at the top of your file.
Editing an App's GUI in Android Studio
- On the left vertical border of Android Studio are several tabs, that select main windows.
- Project - This is a tree of objects in the app, including Java code, Resources, and more
- Structure
- Capture
- Build Variants
- Select the Project window, and then select the XML that defines the UI layout.
For a simple app, this will be in the "app > res > layout > activity_main.xml" section of the Project tree.
This will open an editor for manipulating the GUI. This creates several window panes
- Palette - prototypes of View objects you can drag into the editor
- Component Tree - the Views and ViewLayout objects that are in your GUI
- The main GUI editor. Above this window pane is a toolbar with an icon of a blue square with a drop shadow on its
corner (like a diamond). This selects the view of the GUI.
- Design - previews what the UI will look like.
- Blueprint - Displays an editor that allows you to add new Views and move or resize Views.
- Design - previews what the UI will look like.
- Palette - prototypes of View objects you can drag into the editor
- To delete an item from the UI, select its entry in the "Component Tree" and hit Delete-key
- To add an item, select the item in the "Palette" window pane on the left. This is a 2-level hierarchical
view, so first select the category in the left half of the pane (for example, category "Text") and then specific
object (for example, "TextView") in the right half of the pane.
- Drag the item you selected in the palette to the layout window in the large pane in the center of the screen.
You can use the mouse to directly manipulate any View, such as resizing or moving it.
Click and drag squares in the corners to resize the View. Click and drag circles inthe middle of the border edges to move the View.
- To set the text in a View object, select the object in the layout window. This should open an "Attributes" window pane (in
my installation, this is on the right). Select the "text" property, delete the contents of the property and then click the "..." button to
the right of the text edit box. This opens a modal dialog that allows you to select a "string" resource which will be
used for the View's text.
- Create string resources in the Strings editor.
- In the Project Window, select "app > res > values > strings.xml" and double click it.
- Click the "Open Editor" link (not a tool bar icon)
- To add a new string, click the green "+" toolbar icon. This opens a dialog box where you can enter the "key" and value for the resource.
- In the Project Window, select "app > res > values > strings.xml" and double click it.
- Layout
Layout uses constraints rather than absolute positions, because a single GUI will have to run on many different devices with different screen dimensions.
- A Constraint between the edge of a view and the border of the app. Select the ViewObject and in the
properties pane you can select the left, right, top or bottom margin to the edge of the app. You can also
configure the View object to have a fixed size or else scale to fit the width or height of the App.
- A constraint between 2 Views. Click one View object, then click the square the pops up to the
lower left of the View object. This square is the "Edit Baseline" control. Select the Edit Baseline
and then drag a connection to another View object. This will put the 2 View objects on the same
horizontal baseline.
- Chain constraints. Select one view, then shift-select a second view. Then right click either view, and in the context menu select "Chain > horizontal" or "Chain > vertical". This will force the Views to be in a horizontal or vertical line
- A Constraint between the edge of a view and the border of the app. Select the ViewObject and in the
properties pane you can select the left, right, top or bottom margin to the edge of the app. You can also
configure the View object to have a fixed size or else scale to fit the width or height of the App.
Adding new code to an App in Android Studio
- Adding a new file of source code
In Java, typically each class is in its own file, so the most natural way to add new code in Android is to add a new class.
Select the menu "File>New>Java Class" and then follow the prompts. This will create a new file in the "projectName/app/src/main/java/com/yourDomainName/projectName/className.java" subdirectory under your App project directory. Where:
- "projectName" is the name of your project
- "yourDomainName" is the name of your domain
- "className" is the name of your domain
The new file will contain an empty class definition, to which you can add methods. The file should also contain a code that says it belongs to the same package.
package com.yourDomainName.projectName;
I find I can edit the files in any editor (such as emacs) and Android Studio will always read the latest version of the file on disk.
- Calling your code from the GUI
You first need an instance of your class.
- Declare the variable in the main activity class.
myClass g_GlobalCommand;
- Create an instance of this class when the app starts. One easy place to do this is the onCreate() methods for the activity.
g_GlobalCommand = new myClass();
Now you should be able to call methods on the class from anywhere.
- Declare the variable in the main activity class.
- Setting the function to run when you click a button
Your function needs to be public, return void, and take a single parameter of type View. As an example:
// Called when the user taps a button public void onButtonClick(View buttonView) { // Do something in response to button } // onButtonClick
Set the "onClick" attribute of the View object. To do this, go into the layout editor, and select the View object to display its properties (in a window pane on the right side of the screen). There is a property labelled "onClick" that selects from a pull-down menu of callback methods you have declared in the code as of the last compile. Select the appropriate function.
- Change the string in an object (ie, change "Hello World!" to "I have Changed!")
Get the attribute of the View object. To do this, you may need to go into the layout editor, and select the View object to display its properties (in a window pane on the right side of the screen). There is a property labelled "ID" at the top of the list of properties. You may need to provide a value.
Get a reference to the View object using its ID.
EditText editText = (EditText)findViewById(R.id.edit_text); editText.setText("I have changed!!!");
- Open a new Activity
This uses "Intent" objects - which are declaring an App state change. These can be created any time, and really it is like making a systm call to Android, but you do so by creating an Intent system object and then invoking a method on it.Intent intent = new Intent(this, DisplayMessageActivity.class); EditText editText = (EditText) findViewById(R.id.editText); String message = "extra param"; intent.putExtra(EXTRA_MESSAGE, message); startActivity(intent);
The contstructor to the Intent object takes 2 parameters- A context (we use "this" because the Activity is a subclass of a context)
- The ID of the new activity class
public static final String EXTRA_MESSAGE = "com.dawsondean.myfirstapp.MESSAGE";
Next create a new activity class. In Android Studio, look at the Project window pane, and right-click the app folder and select "New > Activity > Empty Activity" action. This will open a dialog box where you configure the new Activity. When you hit the "Finish" button, this will create an xml file for the Activity GUI, and also a Java file for the Activity code.
Declare the hierarchy of the activities in the AndroidManifest.xml file. To do this, open the file by double clicking "app > manifests > AndroidManifest.xml" in the project window pane. Now add the following to the DisplayMessageActivity
tag - Get the contents of a text edit control
EditText editText = (EditText) findViewById(R.id.editText); String message = editText.getText().toString();
Android Debugger
Starting the Debugger
Use the "Debug 'app'" command in the "Run" menu.- Setting a Breakpoint - Open the source code file, and click on the left column. A red dot should appear on the left margin of the line with the new breakpoint.
- Step Into - F7
- Step Over - F8
- Resume - F9
Java Programming
Install the SDK from Oracle: http://www.oracle.com/technetwork/java/javase/downloads/index.html
A good Tutorial is: https://introcs.cs.princeton.edu/java/11hello/
Hello World
// The public class name must match the file name
// However, if there is no public class, then the file name and class names do not have to match.
// Even if there is a public class, you may have any number of non-public classes and they can have any name.
public class HelloWorld {
//////////////////////////////////////////
public static void
main(String[] args) {
System.out.println("Hello, World!");
} // main()
} // class HelloWorld
To Compile: javac HelloWorld.java
To Run: java HelloWorld
Packages
These define a named scope, usually at the file granularity. Put somethinig like this at the start ofo a file: package com.dawsondean.medicalDevices.scopeNamee;Built-In Types
6 Primitives: char, int, float, boolean, byte short, long, double 6 Boxed Primitives: Integer, Float, Collection Interfaces Collection - unorodered group of things, may have duplicates Set - unorodered group of things, no duplicates List - Like an array. Inddexed by an integer 0 .... length-1 Map - A group of name/value pairs Collection Base Types (Implementations) ArrayList - implements list LinkedList - implements list HashSet - implements set HashMap - implements Map TreeMap - implements Map Generics are like template types in C++. Basically, it is a macro for types. List
Iterators
for (iterator iter = list.iterator(); iter.hasNext();) {
string s = iter.next();
}
for (string s: list) {
}
Interfaces and Classes
These are like pure virtual base classes in C++
public interface MyAPI {
void foo();
}
extends - subclass a parent class
implements - implement an interface
public class CMyClass implements MyAPI, YourAPI extends MyBaseClass
@override
public void foo() {
}
}
Note that all method bodies are inline.
You can only extend one base class but you can implement any number of interfaces
Common Classes
Object - basetype of all casses. Any synchronization methods work on a type Object so it may alsoo be used to make a concrete instance
String
Anonymous Classes
fooSetListener (
new CListenerClass () [
public void myCallback(int foo) {
// Do something.
} // myCallback
} // CListenerClass
);
An anonymous class can only access "final" variabales that are defined in the surrounding scope.
The life of the anonymous class may extend beyond the life of the parent scope, which may happen often if an anonymous class is a callback.
Keywords
static On a Variable: A global variable, not associated with a specific object instance. Variables are by default dynamic. On a Method: A global method, not associated with a specific object instance. Methods are by default dynamic. On a Class: Class name scope is global. Classes are by default static, A static class does NOT havee access to instance variables of enclosing class final On a Variable: Cannot be changed after initialized On a Method: On a Class: Cannot be subclassed dynamic This is the opposite of static. On a Variable: Associated with a specific object instance. Variables are by default dynamic. On a Method: Associated with a specific object instance. Methods are by default dynamic. On a Class: Class name scope is local to a block of code. A dynamic class may access instance variables of enclosing class. Classes are by default static private On a Variable: - Only visible to the class that contains it, not to subclasses On a Method: - Only visible to the class that contains it, not to subclasses On a Class: package On a Variable: - Visible to the class that contains it, and any other classes in the same package, like "friend" classes in C++ On a Method: - Visible to the class that contains it, and any other classes in the same package, like "friend" classes in C++ On a Class: protected On a Variable: - Only visible to the class that contains it and any subclasses On a Method: - Only visible to the class that contains it and any subclasses On a Class: public: On a Variable: Visible to any code in any package On a Method: Visible to any code in any package On a Class: The class that contains the "main" function for the programExceptions
try {
// do something
} catch (Exception e) {
// do soething
}
public void Foo() throws Exception {
throw new Exception();
}
Worker Threads
public class myThreadClass implements Runnable {
@override
public void run() {
// do something
}
} myThreadClass
To fork:
myThreadClass worker = new myThreadClass();
Thread t = new Thread(worker);
t.start();
The synchronized keywork is like Monitor methods in Mesa - it can only have one active call in all threads.
class CMyClass {
privaate Object m_Lock = new Object();
public synchronized void foo1() {
// Do Something
}
public void foo2() {
synchronized(this);
// Do Something
}
public void foo3() {
synchronized(m_Lock);
// Do Something
}
}
Other synchronization primitives
Thread.sleep(1000); // static methodds, sleeps for n ms
this.notifyAll(); // wakee up all threads blocked on this thread
yourRunnableObject.wait(); // block on a Runnable object calldd "yourRunnableObject"
public static final class CMyAsyncWorker extends AsyncTask {
private final m_LocalVar;
///////////////////////////////////////////////////////
public
CMyAsyncWorker(int foo) {
m_LocalVar = foo;
} // CMyAsyncWorker
///////////////////////////////////////////////////////
// Runs on parent thread
@override protected void
onPreExecute() {
} // onPreExecute
///////////////////////////////////////////////////////
// Runs on worker thread
@override protected workerResult
doInBackground(workerParam param) {
workerResult x;
return(x);
} // doInBackground
///////////////////////////////////////////////////////
// Runs on parent thread
@override protected void
onProgressUpdate(progressParam param) {
} // onProgressUpdate
///////////////////////////////////////////////////////
// Runs on parent thread
@override protected void
onPostExecute(workerResult param) {
} // onPostExecute
///////////////////////////////////////////////////////
// Runs on parent thread
@override protected void
onProgressUpdate(progressParam param) {
} // onProgressUpdate
} // CMyAsyncWorker
To fork the thread:
new CMyAsyncWorker(31).execute(workerParam);
Note: each instance of a AsyncTask can only be executed once.
To update progress counter
threadObject.publishProgress(param);
Java threads can be a subtype of "Looper" which is a worker thread ad a job queue
Static Analyzers
- FindBugsAndroid Programming
App Components
Applications are made of high level components 1. Activity - A unit of interaction, typically one view or tool or screen withinn an app. It is a unit of execution, and may be started or stopped at any time during an app's lifetime
public class MyActivity extends Activity {
private final String myTag = this.getClass().getSimpleName();
private final String restoreTag = ", can restore state";
private final String myState = "MyStateXML";
///////////////////////////////////////////////////////
@override public void
onCreate(Bundle savedState) {
super.onCreate(savedState);
// Use resource definitions to build the View tree for the default view
setContentView(R.Layaout.main);
// If we are being reactivated, rather than initializing for the first time, then restore any state
// we saved when we were last suspended.
if (null != savedState) {
myState = savedState.getString("value");
}
Log.i(myTag, "onCreate");
} // onCreate
///////////////////////////////////////////////////////
@override public void
onRestart() {
super.onRestart();
Log.i(myTag, "onRestart");
} // onRestart
///////////////////////////////////////////////////////
// The activity is starting
@override public void
onStart() {
super.onRestart();
Log.i(myTag, "onStart");
} // onStart
///////////////////////////////////////////////////////
// The activity will interact with the user
@override public void
onResume() {
super.onResume();
Log.i(myTag, "onResume");
} // onResume
///////////////////////////////////////////////////////
// The activity will stop interacting with the user
@override public void
onPause() {
super.onPause();
Log.i(myTag, "onPause");
} // onPause
///////////////////////////////////////////////////////
// The activity is now invisible
@override public void
onStop() {
super.onStop();
Log.i(myTag, "onStop");
} // onStop
///////////////////////////////////////////////////////
// The activity is being shutdown
@override public void
onDestroy() {
super.onDestroy();
Log.i(myTag, "onDestroy");
} // onDestroy
} // MyActivity
Activity objects may be suspended and deleted any time the system needs more resources.
Each activity must be able to save and restore its state at any time so deleting/recreating an activity is invisible to the user.
2. Intent - is a message to start an activity, and also passes initial parameters tot he activity
initializiation. A single intent may cause one or more activities to start
3. Service - Implements background tasks but has no UI, like a Unix daemon process.
4. ContentProvider - provides a data stream, from either local or remote data.
For example, the local contacts list is accessed through a local ContentProvider.
Each ContentProvider supports a REST model, and provides basic methods:
insert()
query()
update()
delete()
A "ContentResolver" will find the content provider that supplies a particular type of data.
Cursor cur = getContentResolver().query(
android.provider.ContactsContract.Data.CONTENT_URI,
new String() { android.provider.ContactsContract.Data._IO, android.provider.ContactsContract.Phone.NUMBER },
null,
null,
null);
The URI that describes a content provider is of the form content://
public class MyActivity extends Activity {
private static class MyWidget extends View {
public MyWidget() [ }
@override protected void onMeasure(int w, int h) { }
@override protected void onDraw(Canvas canvas) { }
} // MyWidget
@override protected void onCreate(Bundnle state) { }
} // MyActivity
Serialization
When any Activity is suspended, its state is serialized to a persistent object called a "Bundle". Each Activity is seperately serializzable.
public class CMyClass extends Activity {
private static class CAppState implements serializable {
}
private CAppState m_AppState;
///////////////////////////////////////////////////////
// Override an Activity method
@override public void
onCreate(Bundle savedAppState) {
super.onCreate(savedAppState);
// If savedAppState is null, then this is the first initialization
if (null == savedAppState) {
m_AppState = new CAppState;
} else {
m_AppState = (CAppState) savedAppState.getSerializable(APP_STATE);
}
} // onCreate
///////////////////////////////////////////////////////
// Override an Activity method
@override protected void
onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putSerializable(APP_STATE, m_AppState);
} // onSaveInstanceState
///////////////////////////////////////////////////////
// Override an Activity method
@override protected void
onRestoreInstanceState(Bundle savedAppState) {
super.onRestoreInstanceState(savedAppState);
m_AppState = (CAppState) savedAppState.getSerializable(APP_STATE);
} // onSaveInstanceState
} // CMyClass
Additionally, Java objects can implement the "Parceable" interface that supports fast efficient marshalling for IPC.
This implements a WriteToParcel method, as well as a CREATOR objest that is a special constructor that takes a marshalled state and unmarshalls a runtime object.
It also has get/set methods for all state variables
Project Directory
myApp
|
| - AndroidManifest.xml
|
| - src/
| Source code, as .java files
|
| - bin/
| Compiled classes, .class files
|
| - gen/
| Compiler generated source code
|
| - res/
|
| - layout/
|
| - drawable/
| Images, drawable XML
|
| - raw/
| Data files to be loaded as streams
|
| - values/
| XML files containing strings and numbers
You may further specify several layouts, each for a different device or configuration.
For example,
res/layout/main.xml
may be augmented with:
res/layout-land/main.xml // Landscape screen
res/layout-port/main.xml // Portrait screen
You can also have different configurations for screen size, pixel density, language, region, docking state, and more
Android resolves the same constant "layout/main.xml" to the specific layout option using the current system state.
Resources
Java reads .xml files in res/ directory and stores the compiled data in the bin/ dir All resources are accessed at runtime with an object of class "Context" The Activity class and Service class both extend the Context class, so all activities and services have access to context methods. The getResources method in the parent Context class will return a runtime context object. For example: String s = this.getResoources().getString(...); So, how do you identify individual resources at runtime? Java generates a runtime class, names "R", at cocmpile time, and R contains all resource names. Really, this is just like a bunch of constants, but it is accessed through static members of a public and globally available class. So, for example: String s = this.getResoources().getString(R.string.hello_world);Manifest Files
This is an XML file that declares activities, content providers and other coponents of an App. It also declares required permissions for running the app so a usere may decide whether to use an App.
<!-- Package is the default package. versionCode and versionName describe the app, not Android itself -->
<?xml encoding="utf-8" ?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.dawsondean.medicalDevices.scopeNamee;"
android:versionCode="1"
android:versionName="1.0">
<!-- Permissions required by this app -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<application .android:icon="@drawable/icon"
android: label="@string/app_name"
android:debuggable="true>
</application>
<activity android:name=".MainConsole"
android: label="Main Console">
</activity>
<provider android:name=".MainConsole"
android: authorities="xxxxxxxxxx">
</provider>
<service android:name=".MainConsole"
android: label="Main Console">
</service>
<receiver android:name=".MainConsole"
android: label="Main Console" />
<uses-sdk android:minsdkVersion="7" />
</manifest>
.apk files
This is the final binary package that will be delivered to users The apkbuilder application will generate one of these from a compiled source tree you run the apk file in an emulator or else upload to the store or a web server.Libraries
Here are some of the key Android libraries android.view android.graphics android.widget android.text android.app android.content android.databases android.telephone android.webkit java.lang java.util All of the built in classes like collections javax Not part of the required Java spec but common and useful Contaians XML libraries org.apachee.http The apache http client org.w3c.dom org.xml.sax org.xmlpull org.jsonPublishing an App to the Android Store
Sign your binary with a public/private key pair. This does not have to come from a signing authority, like verisign, but cana be self-generated. Any debug build will by default use a special debug key, so it is automatically signed for fast development testing. These keys are in the ~/.android/debug.keystore file. You use the "keytool" command to inspect this, and keytool is part of JDK. For example, run "keytool -list -keystore debug.keystore". The password to this keystore is by default "android". 1. You can then create a private key with keytool: "keytool -genkey -v -keystore my-release-key.keystore -aliasViews
View comes from the MVC Model Model - the engine of an app View - The display to show state to the user Controller - the user input that drives program actions A view is like a window in Windows. There is a tree of views, each is a rectangle of screen real estate. Views can contnain child views, the rectangle of a child view is clipped by its parent. Views are used to make buttons and controls. Internal tree nodes are often called "container views" and leafs are often informally called widgets because they implement both view and controller roles. All leaf nodes are subclasses of android.view.View All container views are subclasses of android.view.ViewGroup, which in turn is a subclass of View LinearLayout is a class of container views that arrange children in a line, either a single row or column. Each app has a single FIFO EventQueue, which is a sequential queue of events generated by user actions and other UI activity (for example, Redraw is an event) The Android base classes will implement the main event loop, andd pull events off the head of the queue and call the appropriate callback method. All UI components may override the default callbacks so they will be called for specific events. The UI is single threaded.Programattically Creating a Tree of Views in a App
private LinearLayout root;
@override public void
onCreate(savedInstanceState) {
super.onCreate(savedInstanceState);
LinearLayout.LayoutParaams containenrParams
= new LinearLayout.LayoutParaams(
ViewGroup.LayoutParaams.FILL_PARENT,
ViewGroup.LayoutParaams.WRAP_CONTENT,
0.0F);,
LinearLayout.LayoutParaams widgetParams
= new LinearLayout.LayoutParaams(
ViewGroup.LayoutParaams.FILL_PARENT,
ViewGroup.LayoutParaams.FILL_PARENT,
1.0F);
root = new LinearLayout(this);
root.setOrientation(LinearLayout.VERTICAL);
root.setBackgroundColor(Color.LTGRAY);
root.setLayoutParams(containenrParams);
LinearLayout l1 = new LinearLayout(this);
l1.setOrientation(LinearLayout.HORIZONTAL);
l1.setBackgroundColor(Color.LTGRAY);
l1.setLayoutParams(containenrParams);
root.addview(l1);
EditText tb = new EditText(this);
tb.setText(R.string.defaultText);
tb.setFocusable(false);
tb.setLayoutParams(widgetParams);
l1.addView(tb);
Button b = new Button(this);
b.setText(R.string.labelRed);
b.setTextColor(Color.RED);
b.setLayoutParams(widgetParams);
l1.addView(b);
setContentView(root);
} // onCreate
Creating a Tree of Views in a App With Resources
private LinearLayout g_RootView;
private EditText g_TextBox;
private Button g_Button;
@override public void
onCreate(savedInstanceState) {
super.onCreate(savedInstanceState);
// Create a tree of views from a resource
setContentView(R.Layaout.main);
// Get UI components
g_RootView = (LinearLayout) findViewById(R.id.root);
g_Button = (Button) findViewById(R.id.myButton);
g_TextBox = (EditText) findViewById(R.id.myText);
// Create and register a callback.
Button.OnClickListener listenet = new Button.OnClickListener() {
@override public void
onClick(View arg0) {
// Do some work here
} // onClick
} // End of anon class
g_Button.setOnClickListener(listener);
// Listen for taps - user finger events on the touch-sensitive screen.
// NOTE: Trackball events are handled differently - they are converted to D-pad keystrokes
// Touch events are a lot like mouse clicks, with separate events for DOWN, MOVE, UP
// For efficiency, not all events may be reported. But a MOVE event may batch together several coordinates into a single event.
// The method can call event.getHistoricalX(index), and event.getHistoricalY(index) and more to get all intermediate drag positions
// since the last time it was callled.
View.OnTouchListener listener2 = new View View.OnTouchListener{
@override public boolean
onTouch(View v, MotionEvent event) {
// Do some work here
} // onTouch
} // End of anon class
g_RootView.setOnTouchListener(listener2);
} // onCreate
Event Listeners
Each View class defines event processing methods, like OnTouch and OnKey. These are built-intoo the View class. You may define a View subclass that overrides these methods. Additionally, every view object may ALSO have a listener object, that sees events first. The listener may process events before the View object. This lets you intercept events even if you do not implement or subclass the View. Each event method in the listener returns a boolean (true/false) that tells the framework whether the event has been consumed. If there is no listener or else the listener method returns false, then the framework will pass the event on to the View.Touch Events
The same OnTouch callback can be used to handle several types of touch events.
onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
///////////////////////////////////////
case MotionEvent.ACTION_DOWN:
break;
///////////////////////////////////////
case MotionEvent.ACTION_UP:
break;
///////////////////////////////////////
case MotionEvent.ACTION_MOVE:
break;
} // switch
return(true);
} // onTouch
Information about a single event comes from the event object
event.getX()
event.getY()
event.getPressure()
event.getSize()
Additionally, several events may be batches in a single MOVE event. This will describe each point in the path of movement
event.getHistoricalX(index)
event.getHistoricalY(indnex)
event.getHistoricalPressure(indnex)
event.getHistoricalSize(indnex)
Additionally, a single event may descrbe several pointers, such as when you zoom with 2 fingers
event.getX(pointerIndex)
event.getY(pointerIndex)
event.getPressure(pointerIndex)
event.getSize(pointerIndex)
This tells you how many pointers are active.
event.getPointerCount();
But, the same pointer may show up at different indexes for different events.
In this case, use the pointerId to find which index will access it.
To get the id of a particular index
index = (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK;
index = index >> MotionEvent.ACTION_POINTER_INDEX_sHIFT;
pointerId = event.getPointerId(index);
Then for every event, to get the index of a particular id
index = event.findPointerIndex(pointerId);
Key Events
View.OnKeyListener listener2 = new View View.OnKeyListener{
@override public boolean
onKey(View v, int keyCode, MotionEvent event) {
switch (event.getAction()) {
///////////////////////////////////////
case KeyEvent.ACTION_DOWN:
break;
///////////////////////////////////////
case KeyEvent.ACTION_UP:
switch (keyCode) {
case KeyEvent.KEYCODE_SPACE:
break;
}
break;
///////////////////////////////////////
case KeyEvent.ACTION_MULTIPLE:
event.getRepeatCount();
break;
} // switch
return(true);
} // onKey
} // End of anon class
g_RootView.setOnKeyListener(listener2);
Focus Events
This handles selecting/deselecting a selected control withinn a view.
View.OnFocusChangeListener listener2 = new View View.OnFocusChangeListener{
@override public boolean
onFocusChange(View v, boolean hasFocus) {
return(true);
} // onFocusChange
} // End of anon class
g_RootView.setOnFocusChangeListener(listener2);
You can also call
widget.requestFocus();
to select a specific widget..
Focus is best for text edit widgets. You do *NOT* have to focus a button before clicking it.
Multithreading and Handlers
This is a thread-safe way of calling another thread in a way that is synchronized with that thread's event queue. For example, this is very handy to call the main UI thrad from another worker thread. On the UI thread, call this: private final Handler myHandler = new Hanadler(); On the worker thread call this:
private final Runnable myRunnable;
myRunnable = new Runnable() {
public void
run() {
// Do something.
} // run()
}; // myRunnable anon class
myHandler.post(myRunnable);
A Handler object is associated with the thread on which it is created. For example, if it is created on the UI thread then iti is associated with the UI thread.
It may be invoked (via a post method) from any thread. Post takes a runnable object aand will execute that object on the associated thread. For example,
call post(myObj) frorm a worker thread and then myObj is run on the UI thread and is synchronized witht he event queue of the UI thread.
Menus
The old style of a single optionMenu is being deprecated in favor of the newer model of an action bar. You can create a single menu that is compatible with a task bar. In the View subclass, override the following:
@override
public boolean
OnCreateOptionsMenu(Menu menu) [
getMenuInflater().inflate(R.menu.simple_menu, menu);
return(true);
} // OnCreateOptionsMenu
@override
public boolean
OnOptionsItemSelected(MenuItem menuItem) [
switch(menuItem.getItemId()) {
case R.id.menu_clear:
break;
} // switch
return(true);
} // OnOptionsItemSelected
Fragments
Views may be swapped out, so one is always visible, but this forms a simple card-stack like interface. A fragment is a persistently visible view, so it can be a side-bar. Fragments are similar to views, and have similar event handler callbacks. Fragments are loaded by an XML specification, just like vieiws, with setContentView(r.layout.myFragment); Fragments have callbacks onSaveInstanceState just like views Fragments can be added to ViewGroup and Layout objects, so it acts like a view. But it outlives a particular ViewGroup However... Fragments are not Contexts Fragments have a lifecycle tied to an Activity, not a specific view. In the XML declaration, a fragment will specify a class name that implements that class. The class must be publicly visible within the application AND the class must subclass the "Fragment" class, not Activity or View The subclass should NOT have a constructor - do the initializataion later in response to an early event An object instance of the class will be created when the fragment XML isi loaded
public class MyFrag extends Fragment {
//////////////////////////////
public void
onCreate(Bundle state) {
super.onCreate(state);
// Do init here that would normally be done in a constructor method.
} // onCreate
//////////////////////////////
public View
onCreateView(LayoutInflator inflator, ViewGroup container, Bundle b) {
View view inflator.inflate(R.layout.myLayout, container, false); // Must pass false
// Init the view
return(view);
} // oCreateView
} // MyFrag
Note, you create the view separately than when the fragment is created.
The contnainer will eventually be the parent to the inflated fragment view (calaled a shard).
BUT, the fragment owns the inflated view, so it is dispplayed in the parent container but it may have a lifespan that outlives the parent container. It is not tied
to the parent contnainer.
The object instance of the fragment object may either be created byt he system when the xml formata is loaded or else explicitly.
But, never replace a fragment that is created by an XML init with one that is explicitly created - their lifetimes are different and this
will lead to dangling references.
Each Activity has a single Fragment Manager, which finds Fragments. This is used to ensure a fragment is only created once, but also to
allow sendingn IPC messages to a fragment.
FragmentManager fragMgr = getFragmentManager();
xxx myFrag = frgMgr.findFragmentByTaga(MY_FRAG_NAME_STRING);
Fragments also allow a caller to call setArguments and getArguments on a newly created fragment.
This lets you pass in initialization state, like a Bundle, to a fragment so it can use it when the fragment OnCreate is eveentually called..
You can also group operations on fragments into a single atomic transaction by calling
FragmentManager fragMgr = getFragmentManager();
FragmentTransaction xact - fragManager.beginTransaction();
...
xact.commit();
Custom Widgets
A widget is a subclass of android.view.View, and is usually a leaf node in the tree of containers andn views. A widget implements the calalbacks for drawing and handling user input like touches. For Drawing, a widget must implement the layout and rendering callbacks.Layout
The systm wiil periodically re-layout the UI, whenever conditions like landscape/portrait change. Widgets can also request the system re-layout the widget anytime their state or presentation changes. The widget or the system triggers layout by calling requestLayout(view) on a widget or parent contaiiner view. Each widget then implements the onMeasure method, which is called by the layout manager code in the parent container view. onMeasure may be called several times, each time is asking for desired width and height of the widget onMeasure takes 2 args, the width andd height spec. The widget calls MeasureSpec.getMode and MeasureSpec.getSize on these parameters to parse them The size if a size in pixels and the spec is one of: MeasureSpec.EXACTLY, MeasureSpec.AT_MOST, MeasureSpec.UNSPECIFIED The spec lets a parent ask for different constraints, whether it wants an exacly or max size. The widget returns a desired width and height by setting height and width properties, which is really just member vars. Don't set these directly, call setMeasuredDimension(); Android will raise an excepetion if onMeasure returns but setMeasuredDimension has not been called. The default implementation of on Measure will call setMeasuredDimension with width and height dependning on the mode passed in by the caller MeasureSpec.EXACTLY - Use the sizes suggested by the called MeasureSpec.AT_MOST - Use the sizes suggested by the called MeasureSpec.UNSPECIFIED - Use valur returned by getSuggestedMinimumWidth and getSuggestedMinimumHeieght Once the parent container has chosen a suze for each child widget, it will call onLayout on each childl widget and pass in the actual width and height. Note, a widget may not get the width or height it requested. The widget uses this to configure its state. Alternatively, the widget can examaine the ClipRect on Draw, since that is also set to the final dimensions of the widget.
public class MyWidget extends View {
//////////////////////////////////////////
public MyWidget(arg1) {
// Constructor
}
//////////////////////////////////////////
// Request screen space from the parent UI element. This method mmay be called several times, and
// may not get the space it requests. The final allocated size will be passed to OnLayout (which usually only
// container views implememnt) and is also sete in the view clipRect before onDraw. Examine the view clip rect
// in onDraw to see the actual size.
@override
protected void
onMeasure(int widthSpec, int heightSpec) {
setMeasuredDimension(getSuggestedMinimumWidth(), getSuggestedMinimumheight());
} // onMeasureSpec
} // MyWidget
Drawing
To force a redraw, call view.invalidate(); This queues a draw event and then the system will eventually call the onDraw() method for the widgets. Basic Drawing Data Structures 1. Canvas Maintains the clip rectangle and scales drawing. It is a parameter to OonDraw(); It is a subclass of android.graphics.Canvas. Basic methods include drawing a line or geometric shapes, drawing text, Canvas also supports matrix operations to scale or rotate or stretch a canvas. Besides 2D operatioins, these can be used to implemment 3D views. Canvas also lets you save and restore the configuratioin of drawing, so you can draw a background with one style, then save the state, draw the foreground using a different style, then restore the state and draw more background in the original background style. 2. Paint The drawing implememnt - contnrools color, brush size, transparency, font, text size and more onDraw will create one of these when needed. It is a subclass of android.graphics.Paint Paint objects may have seveeral attributes includingn shadow effects, shaders (which transition a pain from one color into another color), 3. Bitmap It is a subclass of android.graphics.Bitmap This is usually maintainend in internal state of a Canvas. You may expllicitly manipulate them if you want to dod double buffering or caching previously-rendered bitmaps. On Init:
private Bitmap myBitmap;
myBitmap = Bitmap.createBitmap(
getMeasuredWidth(),
getMeasuredHeight(),
Bitmap.Configi.ARGB_8888);
Canvas tempCanvas =new Canvas(myBitmap);
myDraw(tempCanvas);
On draw:
canvas.drawBitmap(myBitmap, 0, 0, new Paint());
You can also load constant bitmaps from resources to draw them.
BitmapDrawable myRsrcBitmap = resource.Resources.geteDrawable()
4. Drawable
A pattern to be drawn, like a rectangle or circle.
It is a subclass of android.graphics.Drawable
public class MyWidget extends View {
public MyWidget(arg1) {}
@override protected void onMeasure(int widthSpec, int heightSpec) { }
//////////////////////////////////////////
@override
protected void
onDraw(Canvas canvas) {
??? setBackground()???
canavas.drawColor(Color.WHITE);
Paint myPaint = new Paint();
myPaint.setColor(Color.GREEN);
myPaint.setStrokeWidth(10);
canvas.drawLine(1, 2, 101, 102, myPaint);
canvas.drawText("Hello, world", startX, startY, myPaint);
} // onDraw
} // MyWidget
A widget can also override the isOpaque() method. If it returns true, then the system will not try to draw any
part of the screen occluded by the widget. This helps performance.
Drawables
You can also subclass a Drawable, and then have the View call Draw() on your Drawable subclass.
public class MyDrawable extends Drawable {
public MyDrawable(arg1) {}
//////////////////////////////////////////
@override
protected void
draw(Canvas canvas) {
} // draw
//////////////////////////////////////////
@override
protected int
getOpacity() {
return(PixelFormat.TRANSLUCENT);
}
//////////////////////////////////////////
@override
protected void
setAlpha(int value) {
}
//////////////////////////////////////////
@override
protected void
setColorFilter(ColorFilter value) {
}
} // MyDrawable
A view then calls
drawable.draw(canvas);
Note that a Drawable implements draw() not onDraw because it is not an explicit part
of the event processing - it is a graphics
primitive. Moreover, the caller can apply any transformation to the canvas before passing
it to the Drawable object, so the same Drawable
can be used for any arbitraty stretch, scale, skew, 3D rotate or other perspectivie.
A Drawable's position is set in instance variables, there is not a way to specify the coordinates when the drawable is rendered.
Drawables do not negotiate their size with measure/layout methods.