Friday, August 07, 2015

The Android, Cordova, Ionic primer

Do you want to develop Android apps? 
Don't do it under Microsoft Windows: Android Studio is difficult-to-impossible to use on Windows, mostly because of debugging drivers. A Mac or Linux machine is your best option. 

Do you want to also develop Apple iOS apps?
You'll need a Mac. No choice there. Apple insists. 

Do you want to use Unix tools? 
A Mac or Linux machine is your best option.

So, to shorten a long story: 


Modern mobile development 
is easiest on a Mac.
_____
_____

A Primer for Three kinds of 
Android Development (on a Mac)

You'll need an Android device, and a Mac. I'll assume you know how to use the terminal app on a Mac.

If you keep to the following lesson order, you shouldn't run into trouble, since cordova and ionic development depend on the presence of Android Studio. We will:

1. deploy a little native Android Studio app to your Android device
2. deploy a little cordova Android app to your Android device
3. deploy a little ionic Android app to your Android device

------
You can skip this blue text, which is an aside, on the subject of explanatory software:

Instead of this sequence/lesson-order, which meets many technological dependencies silently, we could employ a set of productions. Each production could be thought of as either [target: ordered list of dependencies] or [non-terminal: ordered list of terminals and non-terminals]. Using this, you could build your own sequence/lesson-order, by starting with any target:




ionic-run: ionic-install ionic-start ionic-build
cordova-run: cordova-install cordova-start cordova-build
android-java-app-run: android-install android-java-app-start android-java-app-build
ionic-installcordova-install 
cordova-install: xcode-and-clt-install android-install 
android-installjava-install android-studio-install 

... but the possible paths haven't been converted into clearly written sequence/lesson-orders, so it's easiest to follow my given (1,2,3) sequence.


------


In general, my little lessons are like this:

a) do the minimum necessary to install and configure
b) create the smallest prepackaged app
c) make a change to it
d) build, emulate, serve
e) put it on your device

... planned with the idea that iterating (c,d) and (c,d,e) will let you get started on developing the app you want. A fuller lesson plan would include debugging, finding the appropriate framework or functionality at the appropriate time, etc.

------

1) deploy a little native Android Studio app 
to your Android device

-> Install the Oracle Java JDK

http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html
Download the most recent JDK for your machine.
Install.

-> Install Android Studio

https://developer.android.com/sdk/index.html
Download.
Install standard.

-> Use Android Studio

Launch Android Studio.
Start a new project.
Click the blank app.
Let it build.
Edit the value of the Hello World string's resource.
Build and run the blank app on the emulator.

-> Deploy to your Android device

Under Settings, at the bottom, find the Build Version.
Tap it seven times. After a few taps, it will countdown your taps.
A Developer Settings section then appears in settings. 
Open that section, and enable usb debugging.
Plug the device into your mac.
You may need to agree to pair the two at various stages in this process.
Go to Android Studio.
Click the 'Run' (the green right-arrow at the top).
Choose your device.
The little completely native app should now deploy on your phone.
Play with deleting it and deploying again etc.

2) deploy a little cordova Android app 
to your Android device

-> Get some developer tools

Get an apple id. 
Sign in to: 
https://developer.apple.com/downloads/
Download Xcode and the command line tools.
Install.
(If you don't have a developer account, you can download Xcode for free from the App Store, install it, and run any of a number of commands in your terminal -- like 'gcc' -- and your Mac will then help you install the command line tools.)

Get the nodejs download from
https://nodejs.org
and install.

Make sure that node, npm and git are installed:
node -v
npm -v
git --version

[And for below, note that, if you find that the use of sudo is impossible for some reason, for example, running from inside of an IDE like WebStorm, you just need to claim ownership of all the permissions in your home directory's .npm directory: sudo chown -R $(whoami) ~/.npm ]


-> Install Cordova

sudo npm install -g cordova
sudo npm install -g ios-sim (useful later)

-> Use Cordova

make a directory for your cordova apps:
cd
mkdir cordova
cd cordova
create the sample cordova HelloWorld app:
cordova create myhello com.example.hello HelloWorld
cd myhello
cd www
edit index.html with your favorite editor.
emacs index.html
change the string ‘device is ready’ to something else.
Now add platforms to the project:
cordova platform add iOS
cordova platform android
Build your android app (note that run does this automatically):
cordova build android
Run it in the emulator:
cordova emulate android
Run it on your device:
cordova run android

3) deploy a little ionic Android app 
to your Android device

-> Install Ionic

sudo npm install -g ionic

-> Use Ionic

make a directory for your ionic apps:
cd
mkdir ionic
cd ionic
create a sample ionic 'sidemenu' app (other options are 'tabs' and 'blank'):
ionic start myApp sidemenu
cd myApp
install the local builder.
sudo npm install -g gulp
ionic platform add android
ionic build android
Look at it in the browser:
ionic serve
or
ionic serve -f chrome
Select ‘2’.
Browse to the given localhost url to try the app in the browser.
Then go back to the terminal and:
q
You can also see it in the emulator. 
Cd to the root directory of the project folder, then:
ionic emulate android
ionic run android
Now make a modification:
cd www
cd js
And edit app.js
Change some of the strings in the JSON object that populates the app.
Run on your device (it will build automatically). 
Cd to the root of the project folder, and:
ionic run android
You should see the app on your device.


-------
Note:

Apparently Cordova by default blocks http requests. Just run this command:

ionic plugin add cordova-plugin-whitelist

And you're good to go.

Thursday, July 23, 2015

How to fix the window resize problem with Ubuntu Linux in VirtualBox on Windows

This is a popular enough post, that I thought I'd reprint it here:

Oracle supports a free VM hypervisor called VirtualBox. I'm using version 4.3.28 on Windows 7. I want to put Linux on it. Ubuntu is one of the few Linux distros that offers an .iso image download. I download Ubuntu 14.04.02.

Out-of-the-box, the install comes with a problem. The display is too small, 640 x 480, to even see the entire display settings screen. There are no options for making it bigger, or for making it resize automatically.

Systems are so unbundled, dependency building is so unreliable, conflicts are so common, that it's unclear if my solution would work for even a slight variation on the above situation.

But here's my solution. When I found it, I deleted the virtual machine and tried the same installation procedure again, just to be certain.

1. install Ubuntu on the virtual machine
2. at the top of the VirtualBox guest operating system desktop window, click Devices->Insert Guest Additions CD Image …
3. you will be prompted to run the Ubuntu Guest Additions CD. Do it.
4. then shutdown from within the virtual desktop, and reset from the dashboard. Resizing should now work.

The dozen other solutions are probably just out-of-date. But, again, software distribution is in such a irresponsible state that it is not possible to know this for sure, without an extensive research initiative.

Wednesday, May 20, 2015

Android Studio 1.2 problems

Every IDE is terrible. I won't explain my reasoning here. If you're interested, see my computing philosophy.

But the new Android Studio is not the worst of them. As one would expect, there are immediate snags and bugs. I'll document a few, mostly as problem-resolution pairs.

After downloading, installing, and running, you need to manually update the studio: click the little android-with-down-arrow icon (the SDK Manager) and see if anything needs to be installed. Google will probably fix some of the problems below, in future updates. Including this installation updating issue.


Task -- Create a new project only with default values. Your first new app project will have several problems at birth:


problem: a “Rendering Problems” error -- “the following classes could not be instantiated” ...
solution: you need to change the build.gradle classpath to 1.2.3, and rebuild. Then simply close the semi-opaque error window.


problem: “warning: the project encoding (windows-1252) does not match the encoding specified in the gradle build files (utf-8)”
resolution: there’s a link provided within this error window: “open file encoding settings”. Click it. For both the IDE and Project, select “utf-8”.


Task -- build and run:


problem: running an app in the emulator only displays the locked screen
resolution: click the lock and drag upwards


problem: (on Microsoft Windows) emulator window off the top off the screen
solution: click on emulator, then press Alt+Space, then choose Move, then move with arrow keys


Task: add more "activities" (i.e., “screens” or "pages"):


cool thing: try Tools->Android->Navigation editor. Click to add an activity.
but: deleting activities take some attention. You need to check any appropriate XML manifests, delete related code, and refactor.


Task -- add an activity in navigation editor:


problem: one of the least intuitive aspects of the layout editor (which you get to by double-clicking activities in the navigation editor), is that you cannot simply type new text after double-clicking text. The these have to become string resources.
resolution: double-click the box with the text in it. hit the little ellipsis (...) A dialog shows up. Create a new resource (at the bottom), and then say 'ok'. This will take care of it.


Task -- add a radio group:


problem: orientation of radio group container layout.
resolution: 
1. click on the actual radio group on the right, in the component tree
2. look at the properties box, below the component tree
3. change “orientation” property to “horizontal”


problem: layout width & height default is set to “match_parent” in the properties box. making it huge. note this default may be inherited from the layout type. But is still silly.
resolution: change “layout width” & height to “wrap_content”


problem: check a radio button by default
resolution: it's the radio button property ‘checked’. Of course, the programmatic solution would be different.

problem: the palette disappears from layout editor
solution: there’s a tiny little arrow to the top left. click exactly upon it. a “palette” button should show up. then you can double-click on the .xml tab, and if the palette button is still showing, you should be able to mouseover and get a window adjustment arrow on the left, and then you pull it right, and the palette shows up again.


problem: error “resource id cannot be empty string at ‘@+id/’”
solution: change it to @id+/test … in general, id’s map code to activities or fragments in the XML.


Task -- add a web view:

https://developer.chrome.com/multidevice/webview/gettingstarted

Add the webview from the palette, in the layout editor.

Set height and width with down arrow in properties, to “match_parent”

Create an id, like “webview1”:
android:id=”@+id/webView1”

Then edit your mainactivity java file.

You add the url in java, in mainActivity:

public class MainActivity extends Activity {
   private WebView mWebView;
   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);
       mWebView = (WebView) findViewById(R.id.activity_main_webview);
       mWebView.loadUrl("http://beta.html5test.com/");


If you don’t want the browser to launch, before the URL put:

public class MainActivity extends Activity {
   private WebView mWebView;
   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);
       mWebView = (WebView) findViewById(R.id.activity_main_webview);
       mWebView.setWebViewClient(new WebViewClient);
       mWebView.loadUrl("http://beta.html5test.com/");

… and if the page you’re loading has javascript, you’ll need to add this:

public class MainActivity extends Activity {
   private WebView mWebView;
   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);
       mWebView = (WebView) findViewById(R.id.activity_main_webview);
        // Enable Javascript
        WebSettings webSettings = mWebView.getSettings();
        webSettings.setJavaScriptEnabled(true);
       mWebView.loadUrl("http://beta.html5test.com/");


problem: the IDE can’t find classes, like WebView, WebViewClient, etc.
solution: click and hover, and accept the IDE’s “alt-enter” option to add the appropriate import.


problem: webpage doesn’t load. get “Failed to load resource: net::ERR_CACHE_MISS …”
solution: in the primary manifest, AndroidManifest.xml, put this line anywhere above the application:



easy misunderstanding: if you use relativeLayout, the ‘below_layout’ property in the activity XML file may be confusing. It refers to the xml id of the fragment laid out above it.


problem: constant emulator runtime errors. “glUtilsParamSize: unknow param” (sic)
solution: live with it. you can get rid of them by stopping the AVD (android virtual device) manager, editing your virtual device, unchecking “Use Host GPU”, killing and restarting the emulator.
but: it seems to actually break (or intolerably slow-down) the emulator
future possibility: some kind of error message filters in Android Studio. Which, for these errors, should be in place by default. I expect this will change in some update, since they’re really annoying.


problem: run doesn’t start the app the first time. it starts the emulator.
solution: run twice


Task -- Installing git:


problem: (Microsoft Windows) When you enable Android VCS with git, it can’t find git.exe, even if you fully installed git with defaults. And the Windows start menu search can’t find it.
solution: I found it here: c:\program files (x86)\Git\bin\git.exe





Thursday, February 20, 2014

Motor needs push? Replace Start Capacitor

"Blog helps people find solutions. Problems: Google Search based on statistical pattern-matching. Machines don't understand human sentences. Solution: Multiple simple descriptions of problem. Headline writing style freed from articles and helper verbs. Facilitates computer's pattern-matching."

Ack. I can only mangle my natural language for a paragraph at a time. But here's the actual post topic:

"AC Induction Motor runs well. But Motor needs push start. What's wrong? Start Capacitor normally pushes motor. Capacitors degrade often. Capacitors cheap. AC Motor fixed for under $10. Blog post saves Motors from landfill. World saved."

Quite sadly, it takes real research and experiment to discover this basic fact about motors. A running motor, but one that needs a push-start to actually spin, is almost certainly missing its designated pusher -- the "start capacitor". These things are cheap, and easy to replace. There's no reason to throw out a perfectly good motor or, worse, the entire product it's attached to. Split-phase AC Induction Motors (start phase, run phase) are used in everything -- from pumps to furnaces. The fact that they're tossed on the scrapheap, often with the appliance, is nearly criminal.

The major problem is that symptoms are described differently by different people. Sentences are infinitely variable, though highly constrained (actually, any infinite set is highly constrained). So the meaning of "motor runs if I push it" (and the more vague symptoms that precede this discovery) can be expressed in an infinite number of ways. If Google Search was designed with the rather specific internal circuitry of the human brain, it could 'get' what we 'mean' and search the web on our behalf. Unfortunately, that circuitry is unknown to the natural sciences, although a tiny bit of progress is made every year. This is too slow for Google: they've abandoned the idea of understanding how the brain actually works, and instead hang out with people who wrongly think they can divine internal structure from statistical analysis of surface behavior.

Until someone competes with Google on this front (they seem committed to the wrong direction), or until the science of cognition matures, here's the best we can do, to empower people, and to save the planet: encourage everyone to discover the most commonly used words and phrases that could express their problem.

Don't give up! Save the machine!

Sunday, February 02, 2014

Google Sites URL mapping

I manage a number of sites with Google Sites. It's clearly not a tool that Google feels heavily invested in. There are occasional fixes, typically years in coming, but there are still significant problems with the HTML generated by the WYSIWYG interface, and many UI fragilities with the editor and manager. I use it anyway.

I found one site unexpectedly redirecting/forwarding to a sub-directory page, in this case a "/home". I wondered what was causing this problem, which I certainly didn't want.

I eliminated the possibility of a problem at the registrar -- the thought was that maybe I'd accidentally added this subdirectory to a field in a zone forwarding directive, or maybe I'd put a redirect in an html page, or in the header of a server response on another host server … although this seemed unlikely.

But, no, those possibilities were not realities.

So, I was back into the mysteries of Google Sites. What was prompting this strange behavior?

The only difference I could find between this and other Google Sites, was that in the "web mapping" section I wasn't using the lower-case name of the sites subdirectory.

But instead of generating an error, Google Sites mistakenly interprets this as a redirect directly to the default directory, visible to the user as a "something.com/home" directory, which was not desired.

It would be nice if they would fix this. And, in general, the mapping console could provide precise information about the nature of the mapping.

So, I deleted the old entry, added a new "web mapping" with a lower-case name, and all was fine.


Friday, June 29, 2012

Demagnitizing Camcorders

Although the reasoning in this original article is interesting, it turns out to be incorrect. It's possible to clear a bit of magnetic dust using blank tapes and cleaning tapes, but serious problems that damage subsequent tapes are caused by dirty rollers, capstans, and video heads. After following the method below, the problem came back a few tapes later, and it was not fixable through the same method. Cotton swabs for the non-head components, and paper or chamois swabs for the video heads, with isopropyl alcohol, are the only pieces of equipment that resolve this problem. The tiny specs of magnetic dirt that interfere with a video head, and damage tape image frames permanently, are very easy to remove with a manual cleaning.

My SONY DSR-PD150 is over a decade old, but I still use it, because it's good in low light and very reliable.

Unfortunately I recently threw it into the back of a car full of big self-powered speakers, and it became magnetized. Perhaps the cause was direct contact with the speakers' magnets, or perhaps moving through their magnetic fields, or perhaps from some kind of reverse "Faraday Cage" effect (magnets inside a Faraday Cage, which usually protects from electric effects outside the cage, but, who knows, might amplify the effects when magnets are inside the cage).

The previously reliable image and sound recordings became spotted with dropouts, digital noise, etc. Definitely magnetized heads.

So, how to demagnetize a camcorder? Is it possible?

Yes, it is possible.

I'll say what worked, and then reconstruct the discovery process.

The solution is:

1) get new tapes
2) with each tape:
3) record once for the length of the tape
4) play back once for the length of the tape
5) throw away the tape
6) repeat 3-5 with new tapes until the magnetizing goes away


This sounds unlikely, I know. Like many things related to magnetism, our intuition fails us. Mine did.

At first I tried two different miniDV cleaning tapes. They were no help. These tapes might be helpful in other situations, but apparently not with magnetized heads or magnetic particles, which I imagine were magnetically attached to the heads. I also tried just recording and playing back on the same miniDv video tape, over and over again: this also did not help.

I found one intriguing post, here, and decided to use it as the basis of a little theory, and think through the likely repercussions. If it's true that the use of a camcorder tends to neutralize, rather than magnetize, the recording and playback heads, then we would need to optimize the conditions under which the camcorder could eliminate the magnetic particles depositing on its heads. The only thing that could do this is the tape, since, being magnetic tape, it is both the source of the particles and a potential mop of them. So, after having tried so many things to no avail, I simply broke out a new tape, recorded the full 40 minutes (DVCAM mode, but it wouldn't matter what the tape format is) and played it back. Still dropouts. But it seems a little better. I threw away the tape, broke out a new one, and did the same thing. On the playback, it seemed like there were markedly fewer dropouts. I threw it out. One more time, and this time, the playback was flawless.

Apparently I'd used the new tapes as "clean magnetic mops" to pull tape particles, and their attending magnetic charge, off of the camcorder head. It takes a certain leap of faith to throw away brand new camcorder tapes, but that seemed to be the only answer. I know from previous experience that demagnetizers are tricky and can make matters much worse. Throwing away a few new tapes is well worth it, since it can refurbish a camcorder.

This previously highly-magnetized piece of equipment had demagnetized itself, tending towards neutral, given neutral tapes to help it along with the clean-up. I don't guarantee it, of course, but, for me, the effectiveness of this technique spoke for itself.

Saturday, May 02, 2009

Sleepless MacBooks

My MacBook, like many people's, is an insomniac. If you put it to sleep, from the menu or by closing the shell, it wakes up again, in a few seconds. This default behavior will empty your batteries and overheat your machine in its case.

Now, many things can cause this: mostly hardware interrupt handlers containing instructions to wake up. I first Googled this problem with the phrase: macbook does not stay asleep, but the Apple discussion board is completely disorganized. At the top of the page, it announces "1 solution" but doesn't give you a hint as to where it may be, in pages of discussion! I found it eventually, but I thought it would be helpful just to say:

... turn off Bluetooth.

It's in Systems Preferences under Hardware -> Bluetooth. Your computer will then get the rest it needs, without pills.

Addendum:

If the Bluetooth hardware is failing, the Bluetooth symbol has a little squiggle through it.


This makes the system write a hardware error to the system log (/var/log/system.log) every second. This wakes your Macbook consistently.

In this case, without repairing the hardware, you'll need to put your machine into hibernation, instead of sleep. There's a useful widget for this, called Deep Sleep.

Your Bluetooth hardware may start working again. Anytime you see the grayed out Bluetooth symbol in the upper right, without a squiggle, you'll be able to sleep normally ... if you turn Bluetooth off.

Sunday, June 29, 2008

Open Source OCR on a Mac

Tesseract-OCR is an effective open source project from the mid-1990's. The actual character recognition is terrific, so it's not hard to get good results, and it's quite a time-saver.

But, it's not exactly turn-key. You need to:

1. download the source
2. compile it for a Mac
3. download a language file
4. copy it to the appropriate directory
5. run it on TIFF files that need to be renamed to a .tif extension.

Tesseract won't run unless you copy the language file to /usr/local/share/tessdata. Which is strange, because it uses it very irregularly. Most of the miss-read results are simple English words: you get "iist" instead of "list", "lf" instead of "if". It makes you wonder how exactly it is applying this language file.

If you use a Mac utility like Textedit, or Word, or Open Office, the spell-checker can find and help you fix these in a matter of moments. But, still, it's irritating, when you have a long document. This software needs to be 'productized'.

So, the actual sequence:

1. go here, and download tesseract-2.03.tar.gz.

2. In a Terminal window (Applications->Utilities), find your download directory, cd there, and:

: gunzip  tesseract-2.03.tar.gz
: tar xvf tesseract-2.03.tar


3. cd to the tesseract-2.03 directory, then:

:./configure
:sudo make
:sudo make install


4. Go back here, and download tesseract-2.00.eng.tar.gz, then, find your download directory, and:

: gunzip tesseract-2.00.eng.tar.gz 
: tar xvf tesseract-2.00.eng.tar
: cd tessdata
: sudo bash
: cp * /usr/local/share/tessdata/


Then hit control-d to exit the sudo bash shell.

Make a TIFF file, be sure it has a .tif extension, and then issue a command like this:

tesseract document-image.tif document-results


... and then you'll have text in document-results.txt

Works great. It should come standard with a Mac. With a graphic user interface. And some corrections to the language file use.

Sunday, June 15, 2008

Server heartbeat script

Simple bash script on Gnu/Linux or Unix system, to monitor the uptime of your server, and tell you, call you (well, text your cell phone) when something's wrong. I just call this one heartbeat:


#! /bin/sh -v
while true
do
if wget --no-dns-cache --no-proxy --delete-after google.com
then
if wget --no-dns-cache --no-proxy -t 1 -T 60 --delete-after \
your.domain's.IP.address/beat.php
then
echo "success"
else
echo "Heartbeat stopped" | mail -s "MACHINE DOWN" -c \
your@emailaddress.com \
yourphonenumber@txt.att.net; sleep 20m
fi
fi
sleep 10m
done



We need a server-side script ... the beat.php above:


<?php
header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
header("Expires: Mon, 26 Jul 1997 01:00:00 GMT"); // Date in the past
?>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Beat</title>
</head>
<body>

<? print(Date("l F d, Y ... g:i A")); ?>

<br>
</body>
</html>



A few explanations:

* We hit Google first just to make sure the web is working. No sense queueing up an unecessary e-mail to yourself.

* wget's delete-after cleans up the result of the wget, which is built to fetch pages from a URL.

* wget doesn't error when your local resolv cannot find a domain name. This is why we use the IP address. If you need to test to see if your domain's zone name server is running, create a script for that purpose. Don't rely on this one.

* most cell phone have a way to receive e-mail / text messages. Try sending a message from your phone to your e-mail address, and reply to it, to discover, and test, your cell phone's e-mail address.

* Of course, all the "cache expire" stuff, and the fresh-content dynamic server side script, is necessary, otherwise when your server goes down, some helpful cache server along the way will provide you with the beat.php results anyway, from your numerous previous wgets. It's best to test this, despite my precautions ... there are lots of cache mechanisms being inserted on the web these days.