Tuesday, February 17, 2015

Android : File exists but canRead() returns false

I'm working my way through this developer document about capturing and saving photos and ran into a problem. My photo was saved properly, I could call up the ADB shell and verify it. But when I tried to read it back so that I could display it on the screen, this code would fail:

File imgFile = new  File(mCurrentPhotoPath);
if(imgFile.exists()) {
    Bitmap myBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath());
    
    ImageButton btn = (ImageButton)findViewById(R.id.photoButton);
    btn.setImageBitmap(myBitmap);
}

Sound familiar? I had requested the WRITE_EXTERNAL_STORAGE permission properly (which implicitly gets the READ_EXTERNAL_STORAGE permission as well), so that wasn't the problem.

It turns out that the file does indeed exist, but it was failing on canRead().  Since canRead()==false, exists() was also returning false.

Ok, then, why can't I read it?

The problem lies in the photoPath, and whether to use a URI or a regular file path descriptor.  The code that we're talking about ends up structuring a unique image filename that looks like this:

file:/storage/sdcard/Pictures/JPEG_20150217_071154_2008426377.jpg

which worked fine to save the file. But on a hunch I tried a pure file path:

/storage/sdcard/Pictures/JPEG_20150217_071154_2008426377.jpg

and guess what? That worked.

Wednesday, January 07, 2015

Android APK Can Not Press Install Button

There's lots of reasons why you might want to load an APK file directly onto your Android device. In my case I'm developing an app and didn't want to always have a USB connection setup, so instead I save the APK to my Dropbox directory, and then it appears nicely on my device.

But a problem appeared recently. I get a dialog asking to confirm the install, with CANCEL and INSTALL buttons. And the Install button doesn't work.  This is weird.  It's not disabled. It shows no interaction like it even realizes I'm pushing it. The Cancel button continues to work. But Install, no matter what I do, will not work.  I long press it, I do everything I can think of. Nothing.

I do have "Allow unknown sources" checked, of course. Just to get that out of the way.

I google around and find references to disabling any "screen dimmer" apps that might be running. Why? I have no idea. But I do run Twilight, which alters the colors of my screen at night so it doesn't glare in my face.

I turn that app off, and look at that! The install button works all of a sudden.


How To Record XBox 360 HDMI To Composite Video

My 8yr old son currently idolizes somebody named Stampy Longnose, who is a character that makes YouTube videos of himself and his friends wandering around Minecraft. For months my son asked for "recording material" so that he, too, could develop a following like Stampy.  We kept saying "Maybe for Christmas, maybe for Christmas." Well Christmas came, and he did not forget, it was at the top of the list.  So his grandparents got this magical recording material for him. Since they had no idea what it is, of course, now it's up to dear old Dad to make it work.  It took me a lot longer than I thought it would, so I'm documenting the process for those other dads that find themselves in a similar situation.

My son has an XBox 360 E. I can only speak for these instructions relative to that particular console. I discovered that this is a big deal, because it appears that our old pal Microsoft has been changing the video output port pretty much every time.

There are many results on Amazon for xbox recording device (I don't know why my son insists on calling it "recording material"), ranging significantly in price. Although we've got our device connected via HDMI I was not prepared to get what seems like the most popular device, the Elgato HD Capture.  After all I have no idea if he's going to get bored with this in a week once it actually works. Instead we went with the Elgato Video Capture, which is almost half the price. I say we, because although this is the gift my in-laws wanted to give him, they had no idea what it is so I was tasked with doing the research and picking the item :)

Christmas came and went, my boy was excited to finally have the device and we went about setting it up ... and I discovered my first problem.  Our device has an HDMI port.  This recording device has composite cables, otherwise known as the classic Red/Yellow/White combination. Do not confuse this with "component cables", which have 5 separate heads including a green one.

This is not a problem. I get back on Amazon and search for "XBox composite cable", getting plenty of results for around $10 or less.  I bought one. DO NOT DO THIS.  I'm deliberately not linking it.

We wait a few Amazon Prime days, cable arrives and ... it doesn't fit. The particular cable I got has this big fat port on one end, bigger than an HDMI port, and my device simply does not have that.  "Aha," I think, "I must have mistakenly gotten the cable for an older XBox model, not for the 360.  My bad."  I return to Amazon, search for "XBox 360 hdmi composite cable," and thinking I see one that has an HDMI port on the end, get that one instead.

Nope.  Same stupid cable with the big fat end.  Now I'm upset.  My device simply does not have that port.  All I have is an HDMI port, and a little 3.5mm jack next to it that I have assumed is a standard audio-out jack.

It's not.  I finally found this document from Turtle Beach that set me straight:
As you can see above, the trapezoidal A/V (Audio/Visual) port from older Xbox 360 models has been removed and replaced with a single 3.5 mm output jack. The Xbox 360 E includes a 3.5mm Composite A/V Cable (yellow, white, and red), used for connecting to standard-definition TVs.
Oh! That explains both my problems.  First, it is the "E" model that got rid of the older A/V port, which explains why I keep getting the wrong cable.  Second, that 3.5mm jack is actually going to spit out both audio and video.  Nice.

What I needed was this cable . Your XBox came with this cable, but if you're like me and immediately plugged into the HDMI port of your television you may no longer know where you put this original cable.  I actually lucked out, I found it gathering dust in a drawer under our television.

Now we're cooking.  Plug the 3.5mm jack into the Xbox, plug the Red/Yellow/White into the recorder, and...now what.  There's a USB port on the other end of the recorder, so we plug that into my Mac, download the software, and it goes into setup mode asking me to plug in the yellow cable and proceed when I see video.  I don't see video. What's weird is that I'm getting audio.  I wonder what the odds might be that this brand new cable is somehow broken, and decide that can't be the case.

I'll fast forward here. Two things.  First, you can't have your HDMI and your A/V both plugged in at the same time. If you do, the video will only go through HDMI, and go to your television rather than your recorder. So unplug your HDMI.  Yes, this means that when you want to record your Xbox you're going to have to get behind your console, unplug it from the tv, and only watch it on the computer. I did not realize this would be the case and I don't think my son did either, but it's not the end of the world.

Second, you can only do this when the power is off.  If you are looking at the "No Video" screen in the Elgato software and unplug the HDMI cable, nothing will happen. Power cycle your XBox and you should now get your video signal!

Once connected, everything else works identically. My son watched me fire up Minecraft and almost get killed in about 3 seconds before he just grabbed the controller and rescued me. But the important part was that it still works identically to the XBox. Nothing about keyboard controls or anything weird.  You're just playing on the smaller screen.

Almost done. Do you want to play XBox Live?  More specifically, do you have one of those headset microphones that allows you to chat with your friends and basically narrate your game playing experience? My son's got the Turtle Beach XL1 which like much of this other stuff was a good entry level item to see whether he's going to stick with it. Something that might be common in the videogame world, that was completely bizarre to me, is that to get the chat working there's actually a special cable that comes off the headphones - and plugs into the XBox controller. Why? I have no idea. But if you want the other people playing the game to hear you, this is a necessary step.

Did I mention that my son's best friend has a similar setup, along with the recording material? When they learned that we'd gotten one for Christmas, the father told me, "You'll have to let me know if you get the chat working, we can't figure it out."

And there's the problem. How do you get that audio to go through the recorder? Turns out, you don't. Here's the word, straight from Elgato:

All gaming headsets we've encountered so far do not down-mix the live chat from the microphone to the audio output of the PS3 or Xbox 360. 

This means that Game Chat audio from the local gamer will not be recorded by Elgato Game Capture HD. 
You will still hear audio from other players during gameplay, and in your recording. 
You will still hear your voice during gameplay, but not in your recording.
That stinks. That might even be a deal breaker, depending on what you were hoping to accomplish. But! I wasn't done yet.  We've come this far and a father hates to disappoint his son.

Elgato points out that their Elgato - Game Capture HD version (you know, the more expensive one I chose not to get?) comes with a software option to do Live Commentary. I can't really say more about that because I don't have it, but perhaps that alone is enough to make you get the more expensive device, if you haven't already made your purchase. I'm not quite ready to go there.

I had one last option. It's not that hard to add voiceover / narration to videos, especially on a Mac. I tried it briefly with iMovie but didn't like the experience, so I ended up with Wondershare Video Editor. This software seems like the last piece of the puzzle.  My son will make his videos, then when he plays them back he can narrate what he did and why he did it. Might take him a little while to get used to that. And I'm not yet sure how that's going to work when he has other friends playing, because remember - the recorder will pick up *them*, but it won't pick up him.

Anyway, that's what we did to make it work. Hope it helps all you dads out there get the next generation of Stampy Longnoses producing their videos!

Saturday, November 15, 2014

Ready, Aim, Pop! How My Son Built His First iOS App


A few weeks ago my son, who is 8, figured out what I do for a living.  He discovered that I know how to put an app in the iOS App Store.

So naturally he asked, "If I make a game, could you make it so people could get my game on their phones?"  I said sure.

Thus began our father/son project for the next couple of weeks. We decided to go with the programming environment Game Salad, which had one serious advantage over the many others -- it could actually produce appstore-ready code, without really doing any serious programming.

My son had pitched an idea that went something like this : "What if these colored balls were falling down the screen and you had to tap all of them except the white one?"  I suggested, "What if instead of falling down, it was balloons going up the screen? And same thing, you have to tap them before they get to the top? The tapping could be like popping them."  He liked that idea, and we were off. Somewhere along the line the "don't tap the white ones" rule morphed into "the clouds are going to start getting in your way but if you tap on one you lose points".

He did all the graphics (ok, with a little help from his sisters) and played all versions of the game as we improved it.  Too fast.  Too slow.  Too many balloons, not enough balloons.  Balloons are too big, too small. Finally we got it just right.

Getting into the app store has a bunch of baggage that very much does not keep the attention of an excited 8yr old boy, like writing descriptions and filling out legal disclaimers and making screen shots in exactly the right size (seriously - if you're one pixel off, it won't accept you). Luckily I had experience with that, as noted, and cranked through the boring details while he was sleeping.

Try #1 we got rejected, because I'd clicked the "Made for Kids" option.  After all, I had no reason to think that it's not for kids, there's no violence or anything like that and it was in the 4+ age category.  But I hadn't considered ... the basic version of GameSalad that we're using puts in advertisements, and I do not control those. That's what got us rejected, the content of those ads.

Try #2 I turned off that option and held my breath. It takes about a week every time you submit an app for consideration so we were heading into two weeks since the last thing my son could actually help with, and I was afraid he was getting bored.

But, success! I got the note at maybe 9pm a few days ago, shortly after he'd gone to bed. So I went upstairs with the laptop, nudged him back awake, and said "Hey, read this for me."  He read, "The following app has been approved and the app status has changed to Ready for Sale....we got in? It's on the store?" I confirmed that it was indeed on the store and he immediately rolled into, "How many downloads do we have?"

I told him to be patient and go back to sleep. :)

I hope you get a chance to download the game. He asks me every morning what his numbers are (he calls them likes, and I haven't seen the need to tell him different :)).  If you think it's worth the extra time maybe throw him a rating/review. It's great to see how proud he is of his accomplishment, and I want to do everything I can to make this a positive experience for him. Maybe he'll want to make more!



Thursday, September 26, 2013

The Sum of Even Fibonacci Numbers

A co-worker showed me the following problem last night:

Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be:
1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.
If you jump too fast to your early CS101 knowledge you might bang out a recursive fibonacci function to get yourself started (using Ruby as an example):

def fib(n)
  return 0 if n==1
  return 1 if n==2
  return fib(n-1)+fib(n-2)
end

But that's not terribly efficient in this problem, where you'll end up calculating and recalculating the fibs all the way up to 4 million.

If you spot that the recursion will just do an absolute number on your stack management and want to get it out of there you can write the function without it:

def fib(n)

  prev = 0
  curr = 1
  (n - 1).times do
    curr, prev = prev+curr, curr
  end
  curr
end


But you're still going to calculate too many numbers and end up with a solution that is O(N^2) because every time you move to position N your function is going to recalculate everything from 1 to N-1.

Instead, don't abstract the function.  Treat it like the formula that it is, and write it in a single loop.  You are going to be calculating your variable N using the N(x) = N(x-1)+N(x-2) formula, until N>4000000.  Along the way, if N is even, add it to your growing sum:

first = 0
second = 1
sum = 0
while (second < 4000000) do
  sum += second if second.even?
  temp = second
  second = first + second
  first = temp
end
puts sum

Did you get 4613732?  You could clean up that code a bit and there's tricks to avoid that temp variable but I want to get to a better solution.  The one above calculates all the Fibonacci numbers less than 4 million, which means it goes through the loop 33 times.

We can do better.  If you look closely at the fibonacci sequence you may spot a pattern in the even numbers.  Did you notice that every 3rd number is the even one?  Which makes sense because once you bring even a single odd number into the pattern it's going to go the same way -- even plus odd equals odd, odd plus odd equals even.  So the Fibonacci sequence goes odd even odd odd even odd odd even odd where each even number is wrapped with odd numbers.

How can we use this?  Well this means if we know that fib(N) is even, we want to jump to fib(N+3) without worrying about the two in the middle.  So instead of looping over them why not just calculate them while we're here?  I'm going to use the sequence 5,8,13,21,34 as an example.  If I'm on 8, I want to calculate 34:

Given fib(x)=8
Given fib(x-1)=5
Calculate fib(x+1) = (8+5)
Calculate fib(x+2) = fib(x+1)+fib(x) = (8+5)+8  = (8*2 + 5) = fib(x)*2 + fib(x-1)
Calculate fib(x+3) = fib(x+2)+fib(x+1) = ((8+5)+8)+(8+5) = (3*8 + 2*5) = fib(x)*3 + fib(x-1)*2

Still with me?  So as long as I have fib(x) and fib(x-1) I can jump to fib(x+3) with some multiplication.

So now I can go through the loop like this:

x1 = 1

x  = 2
sum = 0
while (x < 4000000) do
      sum += x
      n = 3*x+2*x1
      x1 = 2*x+x1
      x = n
end
print "Your total is #{sum}"


Same result, only this time we bounced up to 4 million in just 10 hops.

Again, we could probably make it even more efficient than that by considering the actual cost of each math operation - I added some multiplications but now I'm also no longer testing for even numbers, so maybe it's a wash. I was mostly interested in showing that whole "even numbers every third so only jump by 3s and don't test for even" pattern.

I wanted to document this approach since I haven't seen it yet as one of the standard answers.  Enjoy.



Tuesday, September 17, 2013

Copy And Paste Between Two Devices

If you're a developer, this has probably happened more than once. You're working on two devices that are physically right next to each other, yes? Maybe, like me, you've got your iPad next to your laptop.  And inevitably you find a link on your laptop that you want on your iPad.  Blah.  What's the fastest way to get it from one to the other?

Sure you could mail it to yourself, or drop it in DropBox, or even maybe type it directly into the secondary device.  All too much bother.

Run an instant messaging program of some sort on both devices (like AIM).  IM the message to an understanding friend.  Now go over to your secondary device and fire up the conversation.  Your message, link included, will be there.  

Totally hacky but it's the fastest way I've yet found!

Friday, February 22, 2013

Array Sampling Without Repeating [Ruby]

I've often come across the problem of random sampling in situations where you don't want repeats.  For instance say you've got a list of the user's MP3 files and you are playing them randomly.  You've just played a song and you choose another random one.  It's easy to say "Don't pick the same one that you just picked."  And with a little work you could pick an N and say, "Don't repeat a song in the last N songs."

But you also don't want to say "Don't repeat any songs until all the songs are played", because if the user's got 500 songs in their library it'll be a long time before they hear their favorite song again.  What you really want is just something that says "Make it less likely to pick this song too too frequently."

So, here's the idea I finally came up with.  Say that you've got an array of files to work with, regardless of what is in them.  In Ruby you can just ask for file  = files.sample to get a random element out of the array.

Now what?  We go and do what we want with file, but now we want to assure that this is less likely to be called in the near future (and, preferably, absolutely guarantee that it is not called within the next N samples).

Start by snipping file out of filenames and moving it to the end of the array:

files <<= files.delete(file)

Try it:


(main)> files=["foo", "bar", "baz", "quux"]
=> ["foo", "bar", "baz", "quux"]
(main)> file = files.sample
=> "bar"
(main)> files <<= files.delete(file)
=> ["foo", "baz", "quux", "bar"]

So what?  The sample method is equally likely to pick any item in the array, right?

What if we tell it not to?  What if we tell it to only sample a portion of the array?

file = files[0..files.size>>2].sample

Here, we're saying to only get samples out of half the array.  So when a sample is chosen and moved to the back, we've established that there's no way this sample can be repeated until at least N/2 samples have been taken.

Depending on your N you might want to do something like N*0.90 or something (if N is a thousand maybe only 100 samples have to go by before it's ok to repeat).  

It's a little trick, but I think it's important.  I've got an app I'm working on that chooses random quotes, placing them on random images.  It bothers me when I know that I've got over 500 quotes in the database, and the user sees a repeated quote after 4 refreshes of the page.  So now they won't, now it'll take hundreds of refreshes before they see a repeat. Truthfully I'll probably switch that over to cap at 100.


Friday, August 31, 2012

RubyMotion : Gems Are Not Being Compiled / Built / Included

I was working on the most basic of apps, really nothing complicated at all, and trying to include BubbleWrap.  But the first time I tried to use anything (in this case, Device.screen.width) I was getting a name error - as if BW was not included.

I had  require 'bubble-wrap' in my Rakefile. I'd done a gem install bubble-wrap.  That wasn't it.  What appeared to be happening was that over in build/iPhoneSimulator-5.1-Development/objs there should have been a /Users/dmorin/.rvm/... directory where my required gems were getting copied, and that directory didn't exist.

I double checked everything, I ran "rake clean", I could not for the life of me make it include that directory.  I even created a brand new empty motion directory and included bubble-wrap in it so that this was literally the single line change I made from default -- and it compiled.  Go figure.

Finally, I found it.  I had been modifying some sample code that I found online, and it was this line:


app.files = Dir.glob(File.join(app.project_dir,'app/lib/**/*.rb'))|

Dir.glob(File.join(app.project_dir, 'app/**/*.rb'))

I'd seen something like that trick before, and it seemed like something I understood - basically saying that you're going to put some common code into a /lib subdirectory, so compile that first in order to make it available to your primary code.

But that's not quite accurate.  I think there was a mistake in the code that I copied, because what this does is to make app.files *only* point the files in your app/ and app/lib directory - completing removing any gems from the filepath.  You can check this with rake config - performing this command on a brand new directory will return all of your gem paths (whether it's .rvm or not), but doing so in the directory where the above line is included in the Rakefile?  Shows all my app/ code, but no gems.

In my case it turns out I don't need that line at all, so I've removed it.  Soon as I did that, my gems were included.  If you do need to manipulate app.files and the way things are included, you'll want to append or otherwise manipulate the existing list, not just replace it with a plain old equals!