Category Archives: android

Tweaking Emacs on Android via Termux: xclip, xdg-open, syncthing conflicts

Update: Fixed reference to termux.properties

I’m planning to leave my laptop at home during our 3-week trip, so I’ve been shifting more things to my phone in preparation. Orgzly is handy for reviewing my agenda and adding items on the go, but nothing beats Emacs for full flexibility. Runnng Emacs via Termux works pretty well. I can resize by pinch-zooming, scroll by swiping, and even enter in more text by swiping right on the row of virtual keyboard buttons.

Here’s what I’ve configured in ~/.termux/termux.properties:

extra-keys = [['ESC','/','-','HOME','UP','END','PGUP','F5'],['TAB','CTRL','ALT','LEFT','DOWN','RIGHT','PGDN','F6']]

and here’s what that looks like:

Screenshot of Emacs

I patched my Termux to allow the use of function keys in the extra keys shortcut bar. It’s been merged upstream, but the new version hasn’t been released yet, so I’m still running the one I compiled from source. It would be nice to fix accidental keypresses when swiping extra keys to get to the input field, but that can wait a bit.

I set up Syncthing to synchronize files with my server and laptop, Termux:API to make storage accessible, and symlinks in my home directory to replicate the main parts of my setup. I set up Orgzly to auto-sync with a local repository (synchronized with my server and laptop via Syncthing) and the same Org files set up in my agenda in Emacs on Termux. That way, I can hop between Orgzly and Emacs as quickly as I want. Here are a few tweaks that made Emacs even better.

First, a little bit of code for phone-specific config, taking advantage of the weird automatic username I have there.

(defun my/phone-p ()
  (and (equal (system-name) "localhost") 
       (not (equal user-login-name "sacha"))))

For Emacs News, I wanted to be able to easily open Org Mode links to webpages by tapping on them. This code makes that work (and in general, anything that involves opening webpages):

(setq browse-url-browser-function 'browse-url-xdg-open)

This piece of code cleans up my Inbox.org file so that it’s easier to skim in Orgzly. It archives all the done tasks and sorts them.

     (defun my/org-clean-up-inbox ()
       "Archive all DONE tasks and sort the remainder by TODO order."
       (interactive)
       (with-current-buffer (find-file my/org-inbox-file)
         (my/org-archive-done-tasks 'file)
         (goto-char (point-min))
         (if (org-at-heading-p) (save-excursion (insert "\n")))
         (org-sort-entries nil ?p)
         (goto-char (point-min))
         (org-sort-entries nil ?o)
         (save-buffer)))

     (defun my/org-archive-done-tasks (&optional scope)
       "Archive finished or cancelled tasks.
SCOPE can be 'file or 'tree."
       (interactive)
       (org-map-entries
        (lambda ()
          (org-archive-subtree)
          (setq org-map-continue-from (outline-previous-heading)))
        "TODO=\"DONE\"|TODO=\"CANCELLED\"" (or scope (if (org-before-first-heading-p) 'file 'tree))))

I also sometimes wanted to copy and paste between Termux and Emacs by using the keyboard, so I submitted a patch for xclip.el so that it would detect and work with termux-clipboard-get/set. That code is now in xclip 1.9 in ELPA, so if you M-x package-install xclip, you should be able to turn on xclip-mode and have it copy and paste between applications. In my config, that looks like:

(when (my/phone-p)
  (use-package xclip :config (xclip-mode 1)))

Because I use Orgzly and Termux to edit my Org files and I also edit the files on my laptop, I occasionally get synchronization errors. I came across this handy bit of code to find Syncthing conflicts and resolve them. I just had to change some of the code (in bold below) in order to make it work, and I needed to pkg install diffutils to solve the diff errors. Here’s the fixed code below, along with a convenience function that checks my Orgzly directory:

(defun my/resolve-orgzly-syncthing ()
  (interactive)
  (ibizaman/syncthing-resolve-conflicts "~/cloud/orgzly"))

(defun ibizaman/syncthing-resolve-conflicts (directory)
  "Resolve all conflicts under given DIRECTORY."
  (interactive "D")
  (let* ((all (ibizaman/syncthing--get-sync-conflicts directory))
        (chosen (ibizaman/syncthing--pick-a-conflict all)))
    (ibizaman/syncthing-resolve-conflict chosen)))

(defun ibizaman/syncthing-show-conflicts-dired (directory)
  "Open dired buffer at DIRECTORY showing all syncthing conflicts."
  (interactive "D")
  (find-name-dired directory "*.sync-conflict-*"))

(defun ibizaman/syncthing-resolve-conflict-dired (&optional arg)
  "Resolve conflict of first marked file in dired or close to point with ARG."
  (interactive "P")
  (let ((chosen (car (dired-get-marked-files nil arg))))
    (ibizaman/syncthing-resolve-conflict chosen)))

(defun ibizaman/syncthing-resolve-conflict (conflict)
  "Resolve CONFLICT file using ediff."
  (let* ((normal (ibizaman/syncthing--get-normal-filename conflict)))
    (ibizaman/ediff-files
     (list conflict normal)
     `(lambda ()
       (when (y-or-n-p "Delete conflict file? ")
         (kill-buffer (get-file-buffer ,conflict))
         (delete-file ,conflict))))))

(defun ibizaman/syncthing--get-sync-conflicts (directory)
  "Return a list of all sync conflict files in a DIRECTORY."
  (directory-files-recursively directory "\\.sync-conflict-"))

(defvar ibizaman/syncthing--conflict-history nil 
  "Completion conflict history")

(defun ibizaman/syncthing--pick-a-conflict (conflicts)
  "Let user choose the next conflict from CONFLICTS to investigate."
  (completing-read "Choose the conflict to investigate: " conflicts
                   nil t nil ibizaman/syncthing--conflict-history))


(defun ibizaman/syncthing--get-normal-filename (conflict)
  "Get non-conflict filename matching the given CONFLICT."
  (replace-regexp-in-string "\\.sync-conflict-.*\\(\\..*\\)$" "\\1" conflict))


(defun ibizaman/ediff-files (&optional files quit-hook)
  (interactive)
  (lexical-let ((files (or files (dired-get-marked-files)))
                (quit-hook quit-hook)
                (wnd (current-window-configuration)))
    (if (<= (length files) 2)
        (let ((file1 (car files))
              (file2 (if (cdr files)
                         (cadr files)
                       (read-file-name
                        "file: "
                        (dired-dwim-target-directory)))))
          (if (file-newer-than-file-p file1 file2)
              (ediff-files file2 file1)
            (ediff-files file1 file2))
          (add-hook 'ediff-after-quit-hook-internal
                    (lambda ()
                      (setq ediff-after-quit-hook-internal nil)
                      (when quit-hook (funcall quit-hook))
                      (set-window-configuration wnd))))
      (error "no more than 2 files should be marked"))))

If you use Emacs on Android via Termux, I hope some of these tweaks help you too!

Reviving my Asus Transformer TF700T with the KatKiss ROM

Buying the TF700T had been a mistake. It was ahead of its time and not powerful enough for the tablet it wanted to be. I hadn’t given myself enough time to try it out during the return period, so I was stuck with it. I tried reflashing it with other ROMs like CROMBi-kk, but the lack of responsiveness still drove me crazy. I put the tablet in our old electronics bin and moved on. It survived a number of e-recycling purges through the years partly because it looked in such good condition that it would be a shame to throw away, and partly because it was too frustrating a machine to inflict on anyone else.

Now we find ourselves with a toddler who wants to type. W- fixed up his old X220 tablet PC to boot to console mode with 640×480 resolution so that the text is easy to see, but it’s heavy and has poor battery life. A- declared the Sony Vaio U1 to be too small for her, so we dusted off the TF700T and W- found the charger. It was still frustratingly slow. We want computing to be pleasant. I didn’t want to give up hope, though, especially since I’d found surprisingly recent Reddit threads about people using the TF700T.

Formatting the tablet took longer than I thought it would, but fortunately the forum posts reassured me that I didn’t mess it up. After that, I reflashed it to KatKiss Nougatella following the instructions for reflashing the TF700, it actually became somewhat usable. I installed a text editor and an SSH client, docked it into the keyboard, and let A- play.

A-‘s okay with using the TF700, although she misses using F1 to bring up the help screen in Vim. (W-‘s influence! Maybe I can sneak in some Emacs if I remap Emacs’ F1 to bring up something like view-hello-file…) We’re still leaning towards the X220 since it’s more configurable, but the TF700 can be good for guided exploration too.

We don’t care about making sure A- learns how to type so early, and she’s got plenty of time to do other non-computer things. But sometimes she sees W- working on his laptop and she wants to do it too, so she might as well do something useful. I kinda like how her interface is pretty basic. No whizbang animations enticing her to play, just the feedback of seeing text appear on the screen as she presses buttons. She can toggle Caps Lock to make uppercase and lowercase letters, and she knows how to make “?” by pressing Shift with another key. She can spell her name if we tell her which letters to look for. If she happens to type 1 and 0 in the process of banging on the keyboard, she reads it out as “ten.” We’ll let her explore when that’s what she’s curious about, and we’ll also draw her away from it with lots of other activities and by keeping it out of sight as needed.

We have another under-utilized Android tablet. The TF700T’s special because it has a docking keyboard and therefore passes A-‘s “Is this a laptop?” test, while the tablet + Bluetooth keyboard combination does not. I wonder what we’ll end up doing with it. Who knows, if the battery life isn’t dismal, I might even end up using it for writing once A- is old enough for drop-off classes.

Hooray for people working on making old tech more usable!

Decision review: Samsung Note 8

It was quite a big jump going from a Moto G (2nd gen, bought in 2015) to a Samsung Note 8 this year, mostly on my dad’s insistence. Here’s how I’ve been working on making the most of my new phone’s capabilities.

  • Camera: Way more pictures of A-, since the camera works decently even in low light. I like how it reminds me to clean the camera lens.
  • Better battery life, quick charge: This is great. I used to keep W-‘s old Moto G handy so that I could swap to it if my phone battery ran low while I wrote in bed. Now I don’t even worry about charging overnight, since I can charge my phone while having breakfast with A-.
  • More storage: It’s nice not having to decide which apps I have space for on my phone. I even used the SD card to copy thousands of archived photos into Google Photos.
  • Pen: Screen-off notes are really quick to scribble down, since all I need to do is take out the pen and start writing. I trust writing more than typing for taking fast notes. I also really like the ability to select part of the screen and extract text, because sometimes apps don’t make it easy to select and copy text. I’ve used the pen to draw and colour illustrations for a book for A-. It’s more awkward than using my tablet PC or the iPad, but it lets me use phone time to get more things done, so it’s worth it.
  • Fingerprint scanner: Surprisingly handy way of reducing the friction of using my phone. I keep my phone locked when the screen is off so that A- doesn’t play with it, and tapping the fingerprint sensor to unlock the phone saves me a bit of fumbling around.
  • Voice and gesture control for pictures: Great for taking pictures, since it’s not easy to hold and shoot with one hand.
  • Speech recognition in general: I’ve been getting the hang of this now that battery life means I’m a little less worried about leaving my phone listening all the time. I have a few shortcuts for tracking activities, and I often set timers and add grocery items by voice too. It’s still not quite reliable, but it’s worth a shot. A- occasionally parrots “Okay Google” and “Command sent,” so I try to model saying “please” when I ask my phone to do things. I haven’t used Bixby as much, since voice wake-up for Bixby interferes with voice control of pictures.
  • Larger screen: This was a little hard to get used to, since the bigger screen makes it hard to put my phone in my pocket or hold in bed. But it does make it a little more manageable to ssh into my server and do things, although working with a virtual keyboard is still annoying. I’ve also used the split screen feature a few times.
  • Edge apps: I’ve used the clipboard and the ruler a few times.
  • Live focus: I’ve used this a few times, but I usually don’t have much time to compose a picture of A-. Maybe when she’s a bit older, or if I think about it more.

I want to explore more of the camera’s features, figure out a good workflow for photos, learn more about what I can do with speech recognition, and get better at workflows for notes (thoughts, images, and e-books).

I wonder if it makes sense to draw more on my phone than on paper even when A- is around. I haven’t been keen on doing so because she usually wants to imitate me, and she gets more out of drawing on paper than on my phone. Maybe I’ll draw on paper and take quick pictures on my phone instead.

I probably won’t upgrade for a while, since it’s likely to be a bit of a hassle selling this phone and upgrading to a new one. I might be tempted by an even better camera in the next phone. After all A- is only this age once. I really like the stylus. That means keeping an eye on the Samsung Note line and figuring out when it makes sense to upgrade. I hope this phone is sturdier than the Samsung Galaxy S3 I experimented with years ago. This one has survived life with a toddler so far, so that’s good. I spend more time on my phone than on my laptop these days, so it’ll be interesting to see how I can make the most of it.

Daily, weekly, and monthly journals: my Memento + Google Sheets + Tasks Free + Google Tasks + WordPress workflow

Journaling considerations:

  • A- nurses a lot in bed. I keep my phone handy and I write when she doesn’t want to let me go.
  • I also jot quick notes throughout the day so that I don’t have to keep them in my head. These go into the nearest synchronized device.
  • It’s hard to remember the context for those notes if too much time passes. A daily verbal recap for W- and a weekly summary for my blog seem to be just the right balance. Anything older than a week gets too fuzzy, while writing detailed notes every day takes too much time away from other things I’d like to do.
  • Monthly reviews give me a better perspective on big changes. It’s hard to keep enough in my head when I’m reading or writing on my phone, so I need help summarizing a month’s worth of highlights.

Here are the technical details:

I set up Memento Database on my phone and on a backup Android phone. I picked it because it can synchronize between phones in the background, and it can also sync with Google Sheets so that I can process things further.

My journal database has the following fields:

  • Date: defaults to current date
  • Note
  • Category: single value from a list. Most of my entries go into Gross Motor, Fine Motor, Language, Self-care, Other, or Us, and I add other categories as needed.
  • Highlight: a number indicating the level of review this should be included in: 1 – weekly, 2 – monthly, 3 – yearly. I display this field as the status, so that it shows up on the right side.

I have a shortcut on my home screen so that I can quickly add a journal entry.

I normally sort the list by date, with recent entries on top.

As part of my weekly review, I look at recent entries, fill in any categories I skipped, and choose a few to highlight. For example, last week, I wrote 17 entries and I chose 13 to include in the weekly review.

I configured Memento’s default export formatting to include only the Note field and to export that without the field label.

I filtered the database to show only the entries within a given date range where the highlight value was greater than 0.5.

I grouped it by category so that similar entries were together. This was better than fiddling with the sorting, since this takes fewer taps to set back to my default view.

After filtering and grouping the entries, I used the “Send all > Send as text” command to send it to Tasks Free, which is a task manager that synchronizes with Google Tasks. I like the way I can drag-and-drop tasks to reorder them, which makes prioritizing so much easier on my phone. I edit the text in Tasks Free, turning the keywords into paragraphs and moving things around for better flow.

After drafting the body of the post (and possibly switching between phones, if my battery ran low), I select all the text, copy it into the WordPress app, set the categories and the title, and post the entry.

The monthly review process is quite similar. I start with a filtered view that shows all entries for last month (133 entries in November), and I group it by category. I skim all the entries, not just the ones included in the weekly review, because sometimes little moments turn out to be significant or part of a bigger pattern. After setting the highlight values for the things I’d like to include in my monthly review, I switch to another filter that shows me last month’s entries with a highlight value greater than 1.5 (28 entries in November). I send it all to Tasks Free, edit the post, copy it into WordPress, and publish.

If I manage to squeeze in some computer time, I use Google Tasks to copy the text into Emacs and then use my regular Org Mode review/publish processes.

I’ve been thinking about how I can improve this workflow. Sending text to the WordPress app doesn’t seem to work (the text disappears after I save or publish), and it’s kinda nice being able to move my weekly review task around on my task list in order to accommodate other priorities. I also like the way Google Tasks keeps the data from completed tasks, which has come in handy a few times. Tasks Free editing is more responsive, too. Synchronizing with Tasks Free seems to be more robust than synchronizing with Orgzly, since I only have to watch out for editing the same task on two devices instead of watching out for the whole file.

I’d like to get back to drawing the weekly and monthly reviews, but maybe that can wait until A-‘s sleep is more settled and my discretionary time is more consolidated. The visual journals are more fun to flip through, but the bulk and chronological views I hacked into my WordPress theme are reasonable workarounds.

Recreating and enhancing my tracking interface by using Tasker and Javascript

I got tired of setting up Tasker scripts by tapping them into my phone, so I looked into how to create Tasker interfaces using Javascript. First, I created a folder in Dropbox, and I used Dropsync to synchronize it with my phone. Then I created a simple test.html in that folder. I created a Tasker scene with a WebView that loaded the file. Then I started digging into how I can perform tasks, load applications, and send intents to Evernote so that I can create notes with pre-filled text. I really liked being able to reorder items and create additional screens using Emacs instead of Tasker’s interface.

Here’s my code at the moment. It relies on other Tasker tasks I’ve already created, so it’s not a standalone example you can use right off the bat. Still, it might be useful for ideas.

tasker-scripts/test.html:

<html>
    <head>
        <title>Sacha's personal tracking interface</title>
        <style type="text/css">
         button { padding: 20px; font-size: large; width: 45%; display: inline-block  }
        </style>
        <script type="text/javascript" src="http://code.jquery.com/jquery-1.11.3.min.js"></script>
    </head>
    <body>
        <div id="feedback"></div>
        <!-- For making it easy to track things -->
        <div class="screen" id="main-screen">
        <button class="note">Do</button>
        <button class="note">Think</button>
        <button class="note">Note</button>
        <button class="note">Journal</button>
        <button class="switch-screen" data-screen="track-screen">Track</button>
        <button class="switch-screen" data-screen="play-screen">Play</button>
        <button class="switch-screen" data-screen="eat-screen">Eat</button>
        <button class="switch-screen" data-screen="energy-screen">Energy</button>
        <button id="reload">Reload</button>
        </div>
        <div class="screen" id="play-screen">
            <button class="play">Persona 3</button>
            <button class="play">Ni No Kuni</button>
            <button class="play">Hobbit</button>
            <button class="switch-screen"
                    data-screen="main-screen">Back</button>
        </div>
        <div class="screen" id="energy-screen">
            <button class="energy">5</button><br />
            <button class="energy">4</button><br />
            <button class="energy">3</button><br />
            <button class="energy">2</button><br />
            <button class="energy">1</button><br />
            <button class="switch-screen"
                    data-screen="main-screen">Back</button>
        </div>
        <div class="screen" id="eat-screen">
            <button class="eat">Breakfast</button>
            <button class="eat">Lunch</button>
            <button class="eat">Dinner</button>
            <button class="switch-screen"
                    data-screen="main-screen">Back</button>
        </div>
        <div class="screen" id="track-screen">
            <button class="update-qa">Routines</button>
            <button class="update-qa">Subway</button>
            <button class="update-qa">Coding</button>
            <button class="update-qa">E1 Gen</button>
            <button class="update-qa">Drawing</button>
            <button class="update-qa">Cook</button>
            <button class="update-qa">Kitchen</button>
            <button class="update-qa">Tidy</button>
            <button class="update-qa">Relax</button>
            <button class="update-qa">Family</button>
            <button class="update-qa">Walk Other</button>
            <button class="update-qa">Nonfiction</button>
            <button class="update-qa">Laundry</button>
            <button class="update-qa">Sleep</button>
            <button id="goToWeb">Web</button>
            <button class="switch-screen" data-screen="main-screen">Back</button>
        </div>
        <script>
         function updateQuantifiedAwesome(category) {
             performTask('Update QA', null, category);
             hideScene('Test');
         }

         function showFeedback(s) {
             $('#feedback').html(s);
         }
         function switchScreen(s) {
             $('.screen').hide();
             $('#' + s).show();
         }

         $('.switch-screen').click(function() {
             switchScreen($(this).attr('data-screen'));
         });
         function createEvernote(title, body) {
             sendIntent('com.evernote.action.CREATE_NEW_NOTE', 'activity',
                        '', '', 'none', '', '',
                        ['android.intent.extra.TITLE:' + (title || ''),
                         'android.intent.extra.TEXT:' + (body || '')]);
         }
         $('.note').click(function() {
             createEvernote($(this).text());
         });
         $('.energy').click(function() {
             createEvernote('Energy', 'Energy ' + $(this).text() + ' ');
             switchScreen('main-screen');
         });
         $('#reload').click(function() {
             performTask('Reload Test');
         });
         $('.update-qa').click(function() {
             updateQuantifiedAwesome($(this).attr('data-cat') || $(this).text());
             hideScene('Test View');
         });
         $('#goToWeb').click(function() {
             browseURL('http://quantifiedawesome.com');
         });
         $('.eat').click(function() {
             updateQuantifiedAwesome($(this).text());
             loadApp('MyFitnessPal');
         });
         $('.play').click(function() {
             performTask('Play', null, $(this).text());
         });

         switchScreen('main-screen');

         </script>
    </body>
</html>

You can find the latest version at https://github.com/sachac/tasker-scripts.

Thinking about simplifying capture on my phone

I’ve been thinking about temporary information: things like where I put down something I was holding, the task I’m working on just in case I get interrupted, thoughts that I want to explore later on.

The seeds of a good system are there, if I learn how to use them more effectively. I usually have my phone handy. Evernote can record audio, pictures, or text, and the creation date is an automatic timestamp. I can export the notes and process them using Emacs. Google Now’s “Note to self” command can create a note in Evernote, or I can tap the Create Note icon.

How can I improve how I use these tools?

If I get used to starting my note lines with a special keyword, then it’ll be easier for me to extract those lines and process them. For example:

DO Actions to add to my to-do list
THINK Thoughts to explore
PLACE Putting things down

If I add custom commands to Google Now, or make Google Now the fallback for another command line, then I can use that for my tracking system as well. AutoShare and AutoVoice might be handy. I should probably learn how to get Tasker working with Javascript, too. Alternatively, I can use Evernote’s e-mail interface, although there might be a slight delay if I’m offline.

If I create a custom single-click interface that can start the note with a specified keyword, that would be even better.

I could also use a more systematic review process. For example:

  • All THINK items can be automatically added to the end of my

questions.org as their own headings.

  • All DO items can be added to my uncategorized tasks.

Okay, let’s start by figuring out Javascript and Tasker, since that will make it easier for me to write actions that take advantage of intents.

First step is to save the JS library template from Tasker. The file is stored in /storage/emulated/0/Tasker/meta/tasker.js. Okay, I’ve created a Tasker scene that has a WebView component that loads the file that I synchronized with Dropsync.

The next step is to simplify development so that I can try things quickly. I want to be able to sync and reload my WebView scene by tapping a button. The Dropsync Tasker action returns immediately, so maybe I’ll just add a wait to it.

Hmm, maybe a good path might be:

  1. Set up easy sync/reload, so I can try things out quickly.
  2. Include JQuery.
  3. Run tasks.
  4. Launch apps.
  5. Send intents.
  6. Convert my current tracking menu to this format.
  7. Add buttons for creating notes (either e-mail-based or intent-based):
    • Do
    • Think
    • Place
  8. Add a command-line. Compare using it vs. using buttons.

On a related note, what kinds of things would I like my phone to be smart enough to do?

  • If I’m at home and I’m calling my cellphone from our home phone, set the ring volume to maximum, since that means I’m trying to find it.
  • If I say that I’m at a social event, ask me who I’m spending time with. Track that. Create a note with the person’s name as the title and “social” as the tag.
  • If I’m going to sleep, track that, then start tracking in Sleep as Android.
  • If I’m going to play a game, track that, then ask me what I’m going to do afterwards and how long I want to play. Load hints for the game (if I want). After the specified time, make a sound and remind me of what I was going to do.
  • If I’m going to read a book, show me the list of my checked-out books and let me pick one of them. Track that, then create a note with the title and author so that I can take notes.
  • NFC opportunities:
    • If I scan at the door, show me a menu: walk, subway, groceries, family, bike.
    • If I scan in at the kitchen table, track it as breakfast / lunch / dinner (as appropriate), then launch MyFitnessPal.
    • If I scan in at the table in front of the TV, show me a menu: relax, nonfiction, fiction, games.
    • If I scan in at my bedside table, treat it as going to sleep.

Mmm… Little things to tweak. =)