Android Development Elliott Chenger Android Development Elliott Chenger

Android Studio Tip #003: Swap Intention Action

Today’s tip is going to be short and sweet. I was testing an internal library that I had little experience with a few days ago, when I noticed that for one method invocation I had reversed the inputs. This was partially to do with the lack of documentation and the fact that this legacy library lacked human readable parameter names, but I digress. The problem I had was that this method invocation was used enough that I didn’t want to swap all of the values by hand. 

Today’s tip is going to be short and sweet. I was testing an internal library that I had little experience with a few days ago, when I noticed that for one method invocation I had reversed the inputs. This was partially to do with the lack of documentation and the fact that this legacy library lacked human readable parameter names, but I digress. The problem I had was that this method invocation was used enough that I didn’t want to swap all of the values by hand.

After searching Android Studio for all its actions (⌘+⇧+A) it turns out that what I was looking for does exist. For methods with two parameters only, you can swap the parameters. This action is aptly named swap and though it doesn’t have a direct hot key, you are normally only a couple of keystrokes away from using it.

What is it?

The swap action is what the people at JetBrains consider an Intention Actions. You may be familiar with actions that show up as a light bulb icon next to your cursor, which happens under situations like missing imports, possible refactoring and potential bugs.

How do I use it?

Simply position your cursor anywhere inside your method invocation’s parentheses. And press (⌥+⏎), the Intention Actions drop down will appear and last on the list of the drop down should be swap ‘x’ and ‘y’ where x and y are the parameters you wish to swap.

I am not always swapping parameters so I can’t say this was a monumental find for me but as always knowing of its existence may save me more time in the future and hopefully it does you as well. What’s more important, or interesting, to note is that if you ever want to see what Intention Actions are available for your code you can always press (⌥+⏎) and find out.

P.S.

If you press (⌥+⏎) on string literals you can extract those strings directly to your Strings.xml. Which is great for refactoring legacy code with hardcoded strings.

Read More
Android Development Elliott Chenger Android Development Elliott Chenger

Android Studio Tip #002: Re-enable Test Artifact Switching

It's no doubt that Android Studio gets better with every version. Who doesn't love Instant Run? There is one thing I am sad to see change without mention. Test Artifacts are merged together by default now. 

It's no doubt that Android Studio gets better with every version. Who doesn't love Instant Run? There is one thing I am sad to see change without mention. Test Artifacts are merged together by default now.

If you aren't familiar with testing or test artifacts in Android, Google themselves have created a really nice starting point answering most of your questions. Also I love to note that I am a huge fan of the Arrange-Act-Assert pattern and TDD. I would definitely check them out if you are new to testing or programming in general.

I usually run my tests at the command line via the same build task that will be run on the server. This validate that what I am working on will in fact pass on the server. However, if I want to debug through my tests in IDE I usually like to isolate which test artifact I am running. The reason being is that tests run on the regular JVM are usually faster and it means I don’t have to have a device connected to run them.

So if you are like me chances are that you would like to not have your tests ran together out of the box. In order to get back the old Android Studio behavior navigate to the Experimental tab in Preferences.

Preferences>Build, Execution, Deployment>Build Tools>Gradle>Experimental

And simply toggle off the Enable all tests… box and apply. Voila! You now can switch between your Unit Tests and Android Instrumentation Tests.

TL;DR:

Read More
Android Development Elliott Chenger Android Development Elliott Chenger

Dex Redux

In October of 2014 a friend and past colleague of mine, Mustafa Ali, wrote a great Medium article to help solve a problem that many Android developers have encountered at one point in their career. The Dex method issue in short is a limit to the amount of executable methods allowed in Android's Dalvik Executable file (the one used to execute Android code). Shortly after writing his guide Google did the unthinkable... they released a support library. The library creates multiple dex files to help apps that are large get around the single dex file limit issue. Though this is a great solution for large apps Google suggests to use Proguard to strip your app of unused code or to reduce your dependency on libraries as a whole. The former is much easier than the latter. 

In October of 2014 a friend and past colleague of mine, Mustafa Ali, wrote a great Medium article to help solve a problem that many Android developers have encountered at one point in their career. The Dex method issue in short is a limit to the amount of executable methods allowed in Android's Dalvik Executable file (the one used to execute Android code). Shortly after writing his guide Google did the unthinkable... they released a support library. The library creates multiple dex files to help apps that are large get around the single dex file limit issue. Though this is a great solution for large apps Google suggests to use Proguard to strip your app of unused code or to reduce your dependency on libraries as a whole. The former is much easier than the latter.

I have to be totally transparent and say that I am not as familiar with the depth of the dexing process. I had initially planned on learning more about this and then writing up a large post however due to a family emergency I have not really had the time I wanted to devote to this. I am writing this in hopes to bring more exposure to the problem and maybe get some people who have a great understanding to help contribute to this post.

Finally The problem

So the other day while integrating two feature branches into our development branch. The following error occurred on our build server:

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':application:transformClassesWithDexForNormalDebug'.
com.android.build.api.transform.TransformException: com.android.ide.common.process.ProcessException: java.util.concurrent.ExecutionException: com.android.dex.DexException: Too many classes in --main-dex-list, main dex capacity exceeded

As I am not 100% familiar with what was going on I googled to see if this was something that others have been seeing. To my surprise there was only one result and that was a Google Issue Ticket. There isn't a ton of info in there, some people are suggesting that Google has broken a filter they have that creates the main-dex-list, which is a file that seems to be used to know which classes that should be included in the dex (I could be totally wrong about this).

Google acknowledged the issue, suggested a work around (which I have tried but haven't seen work) and opened another ticket to account for the actual solution. Because I couldn't get their solution to work I decided to test out a solution suggested by Alex Lipov, who was the one who created the Google Issue. Alex has a blog that talks through what he has found while working on this issue. Oddly enough he wrote this blog December of 2014 but didn't create the Google Tracker ticket till April 7th of 2016.

His updated solution is to access the CreateManifestKeepList class which is responsible for what gets kept for the dex. Then he modifies the accessibility of the class so it won't throw any exceptions while being modified. He basically makes the ImmutableMap mutable. It is a drastic approach but it works.

This is where the real fun starts. After utilizing his fix, I removed it so I could prove to myself that the fix is in fact real. When I removed his code from my Gradle build file...it still compiled without any issues. So I am interested in answering the following:

  1. What is the purpose of the main-dex-list?
  2. Why after removing the workaround am I not seeing the bug anymore?

Once I get back to real life I will pick back up and continue understanding the issue but I figured I would put this out and see if the community had any ideas what was going on. I would love to hear if you have had the same issue and how you solved it or if you have any extra info!

Read More
Android Development Elliott Chenger Android Development Elliott Chenger

Re: Chathead Basics

In Pierre-Yves Ricau's blog from 2013 he walks you through how to make a very basic version of Facebook's Chatheads, which if you haven't read is a great read and is yet another reason why I love Android. At the end of his blog he asked the question:

"Does this imply that Facebook Chatheads (or any application with SYSTEM_ALERT_WINDOW permission) is able to conduct keylogging and take screenshots at arbitrary time?"

It was a great question but after trying to explore more with adding views directly to the window I think I found another concern.

In Pierre-Yves Ricau's blog from 2013 he walks you through how to make a very basic version of Facebook's Chatheads, which if you haven't read is a great place to start and highlights yet another reason why I love Android. At the end of his blog he asked the question:

"Does this imply that Facebook Chatheads (or any application with SYSTEM_ALERT_WINDOW permission) is able to conduct keylogging and take screenshots at arbitrary time?"

It was a great question but after trying to explore more with adding views directly to the window I think I found another concern.

What was I trying to do:

In the advent of mobile phones I would have never thought that phones larger than 5 inches would be a market leading trend. However, here it is 2016 and I have a 6 inch Nexus 6p, which has been an amazing device despite it's size. So I set out to see if I could record any touch on the screen to see if I could start to build a heat map from my device. In doing so I made my phone un-usable. My solution was just a dirty proof of concept but I think what I proved is to be very careful adding things directly to the window.

My implementation:

As I said before right now my approach to this problem has been very basic. I took just a plain old View, made it the size of the screen and attached a touch listener to it. I let the touch listener return false, which by definition should have allowed other views to receive the touch. Most of the code is covered in Pierre-Yves' post so I won't go into much detail. What I found in practice was that I was now no longer able to interact with my screen at all.

touchView = new View(this);
WindowManager.LayoutParams params = new
         WindowManager.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
            ViewGroup.LayoutParams.MATCH_PARENT,
            WindowManager.LayoutParams.TYPE_PHONE,
            WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
            PixelFormat.TRANSLUCENT);

WindowManager windowManager = (WindowManager)getSystemService(WINDOW_SERVICE);
windowManager.addView(touchView,params);
touchView.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        return false;
    }
});

So it is apparent that any app with the SYSTEM_ALERT_WINDOW could render a user's phone useless or potentially could hijack the user's screen in a ransomware style attack. I am curious if anyone has found a way around this or has taken a different approach than me to do something similar. I don't want my idea to die off because though I love the Nexus 6P the one hand UX is absolutely horrible and I am trying to experiment with some different paradigms to see how they could make the experience better.

Note:

Since his post there is one slight change in how you ask for permssion to draw on the window, which I have covered in the following gist.

Read More