• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
484if [[ $(type -t compopt) = "builtin" ]]; then
485    complete -F _adb adb
486else
487    complete -o nospace -F _adb adb
488fi
489