Monday, February 24, 2014

ChromeCast and Aereo

Currently, Aereo does not implement ChromeCast support. As such, we are limited to the tab-casting functionality to stream Aereo to the ChromeCast.

There is a big problem with this... You can cast the tab and then put the video in fullscreen mode, but this prevents you from using the computer! If you switch programs, the fullscreen window is closed, and you're stuck watching your program in a tiny box.

I wanted the video to play at fullscreen in the background, allowing me to do other things while casting Aereo media to my TV.

To accomplish this, I wrote the following simple bookmarklet: Aereo Fullscreen

  1. Drag the link to your bookmarks. Or right click, copy link address, and add it as a bookmark via the Bookmark Manager (Ctrl + Shift + O).
  2. From Aereo, start playing the content you want to cast.
  3. Cast the tab to your ChromeCast, wait until you see the Aereo website on your TV.
  4. Click on the bookmarklet. Or start typing the bookmark name in the address bar. The bookmark will appear as a suggestion, and you can select it from there.

The bookmarklet will resize the flash object to appear as fullscreen within the tab. You can then minimize the window without fullscreen being disabled. Now carry on with your productive, multi-tasking life.

A couple notes: I haven't tested this on live TV, only recordings. When you use the bookmarklet, it does not keep your current place in the show! It starts you over from the beginning.

Aereo, please just add native support! :)

Tuesday, December 31, 2013

How to root the Sprint Galaxy S3 on Android 4.3 (SPH-L710)

My friend had a lot of issues rooting his Galaxy S3 after the 4.3 update, and asked me for help. The first successful method I found was explained in this YouTube video, but it's a little hard to follow. I wanted to document the steps here.

  1. This should be obvious, but backup anything important on your device! Also, if you wish to not void your warranty, do not proceed.
  2. Install Samsung Kies 3.
  3. Download the following 2 files:
    Odin v3.09, open the EXE.
  4. (Optional) If you've messed up the current installation, or prefer a fresh install, restore the factory 4.3 as follows:
    1. Turn off the device and remove the battery. Write down the HEX number on the sticker found underneath it.
    2. Start the device in Download mode (hold the power button, volume down, and home at the same time). Plug it into the computer.
    3. Open Samsung Kies 3, go to Tools > Firmware Upgrade and Install.
    4. Follow the instructions. When prompted, enter the Model number SPH-L710. The MEID number is the HEX value that you noted earlier.
    5. Grab some lunch, the download and install will take a while.
  5. Start the device in Download mode (hold the power button, volume DOWN, and home at the same time). Plug it into the computer.
  6. Launch the Odin v3.09 EXE.
  7. Ensure the first block under "ID:COM" shows something, like "COM0". This confirms that Odin can see the device.
  8. Click the AP button under Files. Select the philz_touch file.
  9. Uncheck "Auto Reboot".
  10. Click Start. This will install the PhilZ Touch recovery mod.
  11. When installation is complete, power down the device (if necessary). Start the device in Recovery mode (hold the power button, volume UP, and home at the same time).
  12. Select PhilZ Settings. Select the third option titled Re-Root System. Click Yes to confirm.
  13. After a few seconds, a message on the bottom will state the system has been rooted. Select Reboot System from the top of the home menu.
  14. When the phone reboots, complete Android setup and install SuperSU from the Play Store. If your phone is busy updating other apps, you can go to My Apps and click Cancel before installing SuperSU. Otherwise you'll have to wait for all of the apps to update.
  15. Open SuperSU. When prompted to install the binary, select to install it using the normal method.
  16. SuperSU should then ask you if you would like it to disable Knox. You definitely want to disable this, as it will try to remove root from your device. Click OK. If it fails, you'll need to look for other ways to disable it.
  17. Your device is now rooted! You can check by installing any root app, or a simple Root Checker app.
Refer to the video mentioned above if you would like a visual reference. Note that I have updated a few steps to use Kies 3 and a newer version of Odin.

I can't guarantee this will work forever, but I hope it helps somebody out. Let me know if any of my instructions need clarification.

Thursday, November 14, 2013

First-Gen (2012) Nexus 7 32 GB for $99

Many people saw this DEAL ALERT when GameStop liquidated their new Nexus 7 first-gens for $99. I know you saw it, because they sold out in quick fashion.

Staples was price matching, but they too quickly sold out. I was accidentally sold a 2013 Nexus 7 for $99, and had to painfully return it.

However today, a week after the sale, I noticed that the old model is still available at Staples online. Eureka! I returned to the store, and they placed an online order for me with the price match guarantee!

This is a great deal, especially considering Woot just sold out of the REFURBISHED ones at $160. Hope your Staples is as nice as mine. Good luck!

Monday, November 11, 2013

Check your Google Calendar with Tasker

I recently decided to play with Tasker for Android, and I've been having a blast with it! Here's one snippet some people may find helpful. It checks my Google Calendar and saves some info about today's schedule to a global variable.

To try it out, first you have to retrieve your Google Calendar private XML URL. It is found in your Google Calendar settings menu. Download this JavaScript file, and change the "username" variable to your Google username. Change the "key" variable to the "private-XXXX" portion of your private XML URL.

Save the updated JavaScript to your device, and create a new task like below.

The JavaScript action is under "Script", and Say is under "Misc". For the JavaScript "Libraries" attribute, click the search icon and select jQuery.


I use this as part of my morning profile. It's very flexible if you don't mind playing around with JavaScript. Let me know what you think!

Here's another link to the JavaScript file.

Thursday, September 12, 2013

PrimeFaces horizontal tree - expand all, collapse all

I'm working as a consultant on a project that is using PrimeFaces, namely the horizontal tree component.

It's a great tool, but took some custom javascript to make it fit our needs. As expected, the client requested an "Expand All" button. I was hoping I could use the PrimeFaces javascript object to call a pre-built function, but I didn't find any information on it.

I quickly threw this together. I won't do much explaining, because the code should explain itself. This should also work on the vertical tree, but you will have to modify the class names to match your tree's expand and collapse icons.

treeController.collapse = function() {
 // I wanted to keep the root expanded, but this part can be
 // removed or changed to select the tree div by ID
 var treeExcludingRoot = $(".ui-treenode-children-container").first();
 // find all of the minus icons, and trigger their onclick event
 $(".ui-tree-toggler.ui-icon-minus", treeExcludingRoot).click();

treeController.expand = function() {
 // this works the same way, but with the plus icon
 var treeExcludingRoot = $(".ui-treenode-children-container").first();
 $(".ui-tree-toggler.ui-icon-plus", treeExcludingRoot).click();

You could write it yourself, but why bother? Hope somebody gets to copy and paste it.

Thursday, June 13, 2013

Tomcat is ignoring changes to struts.xml, other config files and Java class files!

I was taking training on Struts 2, which involved importing some existing "Lab" projects into my Eclipse environment. Everything went smoothly the first time I ran the project, but after making updates and re-running the project, the server would not reflect any of my changes!

For hours, myself and a more senior developer banged our heads trying to figure out this problem. We installed a different version of Tomcat, cleaned the project and the working directory, cleared cache, etc. and nothing worked! From simple outputs to the console in class files, to adding or renaming actions in struts.xml, the project always executed as if it were the first run.

Per usual, the most troubling problem had the simplest solution. The person who originally created the project had the JRE imported from an unusual location. Upon import, I received errors saying java and javax could not be resolved. I hovered over an import statement, and used the "Fix project setup..." option to automatically add Eclipse's default JRE to the build path.

Though it properly added the JRE, it did not remove the old JRE location from the build path. Apparently this can cause some very mysterious behavior... As a last resort we checked the build path, and removed the bad JRE. Problem solved! Everything began functioning as expected.

Noobs using Eclipse Indigo: Right click on the project and select Build Path > Configure Build Path.... Under the Libraries tab, see if you have two JRE libraries. If so, delete the one with the little red X.

Sunday, March 3, 2013

Google Maps API for Business: Signing a URL in ColdFusion (Example)

This is one of those problems that quickly sucked up a majority of my day... I wanted to use ColdFusion to make HTTP geocoding requests to the Google Maps API using my employer's business license for the service. Try as I might, using ColdFusion's encryption functions to mimic the other examples kept returning garbage.

But then it dawned on me, the Java example could be mimicked to the T in ColdFusion, since it runs on the Java platform!

<cffunction name="signGoogleURL">  
      <cfargument name="url" />  
      <!--- I stored the key in the request scope, you can remove the default attribute --->   
      <cfargument name="key" default="#request.GoogleAPIs.mapsV3.cryptoKey#" />  
      <cfset var local = {} />  
      <cfif Find("", arguments.url) EQ 0>  
           <cfthrow message="Invalid Google URL." />  
      <!--- pull off the googleapis piece of the URL --->   
      <cfset local.urlToEncrypt =   
                Len(arguments.url)-(Find("", arguments.url)+14)  
      <!--- this is the part we encrypt and pass as signature --->   
      <cfset local.msg_digest = cfhmac(local.urlToEncrypt, webSafeToBase64(arguments.key)) />  
      <cfreturn arguments.url & "&signature="   
           & Base64ToWebSafe(local.msg_digest) />  
 <!--- this function mimmicks the code in signRequest from the Java example --->  
 <cffunction name="CFHMAC" output="false">  
   <cfargument name="signMsg" type="string" required="true" />  
   <cfargument name="signKey" type="string" required="true" />  
   <cfset var local = {} />  
   <!--- get the key in binary --->  
   <cfset local.key = BinaryDecode(arguments.signKey, "base64") />  
   <!--- initialize the crypto object with the key and algorithm --->  
   <cfset local.keySpec = createObject("java", "javax.crypto.spec.SecretKeySpec").init(local.key, "HmacSHA1") />  
   <cfset local.mac = createObject("java", "javax.crypto.Mac").getInstance("HmacSHA1") />  
   <cfset local.mac.init(local.keySpec) />  
   <!--- pass the message's bytes into the crypto object. we return it in Base64 --->  
   <cfreturn ToBase64(  
        ) />  
 <!--- simple switch from google's webSafe format to the actual Base64, in the Java example this is done in UrlSigner() --->   
 <cffunction name="webSafeToBase64">  
      <cfargument name="val" />  
      <cfset arguments.val = replace(  
                replace(arguments.val, "-", "+", "ALL")  
           , "_", "/", "ALL") />  
      <cfreturn arguments.val />  
 <!--- switch back to google's format, before adding to URL. In the Java example this is done at the bottom of signRequest() --->  
 <cffunction name="Base64ToWebSafe">  
      <cfargument name="val" />  
      <cfset arguments.val = replace(  
                replace(arguments.val, "+", "-", "ALL")  
           , "/", "_", "ALL") />  
      <cfreturn arguments.val />  
I chose to include these in a component, and call it as follows:
<cfset variables.requestURL = Maps.signGoogleUrl([url], [API CryptoKey]) />  
The url variable is the full googleapis address including the protocol, and URL parameters like the required client variable. You can then pass that into a cfhttp call and your requests will be validated by your client and cryptoKey values! Hope this saves somebody some time, let me know if you find it useful!