AndroWish: Tips and Tricks

DESCRIPTION

This page is made to share your tips and tricks on this page that can help in making Android applications using AndroWish. Please try to be as specific as you can about AndroWish specific commands e.g. borg and sdltk . and touch screen events Please give as many relevant examples as you can.

Superlinux: An example on using <<PinchToZoom>> .

A simple way to zoom the size of your app by changing the default font of the whole GUI made by Tk :

set font_size 3 ;# default starting font size is set to 3 .

set old_fingers_pinch_to_zoom_distance 0 ;# keeps track of the distance between the pinching fingers before moving the fingers to do the pinch move

proc pinch_to_zoom { fingers_distance } {
    global old_fingers_pinch_to_zoom_distance
    global font_size
    if { $fingers_distance > $old_fingers_pinch_to_zoom_distance } {
         incr font_size
         font configure TkDefaultFont -size $font_size
         set old_fingers_pinch_to_zoom_distance $fingers_distance
         return
       } 
       
    if { $fingers_distance < $old_fingers_pinch_to_zoom_distance } {
            if { $font_size <=3 } {
                  set font_size 3
                  return
               }
            
            incr font_size -1
            font configure TkDefaultFont -size $font_size
            set old_fingers_pinch_to_zoom_distance $fingers_distance
            return
      }      
}


font configure TkDefaultFont -size $font_size

bind . <<PinchToZoom>> { pinch_to_zoom %x } ;# remember that %x is the distance between pinching fingers

# Activate <<PinchToZoom>> virtual event and disable auto zooming
sdltk touchtranslate 3

HaO 2015-03-16: Thanks for the example. The following example takes the font size at the pinch start as reference for the pinch distance. In addition, it scales the distance by the screen size, as screen resolution is highly variant on smart phones.

sdltk touchtranslate 3
set PinchStartFontSize 3
set PinchStartValue 0
bind . <<PinchToZoom>> {+PinchToZoomDo %x %s}

proc PinchToZoomDo {X State} {
    global PinchStartFontSize
    global PinchStartValue
    # State values: 0:Motion, 1:Start, 2:End 1st Finger, 2:End Both Fingers
    switch -exact .. $State {
        1 { # Start
            set PinchStartValue $X
            set PinchStartFontSize [font actual TkDefaultFont -size]
        }
        0 - 2 { # Motion, End
            set FontSize [expr { $PinchStartFontSize + ($X - $PinchStartValue) * 10 / [winfo screenwidth .] }]
            if {$FontSize < 3} {set FontSize 3}
            font configure TkDefaultFont -size $FontSize
        }
    }
}

SSH and SCP to your Android tablet

For the below, you will need SSHDroid installed on your Tablet:

SCP

JM 3/21/2014, If you use Windows PC to edit your scripts, you can use pscp launched like this from the DOS command line:

 pscp -P 2222 C:\Tcl\code\logo2.tcl [email protected]:/sdcard/

In the example I am copying my logo2.tcl script to /sdcard/ on the Android device which IP address is 192.168.1.64 in this case. "admin" is the default password.

SSH

JM 8/9/2014, If using Ubuntu:

 ssh -p 2222 [email protected]

See you specific port and ip address on the SSHDroid screen running on your Android.
default password is "admin"

Sample set of rc files

JM 8/9/2014, my set of rc files...
Instructions:

  1. Create these files (assuming windows) in your PC
  2. copy these 3 files to the Android Tablet
  3. Open Androwish, and launch the script init.tcl

From now on, you will be immediately prompted for the script to run when launching Androwish...

File #1init.tcl

which I only use when I install a new Androwish version:

 file delete /data/data/tk.tcl.wish/files/.wishrc
 file rename -force x.wishrc .wishrc 
 file copy .wishrc /data/data/tk.tcl.wish/files
File #2x.wishrc

File will renamed to hidden .wishrc with the init script above

 set env(HOME) /sdcard
 cd ~
 source wishrc.tcl
File #3wishrc.tcl

this is used to immediately get a file browser dialog to select the script I want to run:

 sdltk textinput on
 set script [tk_getOpenFile]
 if {$script != ""} {
   source $script
   console hide 
 } else {
   puts "hello!"
 }

Superlinux - 2014-03-27 10:35:07

This is an example on how to send your text or HTML file to printing on paper using PrintBot.

You can find PrintBot in this link here

PrinterBot is a network printer driver for Android. It can run Internet Printing Protocol (IPP).

On Linux, as a test, install CUPS-PDF and CUPS printer server and make it shared on the local network.

 borg activity net.jsecurity.printbot.action.PRINT "file:///mnt/sdcard/test-page.txt" "text/html" {} {} {
   borg toast "Printing completed"
 }

ET

Well, AW made my first android tablet purchase worth every penny.

So, here's my .wishrc, with some console fun. Also handy for fat fingers. It adds buttons to the console window.

Warning, careful here if you mangle this, you might not have a console to use to correct your .wishrc file in the protected zone.

I have followed the lead here of having files in /sdcard/home which I can modify, and then copy as needed to the protected AW zone. So, it goes there first, and if wishrc.tcl is found, sources it after it modifies the console window.

The copyit button on the console window will do that for you if you use these folder conventions. It does want a confirmation. Same with exit. The +x/-x resize the x size of the console window. Bottom scrolls you to the bottom, and you can disable scrolling with the checkbox. I also increase the number of lines to 1000.

update: Fixed problem with width adjustments, seems wm geom . is different here than on my winxp system

    if { $tcl_platform(os) != "Windows NT" } { # to test on winxp before going live on android
        set env(HOME) /sdcard/home
        cd ~
    } else {        
        console show
    }
    
    package require Tk
    # a menu item runs this, it's defined here, not inside the console eval
    proc menudo {} {
        puts "pressed-menu"
    }
    if [catch {
        console eval {
            if { ![info exist ::tk::do_scroll] } {
                set menuincr 0 ;# some consoles have an extra item in the edit menu (a font...) AW doesn't, so leave at 0 for now
                set fontsz {times 9}
                pack forget .console .sb .consoleframe
                
                pack [frame  .frame -bg black] -side left -fill y -ipady 2 -pady 2
                pack [button .frame.clear -bg blue -fg white -text Clear -command {.menubar.file invoke 2} -font $fontsz] -side top -fill x
                pack [button .frame.smaller   -bg white -text {font -} -font $fontsz -command {.menubar.edit invoke [expr ( $menuincr+6 )];after 100 {.frame.repos invoke}}] -side top -fill x
                pack [button .frame.bigger    -bg white -text {font +}  -font $fontsz -command {.menubar.edit invoke [expr ( $menuincr+5 )];after 100 {.frame.repos invoke}}] -side top -fill x
                pack [button .frame.exit     -bg red -fg white -text Exit  -font $fontsz -command {exiter}] -side top -fill x
                pack [button .frame.repos -bg white -text Bottom -font $fontsz -command {.console see end; .console mark set insert end}] -side top -fill x
                pack [frame  .frame.frame -bg black] -side top  -fill x
                pack [button .frame.frame.m10 -bg gray  -fg white  -font $fontsz   -text -x -command {
                    if { [.console cget -width] > 30 } {
                        .console config -width [expr ( [.console cget -width]-10 )]
                    }
                }] -side top -fill x -expand 1
                pack [button .frame.frame.p10 -bg gray  -fg white  -font $fontsz   -text +x -command {
                    if { [.console cget -width] < 120 } {
                        .console config -width [expr ([.console cget -width]+10)]
                    }
                }] -side top -fill x -expand 1
                pack [checkbutton .frame.scroll -bg white -fg black  -text scroll  -font $fontsz -variable ::tk::do_scroll] -side top -fill x
                pack [button .frame.frame.mit -bg green  -fg white  -font $fontsz   -text copyit -command copyit] -side top -fill x -expand 1
                pack .consoleframe -in . -anchor center -expand 1 -fill both -ipadx 0 -ipady 0 -padx 0 -pady 0 -side left
                pack .console -in .consoleframe -anchor center -expand 1 -fill both -ipadx 0 -ipady 0 -padx 1 -pady 1 -side left
                pack .sb -in .consoleframe -anchor center -expand 1 -fill both -ipadx 0 -ipady 0 -padx 1 -pady 1 -side right
                
                #puts "console width now [.console config -width]   [wm geom .]" ;# hmmm, seems wm geom different across platforms here
                proc copyit {} {
                    set answer [tk_messageBox -message "Please confirm\nto copy .wishrc"  -icon question -type yesno]
                    if { $answer == "yes" } {
                        file copy -force .wishrc /data/data/tk.tcl.wish/files/
                        puts copied
                    }
                    
                }
                proc exiter {} {
                    set answer [tk_messageBox -message "Please confirm to Exit."  -icon question -type yesno]
                    if { $answer == "yes" } {
                        exit
                    }
                }
                set ::tk::console::maxLines 1000
                .menubar add casc -label Extra -menu [menu .menubar.extra -tearoff 0]
                proc menu+ {head label cmd} {
                    set cmd2 [list consoleinterp eval $cmd]
                    .menubar.$head add command -label $label -command $cmd2 ;# note this is defined outside the console eval... its in the normal namespace
                }
                menu+ extra menu menudo
                
                
                proc ::tk::ConsoleOutput {dest string} {
                    set w .console
                    $w insert output $string $dest
                    ::tk::console::ConstrainBuffer $w $::tk::console::maxLines
                    if {$::tk::do_scroll} {$w see insert}
                }
                set ::tk::do_scroll 1
            }
        }
        
    } err_code] {
        puts $err_code
    }
    if { $tcl_platform(os) != "Windows NT" } {
        if { [file exist wishrc.tcl] } {
            puts "sourcing wishrc.tcl"
            source wishrc.tcl
        } else {
            puts stderr "wishrc.tcl not found"
        }
    }

Here's some more fun with the console and a little test of flashing a button. It should run on any 8.6 setup. I call it wishrc.tcl to test it on my tablet.

button  .b    -text "push me\nafter I stop" -command {wm wi .} -bg black -fg white
pack    .b    -fill both -expand true 

proc uniqkey { } {
    set key   [ expr { pow(2,31) + [ clock clicks ] } ]
    set key   [ string range $key end-8 end-3 ]
    set key   [ clock seconds ]$key
    return $key
}

proc sleep { ms } {
    set uniq [ uniqkey ]
    set ::__sleep__tmp__$uniq 0
    after $ms set ::__sleep__tmp__$uniq 1
    vwait ::__sleep__tmp__$uniq
    unset ::__sleep__tmp__$uniq
}

proc cputs {dest string} {
    if { ! [info exist ::tk::my_color_set] } {
        set ::tk::my_color_set 1
        console eval {
            .console tag configure green             -foreground \#00ff00 -background black
            .console tag configure yellowonblack     -foreground yellow -background black -font {courier 14 bold}
            .console tag configure yellow            -foreground yellow
            .console tag configure whiteonred        -foreground white -background red
            .console tag configure red               -foreground red
        }
    }
    console eval [list ::tk::ConsoleOutput $dest $string]
}

sleep 1000
wm geom . 200x200+100+100
sleep 2000
for {set m 0} {$m < 5} {incr m} {
    .b config -bg red -fg white
    sleep 50
    .b config -bg white  -fg red
    sleep 50
}
parray env
console show
cputs whiteonred "white on red "
cputs yellowonblack " And yellow on black and big\n"

Superlinux - 2014-05-05 12:29:55

I want to highlight a little thing which comes handy, and I know to any programmer this would look silly after you read it.

Now how about hearing the message of [ tk_messageBox ] ? Yes! I know there's [ borg speak $message ] ; but this is how you should utilize it:

  • If you want to hear the $message while the [tk_messageBox] is still on the screen first you start [borg speak $message] then run [tk_messageBox] . Example:
set message "Warning! You are trespassing Java in Android using Tcl/Tk and AndroWish!"
borg speak $message
tk_messageBox -message $message -icon warning
  • If you want to hear the $message after the [tk_messageBox] vanishes from the screen first you start [tk_messageBox] then run [borg speak $message] . Example:
set message "Warning! You are trespassing Java in Android using Tcl/Tk and AndroWish!"
tk_messageBox -message $message -icon warning
borg speak $message

This should show and prove you that [borg speak] works in a separate thread. -- RS 2014-05-08: As I just tested in an interactive wish on Windows 7, tk_messageBox just blocks until dismissed with the OK button.


HE 2014-08-17 I played today with menu and found it difficult to use them with the default font. I could read them but using them was quit difficult. The same with text inside entries and buttons. Comparing with windows I saw also that we can't be sure that we have STANDARD FONTS defined as a default value. And I saw that the font size results nearly to the same size regardless of the screen (at least on the both android devices, one 4" and one 8", and the win7 device). The following code changes the default value when used at the beginning of the code

option add *Menu.Font   TkMenuFont widgetDefault
option add *Button.Font TkTextFont widgetDefault
option add *Entry.Font  TkTextFont widgetDefault
option add *Label.Font  TkTextFont widgetDefault
font configure TkMenuFont -size 12
font configure TkTextFont -size 12

I have to use 'font configure' because I couldn't find out how to change the named standard fonts with the option command.

The other value which is to small for me is the default width of the scrollbars. Looking for a device independent way I come to the following solution as a first draft:

set stdPixProMm 4
option add *Scrollbar.width [expr {16 * [winfo screenwidth .] * 1.0 / ([winfo screenmmwidth .] * $stdPixProMm)}] widgetDefault

The stdPixProMm defines the amount of pixels per mm on a standard screen. I'm not sure if this is the best value for it because I also found out that 'winfo screenmmwidth' and 'screenmmheight' on the win7 doesn't return the correct values. But the result provides on all three devices scrollbars with a width which is usable with fingers.


kc - 2014-09-30 03:17:15

Can anyone tell how to adjust screen brightness in androwish? I tried "borg content update" but it won't work.May be done with wrong parameter.Please help!


JDA - 2015-01-16 17:15

Is there a means in androwish to access openGL libraries?

Androwish rocks! I just discovered Androwish. I was able to download, install, and build the sample helloTclTk example and run it on my Motorola cell phone in addition to porting a small Tcl script. This all in less than a few hours (did not know how to build an android app). Androwish is simply awesome. Thank-you!!


Scroll canvas with finger

chw 2015-02-27: The following solution works OOTB due to the default setting of "sdltk touchtranslate ...". It uses the middle mouse button emulation for panning the entire canvas with fast wipes. Slow wipes deliver still left mouse button events e.g. for moving the currently active canvas item.

set canvas [canvas $base.canvas -xscrollincrement 1 -yscrollincrement 1]
# following lines borrowed from /assets/sdl2tk8.6/demos/items.tcl:
bind $canvas <2> "$canvas scan mark %x %y"
bind $canvas <B2-Motion> "$canvas scan dragto %x %y 1"

HaO 2019-05-07: I also tested it with text and tablelist widget with positive result:

set text [text $base.t ...]
bind $text <2> "$text scan mark %x %y"
bind $text <B2-Motion> "$text scan dragto %x %y"

For tablelist, it was helpful to configure -selectable 0 to all columns to not interfere with selection.

set table [tablelist $base.t ...]
bind [$table bodytag] <2> "$table scan mark %x %y"
bind [$table bodytag] <B2-Motion> "$table scan dragto %x %y"
...
for {set row 0} {$row < [$table index end]} {incr row} {
    $table rowconfigure $row -selectable 0
}

Minimalistic Web-Cam

chw 2015-09-11: Minimalist webcam using AndroWish's borg camera command

# http://<ip-of-device>:8080/.... takes a JPEG picture
proc init {} {
    destroy .label
    borg camera close
    catch {image delete img}
    image create photo img -width 640 -height 480
    borg camera open
    borg camera parameters picture-size 640x480 jpeg-quality 80
    bind . <<ImageCapture>> {borg camera image img}
    borg camera start
    pack [label .label -image img]
    socket -server request 8080
}
proc request {sock args} {
    chan configure $sock -translation binary -blocking 0 -buffering none
    after 100
    catch {chan read $sock 1000} err
    chan configure $sock -blocking 1
    if {![borg camera takejpeg]} {
        chan close $sock
        return
    }
    bind . <<PictureTaken>> [list send_jpeg $sock]
    chan puts -nonewline $sock \
        "HTTP/1.0 200 OK\rConnection: close\r\nContent-Type: image/jpeg\r\n\r\n"
}
proc send_jpeg {sock} {
    bind . <<PictureTaken>> {}
    catch {chan puts -nonewline $sock [borg camera jpeg]}
    catch {chan close $sock}
    borg camera start
}
init

JM 9/5/2017, when using the webcam example from the VFS mounted assets folder, something does not work on my phone to get the IP address and appears OFFLINE, but it is actually ONLINE.
Other than that, knowing the IP address by means of SSHDroid, the sample works great.

JM 9/28/2019, A fix for the above as follows:

proc netstat {} {
    set url OFFLINE
    set col red
    if {[string match "wifi*" [borg networkinfo]]} {
       set wifi [borg systemproperties wifi.interface]
       if {![catch {set ip [borg systemproperties dhcp.${wifi}.ipaddress]}] && ($ip ne "")} {
          set url "http://${ip}:${::port}/"
          set col green
          unset wifi
       }
    } else {
       array set t [borg tetherinfo]
       if {$t(active) ne ""} {
          catch {set wifi [borg systemproperties wifi.tethering.interface]}
          if {![info exists wifi]} {
             set wifi $t(active)
          }
       }
    }
    if {[info exists wifi]} {
       catch {
             set ip [exec ifconfig $wifi]
             set i [lsearch $ip inet]
             if {$i > 0} {
                set ipAddr [lindex $ip $i+1]
                set ip [lindex [split $ipAddr :] 1]
                set url "http://${ip}:${::port}/"
                set col green
             }
        }
    }
    .c itemconfigure txt -text $url -stroke $col
}

How to get a device's dhcp data, ip address, e.t.c

Provided wifi hardware exists, and the device is connected by dhcp:

    borg systemproperties   wifi.interface        ;# find wifi interface, here 'wlan0'
    borg systemproperties   dhcp.wlan0.ipaddress  ;# find device ip address for the given interface, i.e. 'wlan0'
    borg systemproperties   dhcp.wlan0.server     ;# find access point address

dzach 2015-11-18: chw's creative frenzy continuously sprouts new functionality and tips. Here is his reply to a request for turning on|off the camera's LED:

    [Camera's LED c]an be controlled with "borg camera" command but is device dependent.

    On my smartphone (HTC One V) this sequence works:

    borg camera open
    # LED on
    borg camera parameter flash-mode torch
    # LED off
    borg camera parameter flash-mode off

How to get contact info

dzach 2015-12-26: chw mentions the source code of Android as a place to find more uses for content://.... Indeed, using the source code is the fastest way to get some guidance in the class hell of Android. Here is how to gain access to the contacts content, found in .../android-sdk-linux/sources/android-23/android/provider/ContactsContract.java:

    set cursor [borg content query content://com.android.contacts/contacts]
    while {[$cursor move 1]} {
        puts [$cursor getrow]
    }
    $cursor close

or

    content://com.android.contacts/data/phones

to get the contacts phones listed, or use

    content://com.android.contacts/contacts/filter/<put filter data here>
    content://com.android.contacts/data/phones/filter/<put filter data here>

to get filtered contact results.

If, instead, you want to bring up the contact picker to select a contact from there, and return it to your app, then you can use the following:

    borg activity android.intent.action.PICK {} "vnd.android.cursor.dir/contact" {} {} {} callback

or

    borg activity android.intent.action.PICK content://contacts/people {} {} {} {} callback

and then, after having picked a contact, use the result returned by the callback in a borg content query content://... call to get the contact info needed.

Create and open pdf file

2019-05-07 HaO:

The following code snipped gives the framework to create a pdf file using pdf4tcl and then open it. The file is created in the shared document folder.

# Get Android shared Document folder
set documentFolder [borg osenvironment externalstoragepublicdir\
        [dict get [borg queryfields android.os.Environment] DIRECTORY_DOCUMENTS]]
# create folder, if it does not exist
file mkdir $documentFolder
# create pdf file
set pdfFile [file join $documentFolder myfile.pdf]
::pdf4tcl::new pdf -file $pdfFile -unit mm
# here are all pdf creation commands
pdf destroy
# Open pdf file for viewing
borg activity android.intent.action.VIEW "file:$pdfFile" application/pdf

Use menubutton with BWidget Mainframe widget

2019-05-07 HaO: This BWidget hack was introduced for Androwish. See on BWidget page.

Get ANDROID_ID

2022-03-08HaO: Starting from Android 9, the device serial number is returned as "unknown":

% dict get [borg osbuildinfo] serial
unknown

Programs should use the "ANDROID_ID " as a device identification.

To get the "ANDROID_ID, chw abstracted the following procedure from this thread :

proc get_droid_id {} {
    set cursor [borg content query content://settings/secure value name=? android_id]
    $cursor move 1
    set droid_id [$cursor getrow]
    $cursor close
    return $droid_id
} 

size tk_messagebox to horizontal screen

2022-03-08HaO: The following trick (provided by author of Android easy phone app) sizes message boxes to vertical screen size:

option add *Dialog.msg.wrapLength [expr {int(0.6*[winfo screenwidth .])}]

awdark widget and scaling

2022-03-08HaO: AWDark is IMHO the best AndroWish theme:

  • scalable (very different screen resolutions
  • looks nice

Here is my own init which may use a custom font size:

package require awthemes
set dFontSpec [font actual TkDefaultFont]
# Set eventual custom font size here
# dict set dFontSpec -size $Config(FontSize)
set ScaleCur [expr {
        double([font metrics $dFontSpec -ascent])
        / [font metrics TkDefaultFont -ascent]}]
::themeutils::setThemeColors awdark scale.factor $ScaleCur
# >> Setup dot scrollbar for mobile skin
::themeutils::setThemeColors awdark\
        style.progressbar rounded-line\
        style.scale circle-rev\
        style.scrollbar-grip none\
        scrollbar.has.arrows false
package require awdark
ttk::style theme use awdark
::ttk::theme::awdark::setMenuColors -optiondb