Thursday, December 12, 2013

getting close to done

I finally managed to build a resizable EditText box. So you click on the Add Text button, and a little grey box pops up onscreen on top of your drawing. It's semi-transparent so you can see what's going on below. The keyboard pops up and you type your stuff. A double-headed arrow icon on the right: left/right will increase the width of the box, up/down will change the size of the font. Touch the checkmark icon at the top and the text will be placed. Press & hold on the text itself will let you drag it around to where you want it.

This is getting nice. It's reasonably smooth and intuitive.

There are several things I need to fix to get it fully working right. At the moment it doesn't place the text where I want, and the size is being measured in actual pixels, so if you're zoomed out on the page, it's freaking teeny tiny. These are scaling issues. The other bit is gracefully deleting the EditText when finished -- I need a hook or a listener or something that the EditText can use to tell the app it's done.

Sunday, December 1, 2013

More Play Store piracy


I wrote about this back in April. I do not browse the Play Store all that often -- once a month, maybe a bit more -- and I found another one a couple days ago. The game is the property of Mateusz Skutnik, an artist and Flash programmer lauded by escape gamers for his atmospheric, brain-twisting Submachine series.

I notified Mateusz and he confirmed that the developer did not have permission to port his work to Android. He'll be taking action on it.

Because the games they steal are by different developers, pirates' offerings are going to be very diverse in visual style. A developer making his or her own apps will have a certain style, probably more clearly seen in games than other apps. Widgets such as control buttons and menu styles will be re-used, and the flow from one activity to the next will likely have the same feel.

The ad load of a pirated game will be high. That's one thing that you can count on, because the game is free and this is the sole means of revenue.

It would be interesting if Google, with its advanced abilities to search images for faces and general concepts, applied this to the Play Store.

Sunday, November 17, 2013

working on a new app

A few days before Halloween Brian settled on his "costume": a bow tie.

Not just any ol' bowtie, but

><  > the Bowtie of the Future <  ><

It would be changeable at a touch. It would set the background to the shirt behind it. It would take photos. It would have a +1 button.

In about 6 hours we cobbled together a bowtie image that would cycle through the Google colors and wiggle when clicked, had a fake +1 button and a counter on the left, a subtle (Google design always runs subtle) "BETA" on the right. "Adjusting" the tie, i.e. rotating the phone back and forth, would take a photo.

There were a bunch of little quirky things to code for. Because of the front camera's placement, the entire app had to be displayed upside-down from the normal landscape mode, otherwise the camera would have been obscured by his collar. Photos taken by the camera resulted as upside-down, but flipping is easy. Since he's tallish, the camera tended to take photos of the top edge of the opposite wall, and I experimented with carving wedges from packing foam until we decided it was more trouble than it was worth. Brian was dissatisfied with the shake code I'd found and fine-tuned it to use the gyroscope and a specific sequence  of motions to listen for.

And of course we didn't actually use the back camera to divine the clothing behind it. Brian picked a shirt, I slapped it on the scanner, and turned it into the background image.

But that isn't the 'new app' of the post title.  I've started a paint program. Nothing that isn't the same as quite a few paint apps out there, and in fact it may be simpler than most. But it's partly for the experience and partly because I have an idea that will make it special.

The basics, of course, include:
- a palette of 10 colors, which can be customized
- fill color
- outline thickness
- brush
- point-to-point lines
- rectangles and ovals
- text (nothing fancy, just plain ol' text using the native Android font in the outline color)
- zooming, panning
- undo
- eraser (you won't believe how hard that is to figure out, partially due to sketchy Android documentation).

All colors include transparency levels.

You can take a photo or select one from your gallery to slide in as the background layer.

You can save the drawing+background to the gallery as a jpg, and share it to email, Drive, etc.

All customizable items (colors, line thickness) are saved in SharedPreferences, so you can always have that perfect 20% transparent purple you love.

I've just finished coding all the above. Neither Brian nor I are fully satisfied with the sequence of events used to add text.  It's not easy to make a not-too-disruptive popup with a space for your text and a slider for your font size when there's a keyboard that will slide in and take up half your screen space.

More to come...

Tuesday, August 13, 2013

Ninja Escape by Niwaka Soft - walkthrough all stages

Android app

Stage 1 - Use the shuriken to hit the targets
Stage 2 - Pull the rope 6 times
Stage 3 - Shake your device
Stage 4 - use the sword to kill the tiger
Stage 5 - shake (like a bird!)
Stage 6 - hit the 5 with shuriken
Stage 7 - use the flame to fire up the candle. The candle goes in inventory. Use it to see the Chinese numbers.  This is an equation!
Stage 8 - use shuriken on jar for key.
Stage 9 - swipe left and right to move panels away, then swipe up when you see the arrows.
Stage 10 - enter the numbers on the bottom side of the dice. Opposing sides of dice always add up to 7.
Stage 11 - shake to get the key. unlock chest for a brush. paint the eye on the daruma doll.
Stage 12 - use the shuriken to bring the ropes on the sides down. Pull ropes in order 1 2 3 4 5 4 3 2 1. (Thanks, Angela!)
Stage 13 - click each clock dial so it resembles the corresponding "screw" on the fan.
Stage 14 - flip your device upside down and tap the X (I think) 9 times.
Stage 15 - take the brush and brush away all the black marks. I had a hard time distinguishing when all the black was gone, it took me several tries to get it.
Stage 16 - Touch the screen to bring the spiders down, then use the shuriken to kill them in the order indicated.
Stage 17 - move the candles around so there is the indicated quantity in the box.
Stage 18 - turn your device upside down to show 3 0. Shake it to get an arrow. Tap the circle 3 times.
Stage 19 - take the bucket and use it on the branch.
Stage 20 - 704. I brute forced it, so I don't have an explanation for that number. (Edit: apparently the symbol on the banner is supposed to be *, as in multiply, so 88 * 8.
Stage 21 - slide the panels to the center in the order shown.
Stage 22 - take the hook from the left and, using your sword, the rope on the right. It will automatically combine into a grappling hook to use on the ring.
Stage 23 - take the bucket and put the fire out. EZPZ
Stage 24 - Is a little like Simon. Press the 2nd button and a snake (or garden hose?) will pop out from the hole above it. Press the 2nd button again and 2 snakes will come out. Pay attention to which hole and the order, and press the corresponding buttons to get 3 snakes. Once you've gotten all 4 snakes the ladder will come down to exit.
Super spoiler:
2 | 2 | 1, 4 | 3, 1, 2 | 4, 2, 1, 3
Stage 25 - Select the fire tool and shoot the first tube. This will show you which colors to select out of each group of 3 buttons.
Stage 26 - place a red eye on each of the dragons. Swipe them away, then swipe the wall again to get the stairs.
Stage 27 - arrange the sliders to match the heights of the yellow ovals.
Stage 28 - shake your phone to see the symbols on the top of the wall. Click the panels to match.
Stage 29 - use your fire to start the torches, then pull on the rope. Enter the number shown.
Stage 30 - First, the banner shows 2 arrows. Swipe simultaneously using 2 fingers from the center to the edges, i.e. your left finger starts left of the center and swipes to the left edge, and your right finger starts right of center and goes to the right edge. If you've done this correctly, the banner should change to a left arrow. After this, using the same positioning for the swipe -- from the middle outward -- swipe as follows: L L R L L R R L R R. If you mess up it will go back to the 2 arrows and you have to start over again.
Stage 31 - Select your sword and tap on the screen. Arrows will start flying out and your job is to slice them. If you manage to slice them all (they will disappear instead of flying offscreen) you get to the number safe. Code is 332 (again brute forced; no obvious clue except the arrows, which I was unable to count while slicing them).
Stage 32: shake your phone
Stage 33: place the bars on the rack in rainbow order, starting with red at the top.
Stage 34: tilt your phone so that the west arrow points north, then enter the directions.
Stage 35: shake your phone, take the purple ball and place it on the hole. Press the button.
Stage 36: shake your phone to make the warrior go away; shake it again to return with a key. Take the key & shake again to put the key in the lock
Stage 37: the sage advises peace :) set your phone down and wait.
Stage 38: click the circles from small to large.
Stage 39: Shake your device to expose the letters EVE on the banner on the right. The code is a date, the eve of a holiday celebrated nearly worldwide. It seems this has to be the first number you enter, so if you tried others already, restart the level.
Stage 40: touch the small square to the left of the screen to show the code.
Stage 41: swipe the screen in the direction indicated by the deer.
Stage 42: take the gun. Tilt your phone to the left and shoot the ninja.
Stage 43: hold your finger on the thermometer until it gets to the top.
Stage 44: use your sword and slice the painting, then tap the button.
Stage 45: drag the ball to the hole, then flick the arrow in the direction indicated to get a key.
Stage 46: keep "pulling" (flicking) down the corner that hangs down until the screen is torn down.
Stage 47: Turn your device upside down and click the button on the floor. Then turn it right side up and click the button  on the wall.
Stage 48: Shake your device to get the blue ball to drop from the banner. Drag it to the first oval "counter" on the floor. Click the 1st counter once (so there is one star/dot showing), click the 2nd counter once, and the 3rd counter 3 times (3 star/dots).
Stage 49: Turn your device upside down 3 times to light the first 3 candles, then shake for the last.
Stage 50: Tap the figure on the right. There are 3 hotspots that will light the candles, mostly on the left side of the figure.




I got frustrated with this because the game does not save my progress (Nexus 7, currently Android 4.4.2, but it wasn't saving in the earlier version either). Hopefully someone else will be able to finish since it's a pretty nice game.

Tuesday, July 30, 2013

Tesshi-e game: Escape from Mr M's Room.

This is gonna suck, cos it's a paid game, which means none of the usual ETR players are around to help.

Then again, it sucks that the people who would pay for Tesshi-e's very high quality games are very few.  She's put out 88 free games, everyone loves them and she gets 4 and 5 stars very consistently, but when it comes to paying a pittance (231 yen = appx $2.35, 1.75 euro, you can't get one cup at Starbucks for that), no one's stepping up to the plate. I've even seen people say "I never pay for a game on principle" -- what principles, pray tell, are those?

Anyway. This is not a walkthrough but just notes I took while playing, which make decent hints.

There are a ton of clues. I've found a TV remote, a slingshot with no ammo, a piece of paper, and a bottle opener.

The TV got me a slingshot.  The TV displays a green man puppet on 2 different channels, and the positions he stands in correspond to the 4 buttons where the actual puppet is sitting. Just concatenate those two sequences and you have the answer.

The 3 Mr Birdys on a 3-letter safe correspond to the pillows of the same colors. Each Birdy has a number. That corresponds to a letter in the word on each pillow.  That got me the corkscrew. I sure could use a bottle of wine right now, but I haven't found one yet.

Ah. totally missed seeing a bottle to the left of the TV. A knife now, and with it a spade key, and with that the SD.

Took me a while to assemble the equation for the 4 digit box. You have to cut the paper and place it over each of the pictures on the wall, then reorder the shapes. You get the equation 16 x 5859 / 12, which is 7812.

Used the camera to flash into the dark space. There's a picture showing which corners to click on the rotating picture, and a key. Key gives a handle (box under the sofa).

Handle used on the machine on the floor. Got a ball. Ball goes in the slingshot for a windup key.

Windup key used on the akebekos, 231133, used in turn on the other akebeko. Have a key.

Opened the panel above the bed. Using the card-suit panels I get equations for their value. Also used the cork to slingshot the last panel high up above the sofa. Now I've got more math to do.

Got the equations; they need to be arranged in the same vertical order as the pictures.

Happy coin: check the key.

Tuesday, July 16, 2013

Fiddling and tweaking

Since releasing MapTag I've made a number of minor adjustments to the UI in response to comments.

However, it doesn't work in IE8 and that will not change.

The more fun part has been adding a visual index of saved games and previously played games which players completed in less than 10 minutes and less than 125km from the target. Click the "more games" tab to view that. It would be nice to dynamically adjust the criteria, but App Engine doesn't allow an inequality query on more than one field. It's a bit of a struggle to understand why it cannot do something that's elementary to any SQL query, until one considers its intended scalability.

So instead, I had to add a boolean field for 'successful', and if I want to change the criteria I have to run a bit of python script* to run through all the records and recompute it.  One hundred twenty-five kilometers is a pretty broad definition of success, but I wanted it a bit broad for countries that don't have a Roman-based alphabet, which is hard for us Roman alphabetters to Google for. For someplace like Thailand, if you get the right country, you still have a chance of "success."

* the server side I originally wrote in Java, but since Python is faster for certain datastore operations, the boyfriend recommended we switch to that. Did I mention I didn't know any Python? or hardly anything about server side programming?

Tuesday, June 4, 2013

Privacy policy for MapTag

I thought I'd better do one of these for MapTag, too. Same template, different stuffs, more comedy.

I am one human being doing this in my spare time. I'm a geek, which means I'm allergic to salesdroids, which means I would rather spear my own eyeballs out with red-hot pokers than market remotely-related stuff to you. If that's doesn't mean anything to you, here be the legalese:

Privacy Policy for MapTag

  • This application sets a cookie which indicates if you have been to the website before or not.
  • We do not receive or collect any personal information about you, such as your name, street address, phone number or email address. Google Analytics reports your country language, country, state/province and the nearest city. It also reports your browser and operating system (though not specific versions) and the name of your ISP.  If you live in a town of 50 people we might be able to figure out who you are by asking your kid, or their best friend, who in town is browsing the web using Safari on a Mac running OSX.  Of course, that means actually travelling to your town to ask this question, and frankly, we have better stuff to do.
  • We do not knowingly collect information from children under 13. If you believe we have inadvertently collected such information, please contact us so we can promptly obtain parental consent or remove the information. 
  • We do not receive, collect or use your precise geographic location.
  • There are no methods of seeing what data we collect from you.
  • We may keep data indefinitely, though since we don't use it other than to say stuff like, "Oh, someone from Tanzania is playing, awesome!" we have no reason to keep it.
  • We do not get any personally identifiable information (such as name, street address, email or phone) much less share it with other companies.  We might consider making some up, though.  I hear advertisers pay for that stuff.
  • We do not knowingly allow advertising companies to collect data through our service for ad targeting. However, be aware that the social media buttons that are included in this game (Facebook, G+, Twitter)  means those social media networks can probably figure out that you played MapTag. If you don't want that, Chrome has a handy extension called Disconnect which disables 3rd-party tracking.
  • We take reasonable steps to secure your information against unauthorized access or disclosure. However, no security or encryption method can be guaranteed to protect information from hackers or human error.
  • Information we collect may be stored or processed on computers located in any country where we do business.
  • We may make anonymous information available to third parties in these limited circumstances: (1) with your express consent, (2) when we have a good faith belief it is required by law, (3) when we have a good faith belief it is necessary to protect our rights or property, or (4) to any successor or purchaser in a merger, acquisition, liquidation, dissolution or sale of assets. Your consent will not be required for disclosure in these cases, but we will attempt to notify you, to the extent permitted by law to do so.
  • This privacy policy was last updated on 6/4/2013. Our privacy policy may change from time to time. If we make any material changes to our policies, we will place a prominent notice on our website or application. 

If you have any questions or concerns about our privacy policies, please contact fallinghawks@gmail.com.

Friday, May 31, 2013

almost ready to submit to the games sites

Changes and additions:
  • I did add more locations. I forgot to do Israel, which is a darned interesting place to look at.  We have Bangkok, Chiang Mai, Singapore, and Taiwan.  I also added three US urban areas in an attempt to increase the chances of an urban area being selected: SF, LA, and NY (and surrounding areas of each).  Moscow was already included in the Europe ring. This seems to have reduced the chances of being on a long, straight, empty road.
  • I wrote another Javascript/JQuery/HTML file to give players a map, let them navigate in and out of StreetView, and select the location they're at as the starting point for a game.  With huge amounts of help from boyfriend, we got the game storing and retrieving those locations on AppEngine (again! start small! go slow!) And finally I modified index.html to figure out whether it's starting a pre-set game, a user-created game, or a random game.
It's just about ready to release now, I think, with one more fix: if someone calls a game that doesn't exist, the program needs to do something graceful.

Edit, a few hours later: got Israel, got a graceful error message to pop up.  The boyfriend also hacked the page and found he could store junk text in the datastore, but that didn't affect playability. He added code to address the vulnerability and so it seems more or less ready to roll now.

Monday, May 27, 2013

the world is large...

...and has a lot of very straight, very empty roads on it.

MapTag tips (which are really StreetView tips):

There is really no easy way to move a long distance in a single click using StreetView. The step distance seems to depend on how fast the car was going at the time.

The circle, which helps you take the largest step possible, is imperfect. You can't just leave the mouse on the same spot onscreen and keep clicking.  Eventually it will fuck up.  It seems if you move it a bit between each click, that will reduce the chances of it thinking you want to zoom, or adjust the view.  Occasionally I have seen it spin me 90-180 degrees off from where I was headed, so keep half an eye on your general heading in case that happens.

I find it rather interesting, after writing the game, that it's still fun to play.

At some point I may try to increase the chances of hitting urban/suburban areas.  Right now the valid random places are based on about 8 circles of varying sizes: Australia, New Zealand, South Africa, continental US/Canada/Mexico, Alaska/NW Canada, Hawaii, Europe, Japan, and Brazil.  Each has a probability, initially based on area size, but also hand-jiggered a tiny bit based on how much empty expanse it has.  I should tweak them more to have a stronger bias toward Europe, Japan, and such places that have less empty space.  I could specify urban areas (e.g. the US coasts) and give them a bit more probability of being selected.  Other places that should be added: Moscow, Israel, Thailand, Taiwan, Hong Kong, Singapore.

Sunday, May 26, 2013

finally wrote another game (but not Android)

Back in 2006 I wrote a Flash game, sort of an escaper.  In my hackathon fashion, I drew the scenes and worked out the puzzles first so I could download the 30-day Flash trial and learn enough about Flash to create the game before the trial ran out. I had it done in 20 days, a friend hosted it, and people liked it. But it was difficult enough that I didn't really want to do it again.

Fast foward to now, coming up on a year of Android coding under my belt, working with various Google APIs, along with a bit of JQuery and straight Java.  Things make a lot more sense now.  And I come across this neat little game called Pursued, which uses Google Streetview.  You get plopped into a location and you need to figure out what city you're in within a certain time limit.  It's got a lovely, slick HTML5 UI. You get achievement badges for going through themed sets of cities, and it has a separate section for players to add their own games.

Around the same time Yonatan Zunger posted about a game called Geoguessr.  Same general principle, but there's no time limit, and you're shooting for accuracy -- not a city name, but getting as close to the start point as possible.  The UI is less pretty but it's in many ways more challenging.

I mentioned Pursued to Yonatan, saying it would be nice to have a hybrid of the two games, with a slick interface and points for accuracy.  He agreed and suggested I write it.

Well, sometimes I laugh at suggestions.  Sometimes I take them as a challenge.

My all-things-coding tutor, aka boyfriend, has taught me one very important principle: start simple. Don't try to write the entire program at once.  So I got a div to display a navigable Streetview map. Then added a second large map that you could slide in and out from the side.  Then added the ability to drop a marker on that map, calculate where it is versus where the user is, and score it.  Then added another slide-out for an array of pre-set games. And finally some help and credits screens.

And this is all in Javascript, with a bunch of JQuery to listen for clicks and CSS to drive the animations.  Did I mention I don't really know much Javascript?

All in all, I wouldn't say it has a totally slick interface, but it has both a random-location game and a set of pre-set games based on a theme. Plus it scores you based on where you are in Streetview -- for some odd reason, Geoguessr scores your answer based on the original location it dropped you into, even though you might have had to travel for miles to figure out where you are.

I definitely needed help with the trigonometry of choosing a random location and measuring distance (I'm a little jealous that boyfriend didn't even need a refresher).  I received hints and general guidance, and occasionally outright coding. Apparently there are timing issues when you're asking someone else's server to give you large quantities of data: there are things you simply have to wait for, and you can't continue until you have that data in hand, so to speak. He taught me a bit about callbacks and (the formal term escapes me) chaining functions to guarantee one will start executing only after another is finished.  And of course he helped get my AppEngine settings set up so I could upload it there.

So without further ado: MapTag

Thursday, May 9, 2013

reading/writing Google Drive

Here are the broad steps to write a file from an Android device to Google Drive.  You create a unique SHA1 fingerprint for your application (step 1), tell Drive your application exists and will be utilising the Drive API (step 2).  The branding information is the "pretty" name for your app; the package name is its name in your code (e.g. com.example.myapp). Library and dependency installation (step 3) is easy if you have Eclipse; if you have IntelliJ, one of their programmers has shown how to create the analogous configuration on StackOverflow.

The sample code, Drive Quickstart, starts up the built-in camera app, grabs the Uri of the saved image, and uploads it to Drive.  In the process it needs to get a login name and authorization to write to Drive.  Since life is uncertain, it uses startActivityForResult, which returns a result code to determine the next action.  I needed significantly more complicated behavior for writing the file, but this is the basic sequence of events.


My application stores the user login (e.g. "mightyjoeyoung@gmail.com") in SharedPreferences, so once it's set, it won't ask again. There are some initial checks if a) a stored name exists and b) the stored name actually associates with a valid account. If it finds nothing, it starts an account picker Intent.


app  = (App) getApplication();
// check for a previously saved login
settings = getSharedPreferences(app.PREFS_NAME, 0);
String savedLogin = settings.getString("savedlogin", "");
if (!savedLogin.equals("")) {
    app.credential.setSelectedAccountName(savedLogin);
    service = getDriveService(app.credential);
}
if (savedInstanceState != null) {
    inProgress = savedInstanceState.getBoolean("inProgress");
}
if (app.credential.getSelectedAccount() == null) {
    startActivityForResult(app.credential.newChooseAccountIntent(), REQUEST_ACCOUNT_PICKER);
}


When a valid account is set, it authorizes and creates a Drive service object

Drive service = new Drive.Builder(AndroidHttp.newCompatibleTransport(), new GsonFactory(), credential).build();

which is used for the reading/writing transactions.  Failure to authorize results in going back to the account picker.

If all is well, it grabs the Uri of the file on the phone (which was created before starting the whole process) and attempts to upload it.

Drive Quickstart's sample code has no UI beyond the bare minimum.  While it's busy trying to upload, by all appearances the app has hung. And the first time it's run, it can take up to a minute to complete the process (or at least that's what happened to me).  They don't even bother to compensate for changes in screen orientation.  With a progress dialog popup and ongoing status messages, users will be less inclined to cancel.

Drive has a quirk (as mentioned in an earlier post) of keeping track of files with an internal ID rather than the file name. Multiple writes of the same file name results in multiple files with the same name.  Rather than confusing the user (and the macro that adds the records to the spreadsheet) I had to get hold of that file ID, save it to SharedPreferences, and when time came for rewriting, write to that ID.  And, if the user had happened to trash it, fish it out of the trash.

So the logic goes: if you have an ID previously saved in SharedPreferences, and that file exists, you're good to go and overwrite. (And fish it out of the trash, whether or not it's in trash, because it's not super easy to tell if it's in trash.)  If you don't have a saved ID, or you do but the file isn't there, you have to create a new file (and after it's written to Drive, get its file ID and save it).

Here is a list of the methods to work with Drive files. There is also some sample code at the end of each method's page.

One weirdness about the Drive Quickstart sample code: for reasons unknown, it asks for full access to all the files on the Drive.
credential = GoogleAccountCredential.usingOAuth2(this, DriveScopes.DRIVE);
It doesn't need this, and your users will be O_o if your app asks for the same permission. You really want your app to access only the files it creates:
credential = GoogleAccountCredential.usingOAuth2(this, DriveScopes.DRIVE_FILE);

Lastly, the boyfriend's phone seemed to need this added to the manifest:
<uses-permission android:name="android.permission.USE_CREDENTIALS"/>
I'm not sure if this was due to his Android version, or that he has more than one account registered on the phone, or that he has two-stage authentication.

Wednesday, May 1, 2013

Well, scratch that

I still don't know if I want to put it in the Play Store or not, but I restored (since that's what I had it doing before we decided to use Drive) a Share button.  That brings up the generic dialog to send a text file: your choice of Bluetooth, Copy to clipboard, Drive, Email, Gmail, Google, G+, and Text message. So it doesn't require Drive and the Drive spreadsheet macro, and the user is free to pop the data into their own spreadsheet or database.  It's just a CSV file.

And yes, I did make a steampunk scale. I photographed the top surface of a Deco vanity, mushed it into the right proportions, and stuck on Googled images of brass gears and wood borders and such.


However, There are semitransparent XML borders around the weight "dials" and the Save button (see previous post, updated to include the new Notes field and the changes mentioned above), and I haven't coded to compensate for the significantly darker color of the wood scale.The font color is that not-quite-black of Android text, and though the digits are nicely visible, Save is not.  It looks, in a word, awful.  So I'm not posting the pic.

The ideal thing would be to have a semitransparent white for the Save button and remove the border entirely for the dials. We'll just have to see how easy that is to do programmatically.

Wednesday, April 24, 2013

victory declared

Well, it seemed poised to get into the endless-polishing stage, but I think I'm pretty much done with the weight app.  (Although I would kind of like to draw a steampunk scale.)

This has pretty specific requirements. You need to have a Drive account and you need to have a spreadsheet with the macro installed.  It is also designed on the assumption that it is used to record a single weight at a time.  For these reasons I won't be putting this in the Play Store.

Main screen. It will remember the last
weight you entered.

Change background image

Of course, the enter date can be
changed anytime
List of weights and upload button.
Individual weights can be deleted by
swiping away. The menu option lets
you delete all the weights.


If you haven't signed in before, it will
bring up a picker to choose your
Google account. It will remember the
account for all subsequent uploads.







File is always uploaded to LatestWeights.txt on the root (this is not configurable).  The app will
always overwrite an existing file.  Technically speaking, you can use the text file simply as a way
of backing up the database on the phone.

The Google Spreadsheet uses a macro written to find LatestWeights.txt and add its records to the sheet.






























Monday, April 22, 2013

concerns about piracy

Update (5/10/13): Google took this pirate down and I feel gratified. He may just pop up somewhere else, but he'll have to pay the developer registration fee again.  Twenty-five dollars may not seem like much, but it offsets some of the ad revenue, which I've heard is pretty tiny.  Heck, my friend's book has been up for over 4 months and our combined profit hasn't hit that yet.

I was browsing Play for a game to download, when I came across this one. I thought it looked familiar, downloaded it and started playing.  Sure enough, it was this Flash game.

The Android version had a fair number of ads and started to annoy me, and I knew I'd played it before, so I deinstalled it and took a peek at this "developer's" other offerings.  There were a few Japanese games, a bunch of games in English.  All different styles of artwork. Then I came across one, then two, that had been written by a friend.

I had already seen this friend had ported a couple of his Flash games to Android under his own name.  This so-called "developer" was pirating other people's Flash games and posting them under his name, presumably for the ad revenue.

I looked up the Flash versions of several games and contacted four developers. One didn't respond, and the other three said they had not given permission to this guy to port their game.  I gave them the link to complain to Google about copyright violation. Hopefully this guy will get taken down.

But this leads me to ask what protections I have as a Play developer?  If someone installs my app, how easy would it be for them to take the app from their file system, load it into their IDE and add code to pull in ad networks, and push it back out to the Play store as their own?

Google recently won a case against Viacom wherein its subsidiary YouTube was found to be protected by the DMCA for hosting Viacom TV shows uploaded by its users.

Google also protects copyright in other cases, such as copyrighted music being used in user videos.  It has, as far as I understand, a fairly sophisticated algorithm to search for and match to copyrighted material.

Is the same effort put into protecting people who may not even know their work has been ported to Android?  Or at least work that already exists at the Play Store and is pirated into another Play Store app?  Or is it up to developers to constantly search for theft of their own work?

Wednesday, April 10, 2013

The weight project part 2

Eclipse vs IntelliJ and The Google (Drive)

I started programming Java, then Android with IntelliJ some 10 months ago.  I like IntelliJ.  However, the Google Drive example assumed you were using Eclipse, a popular and also free IDE.  It has its own plugin to incorporate Google libraries.  I admit I don't understand more than the rudiments of code libraries, so when I started working on the example I could not figure out how to make it work in IntelliJ.

I downloaded Eclipse, and after some struggle with the newest version and learning that it and the Android SDK don't play all so well together, downloaded the next-older version and got it working.

I also learned enough about Eclipse to realize I didn't like it all that much.  It's slower, even when you tell it not to automatically compile, and seems delicate.  It keeps track of projects in a completely separate folder, so if you delete a file from outside, or rename/move the folder, then try to load/run it, Eclipse has a hissy fit and faints.  IntelliJ just looks at what is there and deals with it, even if your project is open.  Robust.

I struggled for days trying to add the libraries to IntelliJ the way I was guessing they were being added in Eclipse.  (On the Drive example page, there was no description of what the plugin was doing under the hood.)  I finally broke down and asked the collective wisdom of StackOverflow.

After some wrangling with a guy who initially didn't seem to understand what I was asking, he built the example himself and presented me with exactly how to add the libraries. Bless this sweet Russian guy's heart.  Once I had this, I placed it straight into the weights app and it worked beautifully. Yay!

Saturday, April 6, 2013

tackling Google Drive

The boyfriend steps on the scale every day, records his weight on the whiteboard, and every once in a while enters those into a Drive spreadsheet, which has a little chart showing his progress.  (At 177 +-2, he's quite reasonable, but he feels tracking helps him keep it that way.) So I wrote a little database app for his phone.  It saves weights to a comma delimited text file and uploads it to Drive.  A macro in the spreadsheet grabs that file and puts the entries at the end of the sheet.

The fun (/sarcasm) part has been learning to upload or update this file on Drive.  The API is less than well documented, a lot of the code is compiled so you can't read it in the IDE, and that makes it extra painful since I'm barely versed in these sorts of things.  However, there's some nice sample text at the Developers site that show the basics in Java (see "Manage Drive Files").

Interestingly, Drive commands are not so much like a file system as a database.  One updates and inserts files instead of copying them.  Drive files have an ID, which is a separate creature from the name ("title").  Inserting a file will create a new file, and it could have the same title as another file that already exists -- it won't automatically overwrite it.  It's got a different ID, so it must be a different file.  So you have to look for the file and grab its ID, and from there you can update it, or do other stuff like delete, change its title, etc.

Drive requests do not ignore the Trash folder, either.  During testing, I deleted the uploaded file from Drive, expecting the upload to create a new one, and was frustrated for quite some time because my "new" file wasn't showing up. It had been happily updating the deleted file.

The other thing to watch out for is how much you're trying to do.  I followed the Developers sample code to list the files, and it grabs *all* the files, Trash, subfolders, everything. You have to add a query (yeah, database again) to restrict the file listing to where you want it to look, and better yet, the name.  After adding the query

request.setQ("'root' in parents and title = 'LatestWeights.txt' and trashed=false");

the whole process speeded up remarkably.

Monday, April 1, 2013

memory lane - 23 years of falconry

I've been birdless for a couple months now, so I'm feeling sentimental.

I will start off by being disappointing; there are no photos of my very first hawk. They were destroyed in the Great Chicago Fire or something.  Seriously, I'm sure they're somewhere in an album I can't find due to the state of my desk. (Note to the wise: a messy person should never have a 6x4 foot flat horizontal surface, for they shall never find anything again.)

The Apprentice Birds

FRT #2 on the arm of a bystander
My first red tailed hawk I trapped along the San Mateo coast flyway. She was a midsized female, and I didn't have her for very long.  I had just started freeflying her a few weeks earlier when she got into a tiff with a resident hawk.  They spiraled up into the sky, each trying to get a height edge, and after a point I couldn't tell who was who, and I suppose by then it didn't matter.

It was a long wait for the next season, and in October I trapped another female on the coast. We named her Pumpkin, it being close to Halloween, and I got her hunting... eventually.  I think I took about 15 or so jacks with her before losing her in a situation identical to the first.  That time my sponsor was with me, and while I gawped at the two birds spiraling up, he jumped in his truck and tried to follow where they were going.  Eventually he came back, probably puzzled as to why I hadn't followed.

Patience is a falconer virtue.




Yes, I named him Fluffy.
The following season I found my new hawk in the hills north of Livermore. It was really early in the season, or perhaps he was a late hatch, and perhaps due to the remoteness of the area, he was the calmest passage bird I had encountered so far.  He figured out the glove quickly and when I approached him on the perch, he would look like he wanted to bate but held steady for a much longer time.

I knew he was bold: he had a large bloodstain on the trailing edge of a wing which I was certain was not his.  And when the weather turned wet, he started smelling really, really bad.  Before I'd ever met him, he'd tried to catch a skunk. And may have succeeded.

His first kill with me went like this:  I had spent weeks walking the field with him, 4 or 5 days a week, showing him jackrabbits, encouraging him to go after them.  He simply watched them.  Once in a while, he'd launch and cruise by, then land, watching them run away.  I was getting frustrated, naturally, but I hadn't had to bag the female, and I didn't think I should have to bag him either.  But I was contemplating it.

One afternoon, it was cold and drizzling, and just plain depressing because I knew it was going to be more of the same: watch, cruise, land, watch. I trudged around the field, not seeing much under the low grey sky.  Then he launched off my fist and cruised low, barely 2 feet off the ground. Just as I was wondering what the hell he's doing, he did a tidy little wing-over, and nailed a sitting jackrabbit in the head.

From there it was golden.  By then I was more experienced and had learned a bit about how hawks think.  We developed an amazing bond and an ability to communicate.  He was incredibly tenacious, and more than once got dragged 30' under a tree and still held on long enough for me to get in there and secure the rabbit.  During that wet season he also learned he could drown them by dragging them to a nearby puddle.

I don't know how many jacks we caught.  I hadn't bothered keeping track in those days, but if pressed to guess, I would say 40 that first season.  To me, that was a lot, plus I was feeding him up every time we caught.

Late in the season he broke a leg due to a bungee leash. We had it splinted and hoped for the best.  The final X-ray showed it was pretty close.  There are two bones (like the fibula-tibia pair); the larger one had broken, the smaller one managed to keep things in place. As always, he was calm at the vet's, and I think he rather charmed her with his tameness.

We used to take hawks out for evening coffee.  It's a great way to let the public see hawks, and it's great manning for a passage bird.  Just sit with them someplace where they can feel somewhat safe, like next to a wall; they get nervous when threats can come from every direction, and a wall eliminates half of them.

The following season we started slowly but soon he was back up to speed.  The field was a bit thinner that year; we lost part of it to a building, and the jacks were warier.  But we kept catching; it just took a little longer.

It wasn't until years later, when I had my own apprentice, that I realized how lucky I'd been to have a field  full of jackrabbits five minutes from my house.  I would run home, throw on my boots, get the hawk in the car and get 15 minutes of hawking before it turned too dark.  The place was actually a series of 4 fields, the largest of which was maybe 15 acres.  It was surrounded by business parks, so the jacks had nowhere else to go.  A vast field with no boundaries sounds nice on the surface, but a small, defined place is a better setup for a falconer.

The enamel pin I designed, and the photo that inspired it.
At the same time I had also been made a general falconer, which meant I could buy a Harris's hawk or other such captive-bred bird.  I loved Fluffy (so named because I could scritch him on the breast and he would fluff it up and preen it), but I was looking forward to that.  And I was also thinking he was such a great bird that he should have the opportunity to make more great babies.

I was driving over the hill in San Mateo between 101 and 280. It was one of those days that's rainy, but the sun comes out every once in a while and blasts every droplet into a ball of focused light.  And I realized that Fluffy deserved freedom. This was his world, the sun and the sky and the rain, he belonged there, and I was going to give him back.  Yeah, there were tears in my eyes.

About three years after I let him go, a falconer friend happened to mention he'd spotted this tiercel redtail who was catching jacks in his field (which was one of mine, but one I didn't fly often).  He'd walked up to the redtail and it looked down at him, unafraid.  I'd like to think that was Fluffy.



The Flying Wolf Pack

My next baby dragon was a tiercel Harris's hawk. Originally from Bill Murphy's stock, he has the distinction of having been raised by a pair of harpy eagles at the Peregrine Fund.  The P-Fund didn't know how the harpies would react to babies, since it was their first year captive-breeding, so the fertile harpy eggs were rolling safely in an incubator, and eggs of lesser value had been substituted.  The harpies raised their Harris hawk chicks just fine.  Despite this unusual parentage, he was always afraid of large, eagle-shaped objects in the sky.  This would be prophetic.

Squeaky was a great bird -- compared to redtails, he was psychic.  After a long training period (my choice; I was still thinking I was training a passage RT) we caught everything: cottontails, jackrabbits, ducks.  Even, after some struggle, a pheasant or two.
Squeaky spent a year at a breeder's, and came back with the Conan anklets.
It's hard to fold eight years of a hawk into a few paragraphs. But he was my best buddy, my go-everywhere bird, my falconry ambassador to my mom (who finally accepted falconry as a part of my life after he charmingly nibbled a bit of ham from her fingers, and politely looked at her expecting more), my bunny-catching machine who would gladly step off for a quail thigh.

He got knocked around some by the jackrabbits, one time breaking off the outer shell of one talon, then later tearing a flexor tendon on his center toe. When he put that foot up, the toe wouldn't close, so he was flipping me off all the time.  It took some years to heal, but heal it did.

I tried to breed him, but he was pretty much an imprint despite his first 50 days in the chamber.  I took him home after a year or so, where he joined the slightly mental tiercel Harris I'd acquired while he was away.

Polya was a hand-me-down bird, given by a friend who wanted to focus more time on his peregrine.  I was his third owner and was told he was good on game, but tended to go after jackrabbits only in heavy cover -- i.e. moving slowly with potential for stuckage.

He was a character, rather still and reserved, and often seemed grumpy even when he had one foot tucked up.  From this we named him Napoleon, which quickly became Polya -- which is also "field" or "glen" in Russian (поля).  More aggressive than Squeaky, as well as slightly bigger, he did okay in the cast, but just okay.  When bored he would go after Squeaky, who was Ghandi when it came to HH aggression.  Squeaky, slightly smarter than Polya, learned that if he got quarry he could not count on Polya to assist.  Instead, he would flush up a jackrabbit then hang back while Polya came in to do the dirty work.

They caught one pheasant together
Three or 4 years of cast flying started getting wearisome, though.  It wasn't twice the work, but it seemed like a lot of to-do getting both birds ready, loading the truck, keeping track of them in the field, and trying to make sure everyone was happy and staying focused.

I gave Squeaky to a friend who had recently turned general.  This turned out to be a bad idea; the friend flew Squeaky in a cast with a female. In the past I'd occasionally flown Squeaky with my sponsor's female and she behaved aggressively toward him, so his experience had not been good. Squeaky would hang back from the two.  One day an eagle went after him, and though he tried to get away, he didn't fly toward his new owner, who would have scared the eagle off.  He lost sight of them, but came back the next day to find Squeaky's remains.

At this point in time, my husband David, who had cystic fibrosis, was spending more and more time in the hospital. I decided it was better to fly closer to home, so I wouldn't be hours away.  This brought me to a completely new chapter in falconry: crow hawking.

Polya's first owner originally trained him to take crows from the car.  I had never seen it done until a chance meeting with that owner, and I asked him to show me. It was more than slightly crazy driving down empty dirt roads looking for crows, U-turns, pulling onto the wrong side of the road, tossing the hawk out the window and screeching to a halt.

It was really exciting.

It took a while to overcome the chicken in my right foot and the other chicken in my right hand.  Part of driving is programming yourself to believe that there is only one way to do something.  It took a while to coordinate the sequence: how to make a U-turn that isn't going to alert the crows of hawkish mischief, when to drop the window, when to let the bird go.

Polya taught me.  He had been raised to car-hawk. Four-footed furries were just a sideline he had been forced into by stupid owners who didn't understand his joy in catching crows, his mission from God to eliminate the noisome race of corvids from the face of the earth.  When crow hawking he had a stance of alertness and excitement I *never* saw when we were hunting rabbits.  He did have his quirks, though: he would only go out the driver's side window.  A plump, juicy crow could be blissfully grubbing in the grass six feet from the passenger window, and Polya would lean and whine with desire, but he wouldn't go and destroy it.

It's hazardous. Polya got bumped by cars twice, one time hard enough to make him fly up to a building and not want to come down.  I thought the flight up was a last-ditch firing of neurons just before death, and he had collapsed on the roof.  I circled around the building, trying to sense where he was.  The crows circled around one spot for a while, got bored and flew away.  I spoke with people inside the warehouse, but none of them had roof access or a ladder long enough to get up there.  They were all incredibly supportive.  Finally, I called the fire department, explained the situation, and they sent a full-sized truck over.  By amazing coincidence, the captain had known a falconer in the past who had a Harris hawk and had flown the field two blocks away. He knew exactly what kind of bird Polya was. I was not allowed to climb the ladder, so I gave the captain my glove and a crow wing (plenty to hang onto).  He walked the roof, looked all around the HVAC and didn't see Polya. Not dead? Maybe.  Just as I began wondering if Polya have moved while I was inside, he spotted the bird in a tree right next to the building.  Called him back, brought him down.  The FD never charged me for the call, they were wonderful people, but it's not something I want to experience again!

Crows are very smart, and it had gotten to the point where they would alarm-call, flush, and chase my car as soon as I showed up to an area.  We still caught plenty of crows but it was taking hours, and I wanted a break.  I gave Polya to a friend who wanted to breed him, and set my sights on an accipiter.

I had always loved goshawks: their coloration, their reputation for speed and tenacity. During this time I briefly possessed a hand-me-down passage female goshawk about 5 years old. She was almost a rehab, since she came to me terrifically hood-shy and afraid of people as well. I spent a couple months working out those kinks, and her speed and power were amazing. One time I swear she pumped her wings three times and did a nearly-vertical 30 feet up to pull a duck from the sky. We took jacks and ducks, probably about 15. Since she would sometimes just snog off in some random direction, I dropped her weight, in retrospect a little too low, and she began to talk -- a surprisingly loud 'pew' -- quite often, even at night. I gave her to a more experienced falconer who raised her weight some 30g and just carried a live pigeon with him everywhere. Sadly, I heard she died not long after that, due to a heat wave, but I was left with a good enough impression to try another accipiter.

Accipiter Fever, part 1

This cute ball of fuzz was a six-day-old musket pulled from a nest by a friend.  We met up at some ungodly hour, and lugged a 16-foot ladder about half a mile uphill to get to the nest.

I somewhat followed the "Imprint Accipiter," and for my first time raising an eyas he turned out decent.  A sharpy is very small, and requires careful measurement.  Weighing three times a day became normal.  It was an excellent experience watching him grow and develop real feathers, and waiting for that last tail feather to dry up so I could really fly him.

I was admittedly afraid of eyases who smack you in the head because you trained them wrong.  Thankfully, the sharpy hit me in the head only twice before he figured out that he was supposed to be hitting other birds.

He was the author of one of the most amazing flights I've ever seen.  He went after a junco.  If you've never seen a junco, they are these small dark-and-white birds who like a low perch out in the open.  They fluff up to get comfortable, and look deathly ill.  But flush them and you'll see just how sick they are.  The junco went up, the sharpy hot on its tail, looking like a pair of fighter pilots -- and did a full loop in the air.  The junco got away.

The other cool maneuver he did was fly straight out, high up (we're talking 35-40 feet), then stoop like a falcon to mash a robin on the grass below. The robin didn't know what hit it.

The sharpy got asper, though, and x-rays showed it right where the windpipe branches to the lungs.  One day I noticed he was breathing unusually hard after a chase, and within two days he was wheezing loudly. The cure would have involved weeks of meds, he would have to stay at the bird hospital, where he'd be manhandled twice a day and probably fed by hand.  In less than 20 days he'd caught 10 quarry, mostly sparrows and towhees, and it seemed a bad time to do something that would completely change his relationship to people during this formative period.  I didn't know about pine needle infusion at the time. Someone mentioned it but it seemed so new-age and unscientific, and the person who described it didn't mention any efficacy studies. I chose to put him down rather than a) ruin his training and b) letting him go to die a slow death.  I'd never had to put down a hawk.  He was a beautiful little bird.  I never really gave him a name; he was just "the sharpy," like he was the only sharpy I will ever have.




Accipiter Fever, part 2

The next year I thought it better to get a hopefully less delicate bird, and I opted to buy a 22 day-old goshawk from a breeder in Colorado.  He turned out to be the most amazing bird ever. I had the good fortune to have a half-time job that paid well, so I could devote tons of time to him.

It was the same as raising the sharpy, just more food, and avoiding some mistakes I'd made with the sharpy.  I got a ton of good advice from three longtime falconers, each of whom had flown several goshawks.

Is this the face of a killer?
Once he had gotten to the point of flying and bagging, one of the friends gave me an open invitation to fly a field loaded with cottontail.  Pretty soon I was hanging out there the entire weekend, catching a Friday afternoon hawking session, sleeping on the couch, and up Saturday morning to fly again. The house had nothing but working falconers living there -- falconers, hunting dogs, hawks, pigeons, hawk food in living and dead forms, and enough firearms to start insurrection in a small third-world country.

It was in this chaotic environment that Alfie got manned, and in that field where he caught his first bunny.  He ended his first season with well over 100 bunnies under his belt. He too got to meet the crows and he took over 75 of those as well.



Hell yeahs


As we were coming to the end of the season, tragedy struck, big time. The first one he ran into: while flying past a mirrored-glass building to hit a crow, he got distracted by his reflection and tried to hit it.  He bounced off and landed on his back on a grassy strip.  My heart nearly stopped at the sight of him blindly paddling his feet in the air.  I gently picked him up, got him to turn rightside up. He was clearly dazed for several minutes and his right eye didn't want to open all the way.  Nothing broken or bleeding, but someplace dark and quiet would be really good.

I let him rest up for some days, and tested him with hopping to the glove, easing into tiny vertical jumps.  The right wing had a problem as well, but I was pretty sure it was a hard bump, probably bruised up badly but not fractured.  It behaved like tendonitis: it would gradually get better, then one vertical jump would stress it into pain.

It took weeks but he was getting back to nearly full-height vertical jumps and I was contemplating whether we could get a few more hunts in before he started dropping feathers. I never made that decision. One day while vertical jumping, I tossed the lure for him (my signal that we're done), he caught it, took about 3 bites, and simply stopped. And stared into space.

Hawks simply don't do this.

He wouldn't eat.  I managed to get a few bites in him, but he needed at least 50-55g per day just to maintain his weight. Overnight his weight dropped scary low and he was at the vet that day.  She wasn't sure what was going on, but his WBC was high (infection).  She was intending to x-ray him, but he opened his mouth and she saw some blood, making her think he may have eaten a rodent poisoned with anticoagulant.  She threw the whole black bag at him: antibiotic, vitamin K, VFend (for asper), and subcutaneous ringer's solution to keep him hydrated.  She sent me home with all the above, with instructions.  I had never done an injection and that was the hardest one, but fluids are more important than food.  Between antibiotics and ringer's, we poked that poor bird full of holes for four days.

Within a few days he'd regained an appetite, and seemed willing to hop to the glove again, though the wing was still touchy.  We switched to oral meds (not a ton of fun, since they're all sorts of weird flavors that goshawks find icky.  I forget who gave me the tip, but I ended up buying a jar of chicken baby food, mixed his meds with a blob of it, and smeared it on the real food.)

Fifteen days after the first vet visit, she felt he was stable enough to x-ray.  And he had a blob of asper in his right lower air sac.  We put him back on the VFend.  I contemplated and decided against the surgical option, which involves sending an instrument into the air sac and directly spraying asper medication on it.  I phoned Steve Layman to talk about the pine needle infusion treatment.  Half a cup of pine needles steeping in boiled water in the hawk box, twice a day.  Alfie didn't really care for it.  He'd put up with it for a while, then start bouncing around inside the box.  I made a dark box and that helped a lot.  I kept him in there as long as I could, which ended up being a total of maybe 2.5 hours per day, considerably less than Steve's recommended 6 hours.

And slowly, he got better.  The second x-ray showed a definite reduction, and the final x-ray, taken two months after his first visit, showed only a slight mark that might or might not be asper.
The hawk should have an hourglassy shape, as in the last picture.
Ultimately, there was a tradeoff: Alfie was alive, but he barely molted.  We started the next season with two mature decks and a smattering of grey body feathers, but his flights were tipped from the first season and weren't getting better.  I had imped two tail feathers the first season and he broke another next to the decks. He was starting to look bad, though not as wrecked as some goshawk trains I've seen.

And he was alive, and was catching crows like nobody's business.  (The bunny field went rather sparse.)

Sometime in November or so, I'd heard that Polya had not bred (like Squeaky, too imprinted or, in Polya's case, a misprint) and he had been given to another falconer.  But she had gotten a taste of Polya's quirks (I didn't mention that he hates children, and tries to kill dogs, did I?), and at the weight he was at, he was in no condition to have his head on straight.  A fat hawk has no sense of self-discipline.  She asked me if I wanted him, and I said yes, more to get him out of that situation than a desire to have a second hawk that would not fly with the first.

I hung onto Polya for a couple of months, but at that point I had an 8-to-5 job with a 1-hour commute each way, a boyfriend who tended to stay up late, and two hawks that I was forced to fly only on weekends.  At my third moving violation I knew I was doing too much, and the only way to fix it was to stop doing things.  I gave Alfie away, then Polya.  A while later, for reasons unrelated to stress, I dumped the boyfriend as well.

Alfie and his new falconer
Alfie's falconer patiently molted him out, and they are currently having a blast together.  Polya's falconer gave him to an apprentice falconer, who is as far as I know having a blast with him.  Between them, they should depopulate California of crows.  And I found the best boyfriend ever.










Accipiter Fever, parts 3a, b, and c

This one is brief -- I was never able to get to the point where we had an understanding of what the other one is supposed to do.  We had multiple strikes going: one, he was the first passage bird I'd had since apprenticeship; second, the first thing he did in my possession was break a hallux toe from bating; third, he was a Cooper's hawk; fourth, he was a Cooper's hawk, and fifth, he was a tiercel Cooper's hawk.

He spent his first three weeks mostly hooded with a splinted toe.  That never healed quite exactly right, but he was a bold little guy with a grip like iron.  I had him catch sparrows in the living room a couple of times and his agility was breathtaking.  But it was hard even getting decent behavior from him in the house, and our few times in the field together were complete failures.  I fed him up and let him go after about five weeks.

I've been assured by friends with significant Cooper's experience that this is not unusual. Only a small proportion of passage Cooper's hawks are capable of working with people. Experienced Cooper's people will trap several, and keep them for a few hours to suss out if they have one of the 10% that are wired to be a falconry bird.

After this gentleman I acquired a female Cooper's. She was a dream from day one: eating on the glove right away, cooperative, and a lightning fast learner. She went from wild to hawking with me in a mere 7 days, and caught wild quarry with me in just a few more days. She hit pigeons and crows like nobody's business. There were only two blots on the picture: she had a case of roundworms that resisted my efforts to treat it, and, as we continued nailing crow after crow, I began noticing she only wanted the close, easy slips. She wouldn't fly the distances I'd expect from a Cooper's.

These were totally, directly related. Apparently ivermectin is not that effective when it comes to roundworm. I switched to Panacur, but I was simply too late. The roundworms had damaged her intestines sufficiently to kill her.

One more female Cooper's was given to me. She was rescued from a warehouse and the top of her head was bald from bashing against the ceiling. Her rescuer had brought her to a fat 500 grams. I started to trim her back but it quickly became clear she was not one of the 10%. Not as nutty as the tiercel, but definitely not the cooperative sort. As soon as I had fattened her up again I let her go in a county park which is loaded with small birds and has water year round.

Going south

I was still interested in a Cooper's sized bird, but the last one told me that me and Cooper's hawks were probably not meant to be. It takes a special falconer to work with their reptilian brains, and that falconer was not me. A breed that had less potential for fatal health problems was also desirable.

This came in the form of a Peruvian Harris hawk. I acquired him at 12 weeks old from a pair that had originally come from Peru. I've had him about a month now.

Monday, March 18, 2013

Managed cursors and SimpleCursorAdapter

Are deprecated.  RIP.  I found a truly excellent example of ContentProvider with SQLite, populating a ListView, here. It's probably a little more complicated than it needs to be, but then again this whole ContentProvider thing seems so needlessly complicated. Another good write-up is here, covering both the old SimpleCursorAdapter and ContentProvider.

But if you want other applications to access the data, you need to use ContentProvider.  No turning back now, as they say.

Sunday, February 10, 2013

Monday, February 4, 2013

Did it again!

A new app, inspired by XKCD comic #1133 for #upgoerfive lovers.

Saw the comic when it was published in January, laughed even though the secret English major in me shuddered at the awfulness of having to use a tiny subset of the language.  Then the boyfriend sees the hashtag moving around, sees Splasho's editor, and says, hey, this could be a fun silly thing to write for Android.

This turned into a weekend hackathon and really ended up being a big part of my birthday.  We completed early Sunday evening, fell into the endless polishing stage, and got it uploaded to Play late Sunday night.

Get the app here

Privacy policy? We got 'em here.

I am one human being doing this in my spare time. I'm a geek, which means I'm allergic to salesdroids, which means I would rather spear my own eyeballs out with red-hot pokers than market remotely-related stuff to you. If that's doesn't mean anything to you, here be the legalese:

Privacy Policy for Apps from Fallinghawks Studio

  • This application may log information like your Android version, phone model, and error messages generated by the application.
  • We do not collect any personal information about you. In other words, we do not collect information such as your name, street address, phone number or email address. We do not access your contacts list. As part of its sales reports (which we receive for paid apps only), Google Play reports to us your name, city, state, zip code and Android version. 
  • We do not knowingly collect personal information from children under 13. If you believe we have inadvertently collected such information, please contact us so we can promptly obtain parental consent or remove the information.
  • We do not collect or use your precise geographic location.
  • There are no methods of seeing what data we collect from you, though if you contact us we'll be happy to show you what we've got on you.
  • This application may contain links to sites on the internet, each of which has its own privacy and data collection policies. Google, YouTube, the Play Store, and Blogger are all far more interested in you than am I. I'm just here to try to solve any problems you encounter with my app.
  • The Weight Record app stores your login to Google Drive if you use it to upload records to Drive.
  • We may keep data indefinitely as part of our debugging records.
  • We do not share personally identifiable information (such as name, street address, email or phone) with other companies.
  • We do not knowingly allow advertising companies to collect data through our service for ad targeting.
  • We take reasonable steps to secure your information against unauthorized access or disclosure. Google Play encrypts transmission of data on pages where you provide payment information. However, no security or encryption method can be guaranteed to protect information from hackers or human error.
  • Information we collect may be stored or processed on computers located in any country where we do business.
  • We may make identifiable and anonymous information available to third parties in these limited circumstances: (1) with your express consent, (2) when we have a good faith belief it is required by law, (3) when we have a good faith belief it is necessary to protect our rights or property, or (4) to any successor or purchaser in a merger, acquisition, liquidation, dissolution or sale of assets. Your consent will not be required for disclosure in these cases, but we will attempt to notify you, to the extent permitted by law to do so.
  • This privacy policy was last updated on 2/8/2017. Our privacy policy may change from time to time. If we make any significant changes to our policies, we will place a prominent notice on our website or application. 
If you have any questions or concerns about our privacy policies, please contact fallinghawks@gmail.com.

Wednesday, January 30, 2013

troubleshooting the Play store, yikes!

Bird Calling is a pretty specialized app, so we've had few sales so far (sad face).  Niki promoted it on FB today and got a few people interested enough to shell out $1.99.  One of the users though had a problem with an infinitely long download ... tech support to the rescue ... who, ME?

Yes, me.  Who else is going to do it?  Former IT manager to the rescue.

So I ask him if he's downloading via Wifi connection or his data plan.  Data plan.
Does he have any other problems with the data plan, like is it slow to get Maps.  No.
Can he download another large app from Play?  I find a free 58 MB game called Factory96, ask him to download.  It doesn't work either. (Whew. Not my app.)
I tell him that Wifi is a much more stable data connection, and can he connect to his Wifi network and try again.

A few minutes later... SUCCESS.  Yay!

Thursday, January 24, 2013

at the Play Store

Searches:
bird calling - Angry Birds Star Wars tops a list of over 1000 hits; of course my app is nowhere to be seen.
nicole bird calling - my app plus two "zombie solitaire" games
perretta - my app plus two others
nicole bird - my app plus five or six others
nicole calling - my app close to the top of ~35 others
bird call lady - 0 app results
"bird calling" and "bird call lady" (in quotes) return only my app

I'm not displeased. Those who don't spell Perretta correctly can still find  it with Nicole.  The thing I find quirky is how bird call lady without quotes brings up nothing, but with quotes, it finds it (it's a phrase in the description).  I want it to be findable by people like your mom, or my mom, or anyone who doesn't really get that UI has certain common patterns.  You know, the type who would have been better off with an iPhone ;) .

[A few years back I had a sort-of-boyfriend who had a Mac laptop. I know, the finest of programmers use them these days now that they're Unix based, but I'm from the era where Macs' main selling point was their friendliness to the non-technical. Watching this boyfriend browse the internet was an exercise in self-restraint against yelling "NO NO NO NO DON'T CLICK that spammy link," or expecting to peruse a website in an organized manner. When you're using a computer (or anything with a lot of visuals, like an airplane) for the first time, you have a lot to look at and have no idea what's important and what's ignoreable.  After a while, most people learn to discern what's important, but some don't -- to them, the computer screen is a Jackson Pollock painting where every place is equally important, and they click on whatever is in front of them.  That's the kind of end user I'm talking about.]


And one last bug got eradicated: I'm glad one of my beta testers had a Samsung Galaxy S3.  Despite the normal-sized screen, it's xhdpi and from what I could gather from here and here, the S3 uses about 4 times as much memory for an image than other devices.

And naturally, after that bug was done I forgot to include the typo correction in the database and forgot to add the name of the beta tester who found the typo. Hence version 1.0.2.

The uploading of a revision is a bit mystifying.  It gives this weird notification about how people who might download v1.0.0 would now be getting v1.0.2, and it gives the impression this is a bad thing.  It isn't entirely clear that you must archive the old version first in order to activate the new version, then you additionally have to publish the new version.  I'm sure there is reasoning behind this, but it's not the same as my own.

Tuesday, January 15, 2013

It's done and live!

Here's my app:

"Bird Calling" by Nicole Perretta

I had been waiting for my beta testers to get back to me on the "final" version, and I'm glad I did, because one of them found a bug. The pictures are pretty large (sized for a 7" tablet), and each time you launch an Intent (i.e. go to another bird by clicking rather than swiping) the picture goes to the back stack and stays in memory.  We had already done some work to shrink pictures for smaller/older devices, but the back stack was killing even the Nexus 7 within about 5 or 6 back stack additions.  We changed the code to recycle the bitmap sooner rather than later.

Thursday, January 10, 2013

RelativeLayout for dummies

When I started working with Android I was doing strictly LinearLayouts, but they get complicated and ugly very fast. It's analogous to rowspans and colspans in HTML tables, only messier.  Then I learned about RelativeLayout.

It's slick in that you can declare all your elements in (pretty  much) a single RelativeLayout instead of having a zillion child LinearLayouts.  All you have to do is say where an element should appear in relation to another element. To do this you have

layout_alignParentRight, ~Top, ~Left and ~Bottom to anchor your element to the layout itself.  These are ="true" (or not declared at all, I suppose).

layout_toLeftOf and ~RightOf, and layout_above and ~below for positioning relative to other elements.  The argument is the id of the other element, e.g. ="@+id/titleBox"

Things learned: the LinearLayout urge is to declare elements in order of appearance from top to bottom.  Don't do it that way.  Organize by items that are going to stay a fixed size and location versus items that you want to stretch to fill the remaining space.

So I'm laying out elements for a basic media control. It has a TextView for the title of the clip, a ProgressBar, an ImageButton that will later be coded to toggle between play and pause images, and two more TextViews, one to display the total length of the clip and one for the current time position.

I want the title on the left, the play/pause button on the right, and the progress bar to stretch to fill any space in between.

So the first two things I declare are the title and the button.

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:background="@color/offwhite">
    <ImageButton
            android:id="@+id/btnPlay"
            android:src="@drawable/playbutton"
            android:layout_alignParentRight="true"
            android:scaleType="fitEnd"
            android:layout_width="70dp"
            android:layout_height="70dp"
            android:paddingRight="10dp"
            android:background="@null"
            />

   <TextView
            android:id="@+id/songTitle"
            android:textColor="@color/d_gray"
            android:textSize="20dp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:paddingLeft="10dp"
            android:paddingTop="22dp"
            android:text="clip title"
            />

Then we'll jam the seekbar in between, with a little padding to give it some distance from the other elements.
    <SeekBar
            android:id="@+id/songProgressBar"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_toLeftOf="@+id/btnPlay"
            android:layout_toRightOf="@+id/songTitle"
            android:paddingTop="20dp"
            android:paddingLeft="15dp"
            android:paddingRight="15dp"
            />
The last two textviews are anchored to the seekbar itself.  They have the same left and right padding as the seekbar.
   <TextView
            android:id="@+id/songCurrentDurationLabel"
            android:textColor="@color/d_gray"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignLeft="@+id/songProgressBar"
            android:layout_below="@+id/songProgressBar"
            android:paddingLeft="15dp"
            android:text="current time"
            />
    <TextView
            android:id="@+id/songTotalDurationLabel"
            android:textColor="@color/d_gray"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignRight="@+id/songProgressBar"
            android:layout_below="@+id/songProgressBar"
            android:paddingRight="15dp"
            android:text="total time"
            />

This is so much cleaner than having about 3 nested levels of LinearLayouts.