Remote debugging an embedded WebView in Android

And there I was, thinking that I was done with AzureStorageExplorer for Android v1.0.0. But, nope. In my last round of testing, I couldn’t even login using my work account. The Sign In button didn’t do anything. I went back a few versions to see if the Android update for WebView could have done something to break it. That wasn’t it. The OAuth client library I was using had the recommended code for enabling Javascript in the WebView client so I knew that wasn’t it. I was able to login through the Azure OAuth flow using my personal Azure account. So, I knew there was something about the enterprise account login screen, which could have changed recently that ended up breaking the authentication in the app. It turns out that it did. Read on to know how I found out.

The first step was to prove that something was indeed broken in the login screen for enterprise accounts in Azure in embedded WebViews. To do this, I looked up Chrome’s remote debugging options and found this page describing how to remotely debug WebViews in mobile apps. So, I enabled the setting as recommended by Google, which required adding this piece of code in my activity’s onCreate(Bundle) method.


if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
WebView.setWebContentsDebuggingEnabled(true);
}

I ran the app, launched Chrome’s Developer Tools, and connected to the app’s WebView. This is what I found..

2016-12-26_09-49-21

That last error in the console is what was logged when I pressed the Sign In button after entering my work account credentials for Azure. It turns out that the page’s JS now has code to store something in the browser’s localStorage. The reason this isn’t a problem, if you were logging into Azure through a desktop or even a mobile browser, is because localStorage is enabled for every site by default in the non-embedded browser view. But for a WebView in an Android app you need to explicitly enable the DOM storage, just like you need to enable JS through the WebSettings class.

After finding this, it was easy to know where I needed to make the fix. So, I set out to fork the source repo of the OAuth library I was using, made the necessary changes and created a pull request. If you are using the same library and have run into this issue, you could clone my repo and build the project to produce the patched .jar (or an .aar), which you can use in your project directly until the author of the library can get to my pull request (if at all!).

Advertisements
Image

Unofficial Tesla Android client for controlling your Model S

Tesla Motors

Tesla Motors

GitHub link: https://github.com/praneetloke/MyTesla

But there’s already an official app from Tesla for the iOS and Android, then why this? Because I wanted to and besides there aren’t any open source Android clients. There are couple of Ruby clients and a node.js client. The node.js client is particularly of interest to me since it has visual examples of each API it supports. The telemetry streaming API is my favorite. If you remember, that’s what Tesla used to debunk the NY Times reporter for his fake report on the Model S sometime ago.

Anyway, back to the MyTesla client. You can fork it, download it, modify it, do whatever you want with it. This client is unstable, unofficial, and most importantly, unverified (since I don’t own a Tesla Model S, unfortunately). So please use this with caution. If you find bugs, please raise an issue in my repo or you can fork-fix-pull. If you are able to help with its stabilization by testing this on your Tesla Model S, please let me know. You can hit me up on G+ or LinkedIn.

There are 3 REST API clients for your use in this project. LoginClient, VehicleStatusClient and VehicleCommandClient. I have already pulled in these 3 REST interfaces into a custom Android Application class called TeslaApplication. I did this to remove any dependency from consumers having to pull in AndroidAnnotations as well. On a side note, you should check out AndroidAnnotations. It is awesome! Anyway, in your project, you can simply extend the TeslaApplication and be on your way. You don’t need to put anything in it. I have not actually tested to see if such an extension is actually required if you were to reference this project but be my guest.

I have also made a LoginActivity which has a boilerplate login form which you can present to your users. It handles submitting the email and password to the API and inspecting the response to see if it was successful. I actually plan to change this to a login dialog instead or perhaps have both since a dialog only needs a layout. Then you can choose either depending on your needs. When login fails, it currently doesn’t do anything. I am yet to work on that. I also need to work on some cookie transfer from LoginClient to the other two clients because from what I saw in the AndroidAnnotations sources, there doesn’t seem to be a unified storage for cookies acquired by REST interfaces.

When you look at the library I made, you will notice that I didn’t use primitives. That’s because of the nature of the API itself. It’s unofficial and there are unconfirmed properties whose values are unknown and sometimes null. So this being Java, I couldn’t use primitives in some cases. For those that had confirmed values I could have used primitives but I felt I needed to be consistent rather than have you guess what you’ll be using when you inspect an object. And yes, I am talking about primitives and objects because I actually went ahead and created model classes (POJOs) for all of the endpoints. This should make interaction way easier. It uses Gson for type conversion. I chose Gson over Jackson mapper for its lightweight and performance. Gson doesn’t have all of the features Jackson has but it does the job, fast too.

If you have watched this clip of the guy issuing commands to a Tesla Model S, you’ll be at least half as excited as I was to find a REST client and play with it if you have a Tesla Model S. Of course, you would more likely already have the official Tesla app. But if you are into programming and diving into things on your own, this is for you. I wish my VW CC was capable of something like this.

Credits

  • Tim Dorr (and many others that commented on each API endpoint in the Apiary blueprint) for his excellent Apiary documentation based on his findings. He has implemented his very own ruby implementation of the API here.
  • AndroidAnnotations
  • Spring Android

Other clients

  • node.js
  • Ruby. For Ruby, there’s also the one from Tim Dorr himself.

Ford TDK

Guess what?? Last week, I got the Ford TDK which I won from participating in an app idea contest held by Ford. Here’re the pictures!

TDK power cord and instructions manual.

Instructions and power cord for the Ford/Lincoln TDK 3.0

Ford/Lincoln TDK

Ford/Lincoln TDK

[UPDATE] Weird problem with GridView OnScrollListener and list navigation listener

It turns out that the problem was much simpler than I had originally thought.

The Problem

It was actually two fold. The scroll listener for some reason fires the change event as soon as the gridview’s adapter is set even when there are no items in it. My scroll listener was something like this:

private AbsListView.OnScrollListener mOnScrollListener = new AbsListView.OnScrollListener({
  @Override
  public void onScrollStateChanged (AbsListView view, int scrollState) {}

  @Override
  public void onScroll (AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
    if ((firstVisibleItem + lastVisibleItem) >= totalItemCount && !mAsyncTasksPending) {
      loadMore();
    }
  }
});

The above code ended up calling the loadMore(); even before the gridview’s adapter was loaded with the first page results from the service. That ended up making two requests wastefully. The second problem is because of how I had declared the loadMore(); method. I use AndroidAnnotations to reduce boilerplate code. I annotated loadMore(); with @Background to execute the service request in a background thread to prevent the UI from locking up. But, I didn’t need to do this since I was already taking care that the service request be executed in a background thread using another library called async-http, which by the way is freaking awesome! My guess is, when I set the method to be executed in a background thread it was holding up the gridview’s listener thread somehow which caused the events to accumulate in the call stack. This would probably explain why when I paused the activity and resumed it, it would function normally and the moment I scrolled it and caused it to call loadMore() it would freeze again and none of the callbacks would fire.

A little more than the solution

First, what I ended up doing was removing the redundant @Background annotation from loadMore();. Then, I realized that my activity was a little bloated. So, I created a fragment and shoved the gridview, and managing its adapter into the fragment. I was then able to keep my activity lean. By doing so, I have also opened up the possibility of introducing additional fragments to handle different views if necessary in the future which makes this all the more easy to manage without bloating my activity.

Next, I updated the gridview’s onScroll callback. It was still being called as soon as the adapter was set in the gridview. Initially, the adapter is empty and I don’t want it to call loadMore(); when the first page results haven’t been filled in the adapter yet. Loading the first page is handled through the list navigation listener since that sets the currently selected item for which I then go and fetch the list of images. So now, this is how my updated OnScrollListener looks.

private AbsListView.OnScrollListener mOnScrollListener = new AbsListView.OnScrollListener({
  @Override
  public void onScrollStateChanged (AbsListView view, int scrollState) {}

  @Override
  public void onScroll (AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
    //only load more if the visibleItemCount is > 0, and the user has reached the last row of visible items
    if (visibleItemCount > 0 && ((firstVisibleItem + lastVisibleItem) >= totalItemCount) && !mAsyncTasksPending) {
      loadMore();
    }
  }
});

Why I dumped my custom image manipulation code from Transitions

After spending several nights and weekends implementing and testing the code I had written for image resizing, it still didn’t work for some popular devices. This was unacceptable. As I gave this a lot of thought, I realized that I was doing it wrong. No. Not just the code. My effort. As much as the engineer that I am, I wanted to make it work. I was very interested in solving it. I wanted to own it much like every other coding problem I try to solve. But, as an Engineer, I also don’t want to “reinvent the wheel” if I am not going to improve it. I certainly wasn’t improving it.

So, for the upcoming release for Transitions, I trashed all of the code I wrote for image manipulation and simply popped in Square’s Picasso library. Why? Because, it’s simply that much less code I need to change/maintain. It is so much easier to look at my code now with all the complex bitmap decoding stuff gone. I’ll let the experts handle that. And, now I can concentrate what really matters. Putting features together. I am still innovating with Transitions. I added a feature to my open source library CustomPreferences which allows you to load a list preference from the database dynamically. It’s very useful when you let your users build their own database of things and you want to allow them to pick from that list. Currently, you can’t do this with the preference classes out-of-the-box. But, you can, with CustomPreferences.

 

 

iOS Style Scroller For PhoneGap App

I have moved the files to GitHub at https://github.com/praneetloke/SpinningWheel-Wrapper

I am going to show you the extensions I made to the spinningwheel script created by the developer of the popular iScroll script. The spinningwheel script by Matteo works great just out-of-the-box. It’s much better than mobiscroll. Spinningwheel allows you to add slots of custom data which means if you are about to use spinningwheel for a date picker then you have to write your own logic for handling the days/months logic and then there’s the leap year calculation for February. But working with spinningwheel was easy and interesting. Matteo’s code is always organized as you can see from the source of his iScroll and SwipeView scripts. It was just a matter of writing down what extensions I wanted to make to his script. So, I first started out by realizing that I wanted a wrapper around the spinningwheel; that’s where the second file in the attachments comes to use. Most importantly his scripts are always written in regular javascript and always has a destroy method (which is very useful when you want to manage memory). Writing in regular javascript means no external dependencies. Following the same guidelines I too made the extensions in regular javascript and also the new events you can subscribe to in the spinningwheel are written in regular javascript. Another advantage of using spinningwheel over mobiscroll is spinningwheel uses translate3d for the transitions which means it will look and work awesome on iOS devices and even on higher end Android devices (phones and tablets). Oh and another one again is that since spinningwheel is written in regular javascript it easy for you to make extensions to it based on your needs unlike mobiscroll which relies of jQuery selectors heavily which means if you are not using jQuery, good luck!

The ScrollWheel class I wrote allows you to use the SpinningWheel instance as a singleton object. You can create an instance of ScrollWheel and pass in parameters like ‘date’, ‘time’ or ‘custom’ (if you want to use custom slots). Most of you would want to use the date and time presets that I created. The custom presets allow you to simply bind a click listener to text input and show the spinning wheel without having to do any extra work.

As you will see in the ScrollWheel.custom file, I have set the cancel action to call the post callback (which you would have passed when an instance of ScrollWheel was created) immediately and a null value for the results. In your post callback be sure to add a check for the results array so you don’t accidentally update the existing value in the text box (if any) to null. You can see what I have done with my post callback in ScrollWheel_Init.

The HTML element that you need to have to actually show the spinningwheel is pretty simple. Just use something like this (or exactly):

<input id=”timePicker” type=”text” readonly=”readonly” onfocus=”preventFocus(this)” onclick=”showTimePicker(event, this.id, this.value);”/>

or you can modify the showTimePicker function to take just the event object as a parameter and modify the click handler in the element to:

<input id=”timePicker” type=”text” readonly=”readonly” onfocus=”preventFocus(this)” onclick=”showTimePicker(event);”/>

Or you could alternatively ‘bind’ to the click event using jQuery or Zepto as well. I will not explain the logic of updateDates since it is pretty straight forward. In spinningwheel.js, you will find that I have added a new event handler that you can set via an instance of ScrollWheel (or directly via SpinningWheel) called scrollEndAction. This is what you need to set if you want to subscribe to the scrollEnd event and have a handler invoked every time the user stops scrolling a slot.

A snippet of the handleEvent function in spinninwheel where I added the invocation of the scrollEndAction

else if (e.type == ‘touchend’) {

if (e.currentTarget.id == ‘sw-cancel’ || e.currentTarget.id == ‘sw-done’) {

this.tapUp(e);

} else if (e.currentTarget.id == ‘sw-frame’) {

this.scrollEnd(e);

//console.log(“calling scroll end action”);

setTimeout($.proxy(this.scrollEndAction(this.activeSlot), this), 100);

var self = this;

setTimeout(function () {self.scrollEndAction.apply(this, [self.activeSlot]);}, 100);

}

}

There are two new public functions I have added to the spinningwheel.js, called showSlotValuesAfter and hideSlotValuesAfter. These functions will allow you to pass the slot index (0 based), the last key of the json object that the slot holds as values, and the number of values you want to show/hide after that last key. The reason for these is to help with hiding the dates that don’t apply for a particular month and then showing them again when they are applicable. Look at updateDates to understand how this is done. I have also made sure that when you call on these functions the corresponding slot’s max scroll boundary is updated so that it doesn’t allow you to scroll over the ‘hidden’ values. Find out why I call them ‘hidden’ values. 

The good thing about the wrapper I have written is that it checks if an instance of a ScrollWheel is already open and if so it won’t allow you to open another one. This was the only problem with spinningwheel out-of-the-box. SpinningWheel is a global instance and you have to manage it. If you open too many instances at the same time you are likely to chew up memory from the browser and can see significant impact to the performance of the page and even states and values will be corrupted. This is why I wrote the wrapper to make sure that I take care of this.

There is no technical reason for me to name the wrapper as ScrollWheel so you can change the name of the class to whatever you like. Just remember to retain the names and the original license at the top of the files. Although I claim no responsibility for the stability of these extensions and no support for them, I do know that they work because I use them and you can ask me for help as long as you don’t blame me for anything after all you downloaded them, I did not force you to.

A word of caution about spinningwheel’s goal. It is to be used with webkit based browsers. It was created to be used with iOS and Android phones as they implement the WebKit framework and also it is original intended to be used with touch enabled WebKit platforms which means it will not work with desktop browsers (Chrome, Safari, or Opera) out-of-the-box but there’s good news, download the touché framework I blogged about last week and it should work like a charm. I may look into porting this for the WP7 but not yet. I’ll tackle that when I get there but if you do be sure to let me know. It’ll save me some time 🙂

Be sure to ask me if you don’t understand the sources. Just don’t be a duck about it. That’s it for now. Enjoy your new spinningwheel!

Opening Garage Door Using An Android Phone

If you haven’t seen videos of people using their iPhone or Android to open their garage, you are missing out on some excitement. The way it works is there is a bluetooth module which is a transceiver and the mobile device talks to it using SPP. Since iPhone and Android support bluetooth communication using this protocol, you will see videos on youtube with mostly these two devices. Sadly, WP7 doesn’t seem to support SPP as of now or at least to my knowledge it doesn’t seem to have an API for developers to use like the other two do. If any of you know otherwise please let me know.

I got the DaisyWorks bluetooth board and connected it to my garage door wall control switch to simulate the on/off pulse the door switch sends to the opener. I got open source app that DaisyWorks published on github and added some pretty nifty features to it like, Text-to-Speech and Voice Recognition. I have also added two useful features that my car has Coming Home, Leaving Home. Basically, I tell the app at what time I leave home for work and come back home from work and it switches the bluetooth on for an hour given that window and automatically switches it back off after that window to save the phone’s battery.

The good thing about Android phones are that they are actually built on an Open Accessory Development platform. You can read about it here. There are several online resources that can help you build what you need with little programming knowledge and some electrical knowledge as well. Most tutorials, articles do have explanation about the electrical part which is out of scope for this article though (not that I am good at it anyway).

So here’s a video of what I have done with mine. Be sure to leave comments about any questions you may have and thank you for reading this article! Also, look for updates to this application from me.