1 # /* vim: set ai ts=4 ft=sh: */ 2 # 3 # Copyright 2011, The Android Open Source Project 4 # 5 # Licensed under the Apache License, Version 2.0 (the "License"); 6 # you may not use this file except in compliance with the License. 7 # You may obtain a copy of the License at 8 # 9 # http://www.apache.org/licenses/LICENSE-2.0 10 # 11 # Unless required by applicable law or agreed to in writing, software 12 # distributed under the License is distributed on an "AS IS" BASIS, 13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 # See the License for the specific language governing permissions and 15 # limitations under the License. 16 # 17 18 _adb() { 19 unset -v have 20 type $1 &> /dev/null && have="yes" 21 22 if [ "$have" != "yes" ]; then 23 return 24 fi 25 26 local where i cur serial 27 COMPREPLY=() 28 29 serial="${ANDROID_SERIAL:-none}" 30 where=OPTIONS 31 for ((i=1; i <= COMP_CWORD; i++)); do 32 cur="${COMP_WORDS[i]}" 33 case "${cur}" in 34 -s) 35 where=OPT_SERIAL 36 ;; 37 -p) 38 where=OPT_PATH 39 ;; 40 -*) 41 where=OPTIONS 42 ;; 43 *) 44 if [[ $where == OPT_SERIAL ]]; then 45 where=OPT_SERIAL_ARG 46 serial=${cur} 47 else 48 where=COMMAND 49 break 50 fi 51 ;; 52 esac 53 done 54 55 if [[ $where == COMMAND && $i -ge $COMP_CWORD ]]; then 56 where=OPTIONS 57 fi 58 59 OPTIONS="-d -e -s -p" 60 COMMAND="devices connect disconnect push pull sync shell emu logcat lolcat forward jdwp install uninstall bugreport help version start-server kill-server get-state get-serialno status-window remount reboot reboot-bootloader root usb tcpip disable-verity" 61 62 case $where in 63 OPTIONS|OPT_SERIAL|OPT_PATH) 64 COMPREPLY=( $(compgen -W "$OPTIONS $COMMAND" -- "$cur") ) 65 ;; 66 OPT_SERIAL_ARG) 67 local devices=$(command adb devices 2> /dev/null | grep -v "List of devices" | awk '{ print $1 }') 68 COMPREPLY=( $(compgen -W "${devices}" -- ${cur}) ) 69 ;; 70 COMMAND) 71 if [[ $i -eq $COMP_CWORD ]]; then 72 COMPREPLY=( $(compgen -W "$COMMAND" -- "$cur") ) 73 else 74 i=$((i+1)) 75 case "${cur}" in 76 install) 77 _adb_cmd_install "$serial" $i 78 ;; 79 sideload) 80 _adb_cmd_sideload "$serial" $i 81 ;; 82 pull) 83 _adb_cmd_pull "$serial" $i 84 ;; 85 push) 86 _adb_cmd_push "$serial" $i 87 ;; 88 reboot) 89 if [[ $COMP_CWORD == $i ]]; then 90 args="bootloader recovery" 91 COMPREPLY=( $(compgen -W "${args}" -- "${COMP_WORDS[i]}") ) 92 fi 93 ;; 94 shell) 95 _adb_cmd_shell "$serial" $i 96 ;; 97 uninstall) 98 _adb_cmd_uninstall "$serial" $i 99 ;; 100 esac 101 fi 102 ;; 103 esac 104 105 return 0 106 } 107 108 _adb_cmd_install() { 109 local serial i cur where 110 111 serial=$1 112 i=$2 113 114 where=OPTIONS 115 for ((; i <= COMP_CWORD; i++)); do 116 cur="${COMP_WORDS[i]}" 117 case "${cur}" in 118 -*) 119 where=OPTIONS 120 ;; 121 *) 122 where=FILE 123 break 124 ;; 125 esac 126 done 127 128 cur="${COMP_WORDS[COMP_CWORD]}" 129 if [[ $where == OPTIONS ]]; then 130 COMPREPLY=( $(compgen -W "-d -l -r -s" -- "${cur}") ) 131 return 132 fi 133 134 _adb_util_complete_local_file "${cur}" '!*.apk' 135 } 136 137 _adb_cmd_sideload() { 138 local serial i cur 139 140 serial=$1 141 i=$2 142 143 cur="${COMP_WORDS[COMP_CWORD]}" 144 145 _adb_util_complete_local_file "${cur}" '!*.zip' 146 } 147 148 _adb_cmd_push() { 149 local serial IFS=$'\n' i cur 150 151 serial=$1 152 i=$2 153 154 cur="${COMP_WORDS[COMP_CWORD]}" 155 156 if [[ $COMP_CWORD == $i ]]; then 157 _adb_util_complete_local_file "${cur}" 158 elif [[ $COMP_CWORD == $(($i+1)) ]]; then 159 if [ "${cur}" == "" ]; then 160 cur="/" 161 fi 162 _adb_util_list_files $serial "${cur}" 163 fi 164 } 165 166 _adb_cmd_pull() { 167 local serial IFS=$'\n' i cur 168 169 serial=$1 170 i=$2 171 172 cur="${COMP_WORDS[COMP_CWORD]}" 173 174 if [[ $COMP_CWORD == $i ]]; then 175 if [ "${cur}" == "" ]; then 176 cur="/" 177 fi 178 _adb_util_list_files $serial "${cur}" 179 elif [[ $COMP_CWORD == $(($i+1)) ]]; then 180 _adb_util_complete_local_file "${cur}" 181 fi 182 } 183 184 _adb_cmd_shell() { 185 local serial IFS=$'\n' i cur 186 local -a args 187 188 serial=$1 189 i=$2 190 191 cur="${COMP_WORDS[i]}" 192 if [ "$serial" != "none" ]; then 193 args=(-s $serial) 194 fi 195 196 if [[ $i -eq $COMP_CWORD && ${cur:0:1} != "/" ]]; then 197 paths=$(command adb ${args[@]} shell echo '$'PATH 2> /dev/null | tr -d '\r' | tr : '\n') 198 COMMAND=$(command adb ${args[@]} shell ls $paths '2>' /dev/null | tr -d '\r' | { 199 while read -r tmp; do 200 command=${tmp##*/} 201 printf '%s\n' "$command" 202 done 203 }) 204 COMPREPLY=( $(compgen -W "$COMMAND" -- "$cur") ) 205 return 0 206 fi 207 208 i=$((i+1)) 209 case "$cur" in 210 ls) 211 _adb_shell_file_command $serial $i "--color -A -C -F -H -L -R -S -Z -a -c -d -f -h -i -k -l -m -n -p -q -r -s -t -u -x -1" 212 ;; 213 cat) 214 _adb_shell_file_command $serial $i "-h -e -t -u -v" 215 ;; 216 dumpsys) 217 _adb_cmd_shell_dumpsys "$serial" $i 218 ;; 219 am) 220 _adb_cmd_shell_am "$serial" $i 221 ;; 222 pm) 223 _adb_cmd_shell_pm "$serial" $i 224 ;; 225 /*) 226 _adb_util_list_files $serial "$cur" 227 ;; 228 *) 229 COMPREPLY=( ) 230 ;; 231 esac 232 233 return 0 234 } 235 236 _adb_cmd_shell_dumpsys() { 237 local serial i cur 238 local -a args 239 local candidates 240 241 unset IFS 242 243 serial=$1 244 i=$2 245 246 if [ "$serial" != "none" ]; then 247 args=(-s $serial) 248 fi 249 250 if (( $i == $COMP_CWORD )) ; then 251 cur="${COMP_WORDS[COMP_CWORD]}" 252 # First line is a header, so need "1d". 253 candidates=$(command adb ${args[@]} shell dumpsys -l 2> /dev/null | sed -e '1d;s/^ *//' | tr -d '\r') 254 candidates="-l $candidates" 255 COMPREPLY=( $(compgen -W "$candidates" -- "$cur") ) 256 return 0 257 fi 258 259 COMPREPLY=( ) 260 return 0 261 } 262 263 _adb_cmd_shell_am() { 264 local serial i cur 265 local candidates 266 267 unset IFS 268 269 serial=$1 270 i=$2 271 272 if (( $i == $COMP_CWORD )) ; then 273 cur="${COMP_WORDS[COMP_CWORD]}" 274 candidates="broadcast clear-debug-app clear-watch-heap dumpheap force-stop get-config get-inactive hang idle-maintenance instrument kill kill-all monitor package-importance profile restart screen-compat send-trim-memory set-debug-app set-inactive set-watch-heap stack start startservice start-user stopservice stop-user suppress-resize-config-changes switch-user task to-app-uri to-intent-uri to-uri" 275 COMPREPLY=( $(compgen -W "$candidates" -- "$cur") ) 276 return 0 277 fi 278 279 COMPREPLY=( ) 280 return 0 281 } 282 283 284 _adb_cmd_shell_pm() { 285 local serial i cur 286 local candidates 287 288 unset IFS 289 290 serial=$1 291 i=$2 292 293 if (( $i == $COMP_CWORD )) ; then 294 cur="${COMP_WORDS[COMP_CWORD]}" 295 candidates="-l -lf -p clear create-user default-state disable disable-until-used disable-user dump enable get-app-link get-install-location get-max-users grant hide install install-abandon install-commit install-create install-write list move-package move-primary-storage path remove-user reset-permissions revoke set-app-link set-installer set-install-location set-permission-enforced trim-caches unhide uninstall" 296 COMPREPLY=( $(compgen -W "$candidates" -- "$cur") ) 297 return 0 298 fi 299 300 if (( $i + 1 == $COMP_CWORD )) && [[ "${COMP_WORDS[COMP_CWORD -1]}" == "list" ]] ; then 301 cur="${COMP_WORDS[COMP_CWORD]}" 302 candidates="packages permission-groups permissions instrumentation features libraries users" 303 COMPREPLY=( $(compgen -W "$candidates" -- "$cur") ) 304 return 0 305 fi 306 307 COMPREPLY=( ) 308 return 0 309 } 310 311 _adb_cmd_uninstall() { 312 local serial i where cur packages 313 314 serial=$1 315 i=$2 316 if [ "$serial" != "none" ]; then 317 args=(-s $serial) 318 fi 319 320 where=OPTIONS 321 for ((; i <= COMP_CWORD; i++)); do 322 cur="${COMP_WORDS[i]}" 323 case "${cur}" in 324 -*) 325 where=OPTIONS 326 ;; 327 *) 328 where=FILE 329 break 330 ;; 331 esac 332 done 333 334 cur="${COMP_WORDS[COMP_CWORD]}" 335 if [[ $where == OPTIONS ]]; then 336 COMPREPLY=( $(compgen -W "-k" -- "${cur}") ) 337 fi 338 339 packages="$( 340 command adb ${args[@]} shell pm list packages '2>' /dev/null 2> /dev/null | tr -d '\r' | { 341 while read -r tmp; do 342 local package=${tmp#package:} 343 echo -n "${package} " 344 done 345 } 346 )" 347 348 COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -W "${packages}" -- "${cur}") ) 349 } 350 351 _adb_shell_file_command() { 352 local serial i cur file options 353 local -a args 354 355 serial=$1 356 i=$2 357 if [ "$serial" != "none" ]; then 358 args=(-s $serial) 359 fi 360 options=$3 361 362 where=OPTIONS 363 for ((; i <= COMP_CWORD; i++)); do 364 cur="${COMP_WORDS[i]}" 365 case "${cur}" in 366 -*) 367 where=OPTIONS 368 ;; 369 *) 370 where=FILE 371 break 372 ;; 373 esac 374 done 375 376 file="${COMP_WORDS[COMP_CWORD]}" 377 if [[ ${file} == "" ]]; then 378 file="/" 379 fi 380 381 case $where in 382 OPTIONS) 383 unset IFS 384 COMPREPLY=( $(compgen -W "$options" -- "$cur") ) 385 ;; 386 FILE) 387 _adb_util_list_files $serial "$file" 388 ;; 389 esac 390 391 return 0 392 } 393 394 _adb_util_list_files() { 395 local serial dir IFS=$'\n' 396 local -a toks 397 local -a args 398 399 serial="$1" 400 file="$2" 401 402 if [ "$serial" != "none" ]; then 403 args=(-s $serial) 404 fi 405 406 if [[ $( command adb ${args[@]} shell ls -dF / '2>/dev/null' | tr -d '\r' ) == "d /" ]] ; then 407 toks=( ${toks[@]-} $( 408 command adb ${args[@]} shell ls -dF ${file}"*" '2>' /dev/null 2> /dev/null | tr -d '\r' | { 409 while read -r tmp; do 410 filetype=${tmp%% *} 411 filename=${tmp:${#filetype}+1} 412 if [[ ${filetype:${#filetype}-1:1} == d ]]; then 413 printf '%s/\n' "$filename" 414 else 415 printf '%s\n' "$filename" 416 fi 417 done 418 } 419 )) 420 else 421 toks=( ${toks[@]-} $( 422 command adb ${args[@]} shell ls -dp ${file}"*" '2>/dev/null' 2> /dev/null | tr -d '\r' 423 )) 424 fi 425 426 # Since we're probably doing file completion here, don't add a space after. 427 if [[ $(type -t compopt) = "builtin" ]]; then 428 compopt -o nospace 429 fi 430 431 COMPREPLY=( ${COMPREPLY[@]:-} "${toks[@]}" ) 432 } 433 434 _adb_util_complete_local_file() 435 { 436 local file xspec i j IFS=$'\n' 437 local -a dirs files 438 439 file=$1 440 xspec=$2 441 442 # Since we're probably doing file completion here, don't add a space after. 443 if [[ $(type -t compopt) = "builtin" ]]; then 444 compopt -o plusdirs 445 if [[ "${xspec}" == "" ]]; then 446 COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -f -- "${cur}") ) 447 else 448 compopt +o filenames 449 COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -f -X "${xspec}" -- "${cur}") ) 450 fi 451 else 452 # Work-around for shells with no compopt 453 454 dirs=( $(compgen -d -- "${cur}" ) ) 455 456 if [[ "${xspec}" == "" ]]; then 457 files=( ${COMPREPLY[@]:-} $(compgen -f -- "${cur}") ) 458 else 459 files=( ${COMPREPLY[@]:-} $(compgen -f -X "${xspec}" -- "${cur}") ) 460 fi 461 462 COMPREPLY=( $( 463 for i in "${files[@]}"; do 464 local skip= 465 for j in "${dirs[@]}"; do 466 if [[ $i == $j ]]; then 467 skip=1 468 break 469 fi 470 done 471 [[ -n $skip ]] || printf "%s\n" "$i" 472 done 473 )) 474 475 COMPREPLY=( ${COMPREPLY[@]:-} $( 476 for i in "${dirs[@]}"; do 477 printf "%s/\n" "$i" 478 done 479 )) 480 fi 481 } 482 483 484 if [[ $(type -t compopt) = "builtin" ]]; then 485 complete -F _adb adb 486 else 487 complete -o nospace -F _adb adb 488 fi 489