Thursday, April 28, 2016

A Peculiar Problem With Retrofit and Android-Priority-Jobqueue

I am currently developing a new(ish) app which uses several libraries. I did some research on loads of networking and job queue libraries and decided to use Retrofit from Square for networking and Android Priority Jobqueue from Path (Now Yigit).

Everything was going along very well. I was executing API calls inside Jobs using Retrofit...but one day data stopped getting to our servers.

I ran the application again, and it would execute several jobs successfully, so I thought perhaps it was a once off problem, but I was unfortunately wrong.

It happened again on my phone. So I tried a few other devices and they all exhibited similar outcomes.

I tried everything with the job queue. I removed all groups, and priorities and all persistence. I updated to later versions (I wasn't too keen on going to v2 as it is not released as of yet.) I added a logger and explicitly told the JobManager to start but it still stopped after a few jobs. I did some research on the load factor, thinking it might be something to do with that.
It wasn't.
After a few days of debugging, I found a piece of code, written in haste, that I believed to be causing the issue.


public class GenericResponseAdapter extends TypeAdapter<GenericResponse> {

    @Override
    public void write(JsonWriter jsonWriter, GenericResponse genericResponse) throws IOException {

    }

    @Override
    public GenericResponse read(JsonReader jsonReader) throws IOException {



        while(jsonReader.hasNext()){
            jsonReader.skipValue();
        }

        return new GenericResponse();
    }
}

I had created a response for those API calls that weren't anything in particular and had hoped that this would suffice that need. (I was coming very close to the 65k method limit imposed by dex and so I was trying to save methods and effort.)

The problem seems to be that an infinite loop in the
read()
method would, obviously, prevent the Generic Response from being returned.
Thus the thread that the job was being executed on never ended and the next job was never executed.

And so everything stopped uploading.

I know this may seem obvious to some but it took me almost two days to realise this is what was happening and to fix it. The fix will depend on your implementation.

I like to get my stupid errors out there...cause then I don't make them again.

Hope this helps someone!

Monday, July 1, 2013

ADB Whitelist Issue and Android 4.2.2

I managed to get my hands on a Galaxy S 4, which comes out of the box with 4.2.2. It was working great, but for some reason, possibly due to reflashing the device after a soft brick, every time I connected my laptop to my phone it would ask if i want to whitelist the laptop i am using. Every. Single. Time.

In Android 4.2.2 the team introduced a new security measure called ADB whitelisting. This allows the user to dictate whether or not a computer can run adb commands on the device. This is a good feature because adb can be rather dangerous, as it has slightly escalated permissions from a normal app running on a device. Some of the permissions adb has can be dangerous, such as rebooting the phone into recovery or the bootloaders etc.

So with this welcome feature, i had no issue with allowing my laptop on the device. They even included a tick box for 'Remember this computer'. However as i said, for some reason, after the reflash, the device would just not remember my laptop. This is extremely annoying as every time i want to test an app on my phone i have to allow the device to connect.

So i did a little research and found out that the keys of the laptops are stored in a location on the device, namely: /data/misc/adb/adb_keys

This little file was giving me endless hassles.

To solve my problem, i copied my laptops public adb key, located at ~/.android/adbkey.pub , onto my sdcard using 'adb push  ~/.android/adbkey.pub /storage/sdcard0/adb_keys'
Then I ran 'adb shell', giving me access to the phones filesystem.
I ran 'su', but i don't think this is actually necessary.
Finally i copied the adb_keys into '/data/misc/adb/' using cp, the exact command is 'cp /storage/sdcard0/adb_keys /data/misc/adb/adb_keys'
Then i restarted adb and boom! It works now.

If you can't use cp, you can try cat, the command will be slightly different, 'cat /storage/sdcard0/adb_keys > /data/misc/adb/adb_keys'

It's a very silly issue i had, but at least there is a work around.
Hope this helps.

Monday, March 18, 2013

Installing CM 10.1 on the HTC One X

This is not the hardest thing to do, however no one seems to have a complete tutorial. Everything seems half done and no one really explains what is needed and why you should do in case everything goes pear shaped.

Please be advised if this doesn't work, I cannot and will not be held responsible. Be a grown up and take responsibility for your own actions mkay. This will void your warranty and taking it to HTC or whoever may be futile. There is a chance of bricking your phone...I am not sure how, but thats like a standard thing to say.

Your phone will need to have a custom recovery installed in order to do this, you will also need to have a computer (Mac or PC) with adb installed on it. There are multiple ways to do this so please just  Google it, I will probably make a post on it one day, but today, today is not that day.

Moving along swiftly, you will also need to have an unlocked HTC One X. This means you went to http://www.htcdev.com/ , created an account and proceeded to unlock the bootloader of your phone. And please, I beg of you, charge your phone to at least 80%, just to be safe.

EDIT: I forgot to mention that you must be on the latest One X firmware - 4.1.1, you need to have your HBoot at later stage than 1.28.XXXX, which i can say for a fact is the case in 4.1.1, but I'm not sure about any other.

If at any stage you are confused as to what I mean, please stop, do not continue. I am using jargon for the specific reason that if you do not understand what I am saying you should probably not be trying this. It can mess up your phone and so you either need to know what you are doing, or be a really cocky person.

Moving along. Once your phone is ready and your computer is set. Go to the xda-developer link and download the build you desire. You can navigate to the 'official' get cm site or just download which ever build from those guys. Also there is a warning that you need to heed (and I do mean NEED).
There is a link to the 'vendor installer', download this too.
Also download the latest GApps version, otherwise no playstore for you!

All the links are on the first page of the above mentioned link, if you cant read then you should stop reading and stop trying this.

Finally we are at the fun/nerve-wracking part.

Simple Steps:

1. Make a nandroid backup

  • Reboot into recovery (power button and VOL down, then select recovery - supposedly you can get there by holding VOL up, but it doesn't always work for me)
  • Click 'backup/restore'
  • Select 'make backup now' or some such option
  • Wait for it to finish
  • Once it is finished reboot your phone (I know there is not a single tutorial with this line in it, but please just trust me)
  • Now copy the backup you just made off you phone, you only really need the boot.img, whichever is easiest. 
2. Install CM
  • While the phone is on, copy the CM build, the vendor installer and the GApps file onto the phones sdcard (use any means you feel like, i used 'adb push xxxx /storage/sdcard0"
  • Reboot into recovery again
  • Do a factory reset (if you don't, don't cry when you phone doesn't work)
  • Select 'Install Zip from Sdcard' 
  • Select 'Choose Zip from Sdcard'
  • Scroll down to the ROM and select it- should be named 'cm-10.1-[build date]-xxxx'
  • Select 'Yes' among the long list of 'No's'
  • Wait while it installs
  • Now select the vendor installer - it should be named 'cm-10.1-endeavoru-vendor-installer'
  • Wait for that to finish installing
  • Then install GApps in the same way
  • Once it is done, go back to the first screen and factory reset again. 
3. Flash New Kernel
  • This is not optional - if you don't do this your phone won't boot. 
  • Connect your phone to your computer and type 'adb reboot bootloader' in a terminal/command line
  • Then when you are in Fastboot mode (you will know this by the 'Fastboot' in red at the top) type 'fastboot flash boot /path/to/boot.img in a terminal/command line (please replace /path/to/ with where ever the boot.img is located on your computer)
  • That should take about 5s, then type 'fastboot erase cache' in a terminal/command line. 
  • Finally type 'fastboot reboot' and you should be done

So you should boot into CyanogenMod 10.1

If you have any issues then follow the next few steps - I promise you will love me for this.

To restore your backup:
  • Hold the power button and VOL down
  • Use the VOL buttons to navigate to 'Recovery' and select using power button
  • Once in recovery go to 'backup/restore' -select 'restore' and then select your backup
  • Once the backup is finished you need to type into a terminal or command line 'adb reboot bootloader'
  • This will take you to fastboot again.
  • Remember that boot.img i said you should take from your backup earlier in 1. - you need that now, type fastboot flash boot /path/to/backup/boot.img.
  • Now you can reboot and everything should be hunky dory. 


Hope this helps someone who is having issue with installation/recovery.

Also at the time of writing this, i have an annoying issue such that my notification bar doesn't work, the home button doesn't work and my lock screen will not display...so again, this is at your own risk. 

Enjoy!

EDIT:
Due to the issue's i was experiencing on CM, a took the advice of a friend of mine and decided to try out SlimBean - it seems to be based on CM but is tiny compared - the ROM i installed was about 100MB, and the Gapps was about 25MB as opposed to 190MB and 95MB respectively for the CM installation. It works better, haven't had any issues, has all the same mods, and fewer of the bugs...not sure how but hey. Even bluetooth pairing is working. Installation is pretty much the same as with CM, however if you are already on CM, just go to recovery, do a factory reset, install the ROM and 'adb reboot bootloader' then 'fastboot flash boot.img' (same as with CM - the boot.img from the SlimBean package), 'fastboot erase cache', and finally 'fastboot reboot' and you are done!  

Monday, February 18, 2013

git for OS X

If you are a programmer, I can guarantee you, you will or should want to use some sort of version control system. Version control is incredibly important, when I first started coding I thought just having a few backups every now and then on a random one of my flashdrives was sufficient, and truth be told, at that stage it was. Nothing I was doing was too hectic, nothing was drastically changing so I was content with a backup regardless of whether or not it was effective.

But lately, in the last 6months or so, I have realised I need something better than just somewhere to plonk my code when I've reached a certain goal. I needed something that would give me control over my code and allow me to: a) have a backup at all times, b) allow me to see what code was added removed and when, to locate bugs, and c) so other people I work with have access to my code without throwing a flashdrive at me or waiting for an email I forgot to send for the thirteenth time.

So I decided I needed some sort of VCS (version control system). I began looking around and was a little disappointed, nothing was very straight forward, everyone used a different system and there were so many systems. The most common ones in my experience are Subversion or SVN, Mercurial or Hg, Perforce, Bazaar and of course git.

NOTE: Please remember these 'systems' are just software, most of them do not have a GUI of any sorts and are almost exclusively command line tools. That said, there are plenty of GUI's available for each but require a separate download. (This confused me for a while, so don't get confused)

I decided to use git, after seeing companies like Google, Microsoft, Linux...and of course, the deciding factor, Android all use git, I presumed it would be a good system.

So I downloaded the install for my mac and tried to install it, but it didn't work. It has taken me till now to realise why and fix it. If you install XCode from the Appstore, along with the command line tools, a version of git will be installed, however, it is rather old and as of yet I have no idea how or if these install can be updated.

Now I will take you through installing git, including editing your bash_profile file on your computer to allow the use of git from where ever. This is something lacking in almost every single tutorial on git which really annoyed me greatly, and so I shan't do that to any one. Here we go:

NOTE: I am working on OS X version 10.8.2 on my MBP 15"

First we need git:
1.You can download it from git-scm.com
2.Double click on the .dmg file: It should look something like this...


 (If this is the first time installing or trying to install git, you can skip steps 3 and 4)

3.Once its unpacked copy the unisntall.sh script to your desktop



4.Open up your terminal (Either default Terminal or iTerm 2) and type sh, then drag the uninstall script onto the terminal and hit enter - follow the instructions that come up:




This script will uninstall any previous git instances on your computer, except the one installed by xcode

5. Once git is completely uninstall, run the install package, the .pkg file.


6. Click 'Continue' and follow the instructions to install git

7. YAY! Give yourself a big hug and pat on the back, you have successfully installed git. Now we need to make it easily callable from the command line. i.e. we don't want to have to find and navigate to  the file every time we want to use it

8. In your terminal type 'git' (no inverted comma's) and hit enter. If you see a whole bunch of commands come up, great, you are done. If not, continue on. It means that git successfully linked to the directory, for me it didn't do this for some reason.

NOTE: If you can use git as is, the next part is unnecessary, however it's useful if you ever install any other tools that aren't mapped, specifically when you build from source.

9. Navigate to your user profile, if you just opened the terminal you are probably already there, if not type, 'cd ~/' (no inverted comma's) and hit enter, you should now be where you need to be.

10. Now type 'nano .bash_profile' (no inverted comma's) and again hit enter

11. You will see a possibly empty, possibly not screen that looks a little like this:


As the name suggests this is your bash profile - most of the commands you call in the terminal are bash commands, and this little file directs your terminal to all your different programs that are accessed by the command line.

12. Now we need to add the path to git, it should be located at 'usr/local/git/bin', if we direct the terminal there we should be able to run git form anywhere. Type 'export PATH=${PATH}:/usr/local/git/bin' (no inverted comma's) into the space provided:


13. Press ctrl+x to exit, y to save and enter to confirm. Close the terminal and open it again, type 'git --version' (no inverted comma's) and you should see this:


The version of your git installation should be displayed.

Now you just have to learn to use git ;-). which is where the fun starts.

I will be writing another post on using git at a later stage. So keep posted :-)If anything isn't clear or work the way  I have described it, please let me know so I can edit the post and help others who may have similar issues.

Wednesday, February 13, 2013

Beanshell Scripting in Android

I needed to add a new feature to one of my apps. The ability to send the app a scripted set of instructions to execute when needed.
So to start I decided to try and get the Scripting part to work first, I will be adding push notifications at a later stage using GCM, but for now I just wanted to see if it would be possible to actually run a script in Android.

I had no idea where to start so I asked a Android programming buddy of mine, Toby Kurien (I hope he doesn't mind me mentioning him), and he suggested I look at Beanshell. Basically its Java in scripting form. And it looked perfect for what I needed. The only issue is I could find virtually zero documentation on how to include this in an Android project, it works in Java projects, and so I just presumed, based on Android using Java and Toby's suggestion, that it would work.

I set out to get it to work.

First things first, we need the library.
For a whole bunch of getting started documentation, you can check out the website.

I just downloaded the entire package, but I should imagine using just the core and classgen packages would be sufficient.

Anyway, onto the code.

Firstly you need to import the Interpreter like any other class and instantiate the Interpreter Object.

NOTE: I am using this in a Service, however it will work in an Activity or any other component I think.

//Imports the Interpreter
import bsh.Interpreter;

public class SomeService extends Service{

//Instantiates the interpreter object
Interpreter interpreter = new Interpreter();
private final IBinder mBinder = new SomeBinder();

 @Override
    public IBinder onBind(Intent arg0) {
        return mBinder;
    }

 @Override onCreate(){

    }
}

So now we have the Interpreter object and have imported it.
Now we can start using it.

I am just putting this in the onCreate() method, but you can run this in a method or a Thread or however you wish. I have also used it in two different ways, one is to direct it to a file which contains the script and the other is using a reader which has read the script. I also send an instance of the Service to the Interpreter which allows me run methods and send my application data or instructions from the script, which I think is vital for me


import bsh.Interpreter;

public class SomeService extends Service{

Interpreter interpreter = new Interpreter();
private final IBinder mBinder = new SomeBinder();
SomeService serv;

 @Override
    public IBinder onBind(Intent arg0) {
        return mBinder;
    }

 @Override onCreate(){
    serv = this;
    // Creates a File object with the location of the script basic.bsh 
    // (bsh - beanshell script)
    File file = new File(Environment.getExternalStorageDirectory() + "/script",
    "basic.bsh");
            try {
                // Creates a Reader which has read the file
                Reader reader = new FileReader(file);
                // Sets the variable myapp in the script to Service instance
                i.set("myapp", serv);
                //eval() is used to either run a String as a script or the reader
                i.eval(reader);
                //source() is used to run a script from the path name
                i.source(file.getAbsolutePath());
            //EvalError is from the Beanshell Interpreter, and the other two are the standard IO operation exceptions
            } catch (EvalError evalError) {
                evalError.printStackTrace();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
    }
   public void hello(String myName){
   Log.i("TAG","My name is: "+myName);
   }
}

I included a hello() method, which I will use in this example to demonstrate how to call it form within the script.

I must also mention, you can call Android classes into the script, I haven't used it extensively...actually I just used android logging, however, it works flawlessly. I will include an example in the script just for demonstration purposes.

My script will look something like this:

import android.util.Log;
myapp.hello("Sean");
Log.e("TAG","Hello from Beanshell");

And that's that. I use TextWrangler to create the script and then just load it onto the sdcard in the folder 'script'. You can of course decide on however you wish to put the script there, I am certain you could even include the scripts in the Android project itself, but this is what I did.

It's very simple and very effective. If anyone needs any help, please comment and I will get back to you as soon as I can. My next post will probably be on how to use GCM.

Wednesday, February 6, 2013

Timer Class and Alarm Manager


My app was working well. Perhaps not perfectly, but pretty close such that I was very happy with how it was going. My app had a Timer running every second, with a whole bunch of integers iterating and keeping time sensitive tasks in check.

For instance, I need a GPS location for my app, and i need it fairly often. I basically try to get a GPS fix every 5 min with a 2 min 'timeout', i.e. every 5 min it will turn the GPS on, if it cannot find a fix in 2 min it will turn off. If it does find a fix, it will turn off.

So obviously here i need two different integers, one iterating for the 5min counter and the other for the 2min counter, i realise i could use one counter and just have boolean for the state of GPS, but this is not all the counters do (I promise, there is always method to my madness).

My Timer looked something like this:



public class SomeService extends Service
{
public int fiveMinCounter = 0,twoMinCounter = 0;


 @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

 @Override
    public void onCreate(){
    Intent startActIntent = new Intent(context,Splash.class);

    startActPending = PendingIntent.getActivity(context, 0,startActIntent, 0);
    Notification noti = new NotificationCompat.Builder(
          context).setContentTitle(getResources().getString(R.string.app_name))
          .setSmallIcon(R.drawable.icon).setContentIntent(startAct)
          .setWhen(System.currentTimeMillis())
          .setContentText("Touch to open UI").getNotification();
    this.startForeground(1,noti);
    Timer timer  = new Timer();
    timer.schedule(new mTimerTask(),1000,1000);
    }  

public class mTimerTask extends TimerTask{

  @Override
     public void run(){
     //Run some code here
     fiveMinCounter++;
     twoMinCounter++;
     }
  }

}

So this was working fine, doing what I needed it to. However at one stage I started to notice that the GPS would hang sometimes...it would not turn off at all. After some investigation, I realised that not only was the GPS staying on, and subsequently annihilating my phones battery, but the counters had stopped increasing.
The Timer had stopped. Dead.

It no longer ran through the code I had specified. It stopped while the GPS was on, a most unfortunate time to stop.

I did a bit of digging and discovered a few other people who had similar issues with the Timer class. For some reason after an unspecified amount of time, supposedly when the phone goes into deep sleep, the Timer will stop. Even when it is embedded in a Service such as the one above, which is also a foreground service and should not be stopped even by the System. It didn't happen very often, but the sad truth is, if it happens once its dangerous. Especially a bug like this which can stall the GPS in the on state. A battery can literally drain in about 3 to 4 hours with the GPS on permanently.

I need a solution. Something that can do a similar thing, but will not be killed by the System randomly.

I found the Alarm Manager Class, which I have used previously for a task which needed to execute every 24 hours or so.

I altered my code to look like this:

public class SomeService extends Service
{
public int fiveMinCounter = 0,twoMinCounter = 0;
public static Receiver receiver;
public static long second = (long) 1000;
 @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

 @Override
    public void onCreate(){
    Intent startActIntent = new Intent(context,Splash.class);

    startActPending = PendingIntent.getActivity(context, 0,startActIntent, 0);
    Notification noti = new NotificationCompat.Builder(
          context).setContentTitle(getResources().getString(R.string.app_name))
          .setSmallIcon(R.drawable.icon).setContentIntent(startAct)
          .setWhen(System.currentTimeMillis())
          .setContentText("Touch to open UI").getNotification();
  
    this.startForeground(1,noti);
    
    if (receiver == null) {
         receiver = new Receiver();
         registerReceiver(receiver, new IntentFilter("KEEP_CONNECTION_ALIVE"));
        }
    AlarmManager alarmManager = (AlarmManager) context
                    .getSystemService(ALARM_SERVICE);
    Intent intent = new Intent("KEEP_CONNECTION_ALIVE");
    PendingIntent pendingInt = PendingIntent.getBroadcast(this, 2, intent, 
                    PendingIntent.FLAG_UPDATE_CURRENT);
    alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,System.currentTimeMillis(),
                    second, pendingInt);
    }  

public class Receiver extends BroadcastReceiver{

  @Override
     public void onReceive(Context context, Intent intent){
     //Run some code here
     fiveMinCounter++;
     twoMinCounter++;
     }
   }

}
That seems to have fixed the issue. There is another issue where there is a delay in the first execution of the BroadcastReceiver, but it seems to try and catch up executing the number of times it missed.

It runs as well now, and from what I have read about using AlarmManager.RTC_WAKEUP it will wake the phone up to run the code even if it is in deep sleep. So far I have noticed no negative impact on the battery life using this method.

I think the difference lies in the fact that the Timer Class is just that, a class where as the AlarmManager is a System service, so perhaps it is able to stay alive when the Timer would normally be killed.

Hope this helps someone who might have a similar issue to me.

Edit: I am trying to get all the code to be formatted and highlighted correctly, I am new to doing this in a blog, so give me a little break ;-)