This short post will be about creating a back-door to your app, giving you the option to provide more information or actions than you want end users to have. This will be using the Secret Code feature.
I came across some articles with list of codes in order to access some phone’s data (i.e. Camera’s firmware spec.), run some tests (i.e. Vibration test) or even perform actions such as reset to factory settings. Some examples can be found here and here and even as an app that indexes all that information.
Create your own
Creating your own secret doorway for your app can help you get more information from users of your app in a time of need. Getting crash reports from end users can be done by several services such as ACRA or BugSense, but how about errors that are not crashes? How many times did your Mom/Spouse/Friend/Mailman showed you their phone, running your app, and said something like: “Why do I see duplicates on the list here?! Why can’t I sync??”. You probably can’t do anything without debugging the app or at least take a look at the app’s SharedPrefs/SQLiteDB. Using a backdoor can help you get more internal information that will help you find the cause for the problem, no computer is necessary!
Another cool thing is providing more actions to do with your app. You want to keep the app clean for your users, but you might want more power to yourself. You can tweak your internal settings, whether for testing purposes or just to try out new features on your everyday use. Not needing to compile a new version after each change of internal setting, can help a lot in the task of identifying tricky problems.
Examples
Before learning how you can create your own secret code to do some cool stuff, let’s review some use cases that you can use it for:
Diagnose information – Presenting technical details of you app, such as generated UUID that can be used to find relevant server data.
Send internal data outside – You can dump app information, such as the SharedPrefs/DB data, and send it to you via email. Since this code runs on the same process as your app – you have access to everything!
Change settings – You can change the internal settings of your app. Showing more debug logs, communicating with a different server or even change the sorting order of the list you present the user. Anything that can help you understand more about the current situation of the app.
Demo mode – Need to show your app to investors? Showoff to your Friends? You can create shortcuts to some app features that are relatively difficult to simulate. For example: Notification that triggers every morning or when the phone is idle for more than 30mins. Maybe a SMS/phone-call triggered action, QR code scan or a sensor’s incoming data. You can create a demo screen to start everything you want to show on the app, and with sample data to make a neat presentation.
How?
Let’s see how to create one of our own secret code:
That’s what you put on your manifest. Looks simple right? All we do is provide a listener to a secret code, defined in a <data> tag as the “android:host” attribute, and declare a receiver for it. On the receiver, we can just run some code, open an Activity, run a Service etc. Here’s an example of a receiver that starts a new Activity:
public class DiagnoserReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
if ("android.provider.Telephony.SECRET_CODE".equals(intent.getAction())) {
Intent i = new Intent(Intent.ACTION_MAIN);
i.setClass(context, Diagnoser.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
}
}
}
We create an intent with the Activity class, Diagnoser, and start it. That activity will run on the same process as our app, allowing us to access all the data that our app has, using all the permissions that our app has been granted with.
Use it
To start our diagnose screen, all you need to do is go to the phone’s stock dialer (third party dialers not always work with secret codes) and dial the secret code you defined in the “android:host” attribute on the manifest, in the following pattern: “*#*#<secret-code>#*#*. In our example, you’ll need to dial *#*#111222#*#*, the DiagnoserReceiver will receive the intent and start the Diagnoser activity.
That’s it. I hope this post helped you get more from your app. If you have more ideas for use cases for this feature – write them on the comments to help us all exploit this nice feature.
When I wrote Any.DO’s sync system, about 18 months ago, I wanted to use the built in AccountManager API to authenticate and store the users’ credentials. When I used it to access Google accounts it seems a pretty simple experience, so I thought I should do that for Any.DO as well. It also goes very well with a sync mechanism (using a SyncAdapter), making it the perfect solution. The problem – no good documentation was out there. The developers community didn’t have much experience with that back then, and since we didn’t have much time to figure out issues that could arise from this “No man’s land”, a decision was made to use other methods.
But times have changed..
I recently studied that feature again for a project I’m working on, and saw there’s a huge improvement with the knowledge about it. Besides the better documentation on the Android.com site, more and more tutorials went out to the wild, feeding us with knowledge about the mysteries of the notorious Account Manager. Some tales were told about the road to create your own account. I read pretty much all of them.
But..they all still miss something.
I didn’t feel that I actually know everything I wanted to know about the process, and some parts weren’t clear enough. So I did what I usually do when I want to know everything about something – investigate it “Jack Bauer style”! This post is the in-depth conclusion of my journey, with all the quirks and features that this service provides and I thought was important enough to find out. There will be a followup post about Sync Adapters as well, so I recommend RSS/Twitter subscribing to be notified…if you’re into this kind of stuff. I’ve been pretty thorough learning all those features, not just the basic stuff as all other tutorials did, but if I forgot something – please let me know by commenting this post.
Why Account Manager?
Why really?
Why not just write a simple sign-in form, implement a submit button that post the info to the server and return an auth token? The reason for that is the extra features you get and in the small details that you don’t always cover. All those “corners” that developers often miss when they need their users to sign-in, or dismiss by saying “This will happen to 1 out of 100000 users! It’s nothing!”. What happens if the user changes the password on another client? Has an expired auth-token? Runs a background service that doesn’t have a UI the user can interact with? Wants the convenience of logging-in once and get automatically authenticated on all account-related app (like all Google’s apps do)?
Reading this article will probably make you think it’s complicated stuff, but it’s not! Using the Account Manager actually simplifies the authentication process for most cases, and since I’m already giving you a working code sample – why not use it
So, to recap the benefits:
Pros: Standard way to authenticate users. Simplifies the process for the developer. Handles access-denied scenarios for you. Can handle multiple token types for a single account (e.g. Read-only vs. Full-access). Easily shares auth-tokens between apps. Great support for background processes such as SyncAdapters. Plus, you get a cool entry for your account type on the phone’s settings:
Look mom, my name is on the settings screen!
Cons: Requires learning it. But hey, that’s what you’re here for, isn’t it?
The steps we’ll performs to get this done:
Creating our Authenticator – the brain behind this operation
Creating the Activities – in those the user will enter his credentials
Creating the Service – through it we can communicate with the authenticator
But first, some definitions.
Authenti..what?
Lets start with the basics – these are the main parts here:
Authentication Token (auth-token) – A temporary access token (or security-token) given by the server. The user needs to identify to get such token and attach it to every request he sends to the server. On this post I’ll use OAuth2 as the authentication standard, since it’s the most popular method there is.
Your authenticating server – The server that will manage all the users that use your product. It will generate an auth-token for any user that logs in and verify it for every request the user makes on your server. The auth-token can be time limited and expire after a period of time.
AccountManager – Managing all the accounts on the device and pretty much running the show. Apps can request auth-tokens from it and that’s its job to get it done. Whether it means it needs to open a new “Sign-in”/”Create account” activity, or retrieving a stored auth-token that was previously requested, the AccountManager knows who to call and what to do on each scenario to get the job done.
AccountAuthenticator - A module to handle a specific account type. The AccountManager find the appropriate AccountAuthenticator talks with it to perform all the actions on the account type. The AccountAuthenticator knows which activity to show the user for entering his credentials and where to find any stored auth-token that the server has returned previously. This can be common to many different services under a single account type. For instance, Google’s authenticator on Android is authenticating Google Mail service (Gmail) along with other Google services such as Google Calendar and Google Drive.
AccountAuthenticatorActivity – Base class for the “sign-in/create account” activity to be called by the authenticator when the user needs to identify himself. The activity is in charge of the sign-in or account creation process against the server and return an auth-token back to the calling authenticator.
Whenever your app needs an auth-token, it only talks with one method, the AccountManager#getAuthToken(). The AccountManager will take it from there and jump through hoops to get you that token. Here’s a nice diagram of the process from Google’s documentation:
It may look a little cumbersome, but it’s fairly simple. I’ll explain the common case where we log-in to an account for the first time on the device.
First time logging-in
The app asks the AccountManager for an auth-token.
The AccountManager asks the relevant AccountAuthenticator if it has a token for us.
Since it has none (there’s no logged-in user), it show us aAccountAuthenticatorActivity that will allow the user to log-in.
The user logs-in and auth-token is returned from the server.
The auth-token is stored for future use in the AccountManager.
The app gets the auth-token it requested
Everyone’s happy!
In case the user has already logged-in, we would get the auth-token back already on the second step. You can read more about authenticating using OAuth2 here.
Now that we know the basics, let’s see how to create our own account type authenticator.
Creating our Authenticator
As written earlier, the Account Authenticator is the one that gets addressed by the AccountManager to fulfill all account relevant tasks: Getting stored auth-token, presenting the account log-in screen and handling the user authentication against the server.
Creating our own Authenticator requires extending AbstractAccountAuthenticator and implementing some methods. Let’s focus for now on the 2 main methods:
addAccount
Called when the user wants to log-in and add a new account to the device.
We need to return a Bundle with the Intent to start our AccountAuthenticatorActivity (explained later). This method can be called by the app itself by calling AccountManager#addAccount() (requires a special permission for that) or from the phone’s settings screen, as seen here:
Add an account from the device’s Settings
Example:
@Override
public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType, String[] requiredFeatures, Bundle options) throws NetworkErrorException {
final Intent intent = new Intent(mContext, AuthenticatorActivity.class);
intent.putExtra(AuthenticatorActivity.ARG_ACCOUNT_TYPE, accountType);
intent.putExtra(AuthenticatorActivity.ARG_AUTH_TYPE, authTokenType);
intent.putExtra(AuthenticatorActivity.ARG_IS_ADDING_NEW_ACCOUNT, true);
intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
final Bundle bundle = new Bundle();
bundle.putParcelable(AccountManager.KEY_INTENT, intent);
return bundle;
}
getAuthToken
Explained by the diagram above. Gets a stored auth-token for the account type from a previous successful log-in on this device. If there’s no such thing – the user will be prompted to log-in. After a successful sign-in, the requesting app will get the long-awaited auth-token. To do all that, we need to check the AccountManager if there’s an available auth-token by using AccountManager#peekAuthToken(). If there isn’t we return the same result as for addAccount().
@Override
public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException {
// Extract the username and password from the Account Manager, and ask
// the server for an appropriate AuthToken.
final AccountManager am = AccountManager.get(mContext);
String authToken = am.peekAuthToken(account, authTokenType);
// Lets give another try to authenticate the user
if (TextUtils.isEmpty(authToken)) {
final String password = am.getPassword(account);
if (password != null) {
authToken = sServerAuthenticate.userSignIn(account.name, password, authTokenType);
}
}
// If we get an authToken - we return it
if (!TextUtils.isEmpty(authToken)) {
final Bundle result = new Bundle();
result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
result.putString(AccountManager.KEY_AUTHTOKEN, authToken);
return result;
}
// If we get here, then we couldn't access the user's password - so we
// need to re-prompt them for their credentials. We do that by creating
// an intent to display our AuthenticatorActivity.
final Intent intent = new Intent(mContext, AuthenticatorActivity.class);
intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
intent.putExtra(AuthenticatorActivity.ARG_ACCOUNT_TYPE, account.type);
intent.putExtra(AuthenticatorActivity.ARG_AUTH_TYPE, authTokenType);
final Bundle bundle = new Bundle();
bundle.putParcelable(AccountManager.KEY_INTENT, intent);
return bundle;
}
If the auth-token we got from this method is not valid anymore, because of time expiration or changed password from a different client, you need to invalidate the current auth-token on the AccountManager and ask for a token once again. Invalidating the current token is done by calling AccountManager#invalidateAuthToken(). The next call to getAuthToken() will try to log-in with the stored password and if it fails – the user will have to enter his credentials again.
So..where will the user enter his credentials? That’ll be in our derivation for AccountAuthenticatorActivity
This activity will show the user a log-in form, authenticate him with our server, and return the result to the calling authenticator. The reason we extend from AccountAuthenticatorActivity, and not just from the regular Activity, is the setAccountAuthenticatorResult() method. This method is in charge of taking back the result from the authentication process on the activity and return it to the Authenticator, who called this activity in the first place. It saves us the need to keep a response interface to communicate with the Authenticator ourselves.
I built a simple username/password form on my Activity. You can use the Login Activity Template suggested on the Android site. When submitting I call this method:
public void submit() {
final String userName = ((TextView) findViewById(R.id.accountName)).getText().toString();
final String userPass = ((TextView) findViewById(R.id.accountPassword)).getText().toString();
new AsyncTask<Void, Void, Intent>() {
@Override
protected Intent doInBackground(Void... params) {
String authtoken = sServerAuthenticate.userSignIn(userName, userPass, mAuthTokenType);
final Intent res = new Intent();
res.putExtra(AccountManager.KEY_ACCOUNT_NAME, userName);
res.putExtra(AccountManager.KEY_ACCOUNT_TYPE, ACCOUNT_TYPE);
res.putExtra(AccountManager.KEY_AUTHTOKEN, authtoken);
res.putExtra(PARAM_USER_PASS, userPass);
return res;
}
@Override
protected void onPostExecute(Intent intent) {
finishLogin(intent);
}
}.execute();
}
sServerAuthenticate is the interface to our authenticating server. I implemented methods such as userSignIn and userSignUp that return the auth-token from the server, upon a successful log-in.
mAuthTokenType is the type of token that I request from the server. I can have the server give me different tokens for read-only or full access to an account, or even for different services within the same account. A good example is the Google account, which provides several auth-token types: “Manage your calendars”, “Manage your tasks”, “View your calendars” and more.. On this particular example I don’t do anything different for the various auth-token types.
When I finish, I call finishLogin():
private void finishLogin(Intent intent) {
String accountName = intent.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
String accountPassword = intent.getStringExtra(PARAM_USER_PASS);
final Account account = new Account(accountName, intent.getStringExtra(AccountManager.KEY_ACCOUNT_TYPE));
if (getIntent().getBooleanExtra(ARG_IS_ADDING_NEW_ACCOUNT, false)) {
String authtoken = intent.getStringExtra(AccountManager.KEY_AUTHTOKEN);
String authtokenType = mAuthTokenType;
// Creating the account on the device and setting the auth token we got
// (Not setting the auth token will cause another call to the server to authenticate the user)
mAccountManager.addAccountExplicitly(account, accountPassword, null);
mAccountManager.setAuthToken(account, authtokenType, authtoken);
} else {
mAccountManager.setPassword(account, accountPassword);
}
setAccountAuthenticatorResult(intent.getExtras());
setResult(RESULT_OK, intent);
finish();
}
This method gets a fresh auth-token and do the following:
1. Existing account with an invalidated auth-token – in this case, we already have a record on the AccountManager. The new auth-token will replace the old one without any action by you, but if the user had changed his password for that, you need to update the AccountManager with the new password too. This can be seen in the code above.
2. You add a new account to the device – that’s a tricky part. When creating an account, the auth-token is NOT saved immediately to the AccountManager, it needs to be saved explicitly. That’s why I’m setting the auth-token explicitly after adding the new account to the AccountManager. Failing to do so, makes the AccountManager do another trip to the server, when the getAuthToken method is called, and authenticating the user again.
Note: The third argument to addAccountExplicitly() is a “user data” Bundle, which can be used to store custom data, such as API key to your service, right with the other authentication related data on the AccountManager. This can also be set by using setUserData().
After the log-in process done by this Activity, we have the AccountManager all set up with our account. The call to setAccountAuthenticatorResult() returns the information back to the Authenticator.
Now we have the process ready to go, but who will start it? How will it gain access to it? We need to make our Authenticator available for all the apps that want to use it, including the Android settings screen. Since we also want it to run in the background (The log-in screen is optional), using a Service is the obvious choice.
Creating the Service
Our service will be very simple.
All we want to do, is letting other processes bind with our service and communicate with our Authenticator. Luckily for us, the AbstractAccountAuthenticator, which our Authenticator extends, has a getIBinder() method that returns an implementation to IBinder. Our service needs to call it on its onBind() method and that it! The basic implementation takes care of calling the appropriate methods on the Authenticator by the request of an outside process. To see how it’s actually done, you can take a look on Transport, an inner class of AbstractAccountAuthenticator and read about AIDL for inter-process communication.
Here’s how our service will look like:
public class UdinicAuthenticatorService extends Service {
@Override
public IBinder onBind(Intent intent) {
UdinicAuthenticator authenticator = new UdinicAuthenticator(this);
return authenticator.getIBinder();
}
}
..and on the manifest we need to add our service with the
accountType is a unique name to identify our account type. Whenever some app wants to authenticate with us, it needs to use this name when approaching the AccountManager.
icon and smallIcon are icons for the account to be seen on the device’s Settings page and on the account approve page (more on that later).
label is the string that represent our account when listed on the device’s Setting’s page.
accountPreferences is a reference to a Preferences XML. This will be shown when accessing the account’s preferences from the device Settings screen, allowing the user more control over the account. You can check the stuff Google and Dropbox are letting you change about their account for some examples. Here’s an example of my own:
Account Preferences
Random stuff you may want to know
During my investigation I ran into some interesting scenarios that I thought I’d share, keeping your hair intact while working with this API.
1. Check existing account validity – If you want to get an auth-token for an account name that you stored yourself, check that this account still exist first by using the AccountManager#getAccounts*() methods. I’ll quote the AccountManager’s documentation:
“Requesting an auth token for an account no longer on the device results in an undefined failure.”
For me, the “undefined failure” was to bring the sign-in page and then do nothing after I submitted my credentials, so there you have it.
2. First in, first served – Let’s say you copied your authenticator’s code to 2 of your apps, thus sharing its logic, and altering the sign-in pages design on each app to fit the app it belongs to. In that case, the first installed app’s authenticator will be called for both apps when an auth-token will be requested. If you uninstall the first app, the second app’s authenticator will be called from now on (since it’s the only one now). A trick to overcome this will be to put both sign-in pages on the same authenticator, then use the addAccountOptions argument on the addAccount() method to pass your design requirment.
3. Sharing is caring..for security – If you try to get an auth-token from an authenticator that was created by a different app, which was signed using a different signing key, the user will have to explicitly approve this action. This is what the user will see:
Ahm..May I?
The “Full access to..” string is retrieved from the our Authenticator’s getAuthTokenLabel(). You can specify different labels for each auth-token type, being more user friendly on cases like this.
4. Storing the password – The AccountManager is not secured by any encryption method. The passwords there are stored in plain text. You can’t peekAuthToken() to other Authenticators (You’ll get a “caller uid X is different than the authenticator’s uid”), but a root access and some adb commands will do the trick. In the sample code I’m storing the password for the convenience of auto-login the user in case of token expiration. It’s the ultimate trade-off between security and convenience. In most cases I would take the secure road, but for some it’s not worth the inconvenience caused to the user. If someone has a root access and can run adb commands on your device – he can do much more damage than accessing your user’s “high scores” table..
Now what?
Now that you got familiar with this great service, you can download from Google Play the sample authenticator that I wrote. It will allow you to create an “Udinic account” on your device. The authentication will be against a Parse.com account that I created for this cause. These are the options you get on the sample app:
The getAuthToken button will query first all the Accounts from the type “Udinic” on the device. If there’s one, it’ll return its token by calling AccountManager#getAuthToken(). If there’s more than one, it’ll populate them on a dialog and let you choose which one you want.
The getAuthTokenByFeatures calls a cool convenient method on the AccountManager by the same name, that do all the work for you. It’ll query the AccountManager for accounts with the requested type, “Udinic”, and its behavior is as follows:
There are no accounts: Starts addAccount() to allow the user to add a new account. After that, it will automatically call getAuthToken() on the created account to get the token for it.
There’s one account: Get its auth token.
There are 2 accounts or more: Create an account picker dialog and return the token of the account the user picked.
If you want to invalidate the token, you can use the invalidateAuthToken button. Note: The Udinic authenticator knows how to recover from invalidated tokens, as seen previously on the sample code for getAuthToken(). Meaning, after invalidating the token the getAuthToken button will still return a token, but it’ll be only after he asks for it again from the server. You can confirm that by looking at the LogCat and see network communication to the server in that case. Removing the account is possible only through the device’s settings screen.
You can download the source code from GitHub: https://github.com/Udinic/AccountAuthenticator. There are 2 sample apps in there, allowing to play around with them since they both share the same Authenticator. For example: Use different signing keys for them and see the different flow for the user when one is asking for auth-token created by the other sample app. You can also try to create an apklib for the authenticator and reuse it across different apps. If you have a fix or a suggestion – don’t hesitate posting it here or as a Pull Request on GitHub.
This week I had the time to write a small and cool transition animation between Activities.
The regular transition animations between activities animate the Activity as a whole. I wanted to create an animation that split Activity A into 2 parts, animate them in the way out and revealing Activity B. Here’s a gif that illustrate this:
The idea is fairly simple:
1. Save Activity A as a bitmap
2. Split bitmap into 2 parts
3. Pass the 2 bitmaps to Activity B
4. Show the bitmaps on top of Activity B’s layout
5. Animate the bitmaps outwards
6. User is now seeing Activity B
The implementation was not as straightforward as I thought. I ran into some difficulties on the way, but I found solutions to all the problems I encountered. Let’s go step by step.
Note: This implementation requires holding a snapshot bitmap of the entire screen. For some devices that might be a very expensive operation due to low memory and/or large screen area. If you choose to use this animation – do it with care and don’t overuse it.
Save as Bitmap
In order to get a bitmap of the Activity, we can use this code:
On the first line, we get the root view for the activity. We find the view with the id of android.R.id.content, which is the FrameLayout that exist on every layout and contains the layout you put on setContentView(). Here’s how it looks on HierarchyViewer:
In order to get a bitmap of the root view, or any view for that matter, we call the getDrawingCache() method. This will return the cached bitmap of this view in case we have enabled the caching for it. That’s why we also call the setDrawingCacheEnabled() before that. If there isn’t a cached bitmap for the view – it’s been created on the spot.
bmp is the main Bitmap for the entire Activity. splitYCoord is the Y coordinate of the splitting point.
I create 2 smaller bitmaps. mBmp1 is the upper part of the larger bitmap and mBmp2 is the bottom part. Each part’s height is determined by the splitYCoord.
Pass the bitmaps to the next Activity
After I have the 2 bitmaps, I want to start the next Activity and put them on top of its layout. That way the user will see Activity A’s layout where in fact we already moved on to Activity B.
At first, I wanted to pass them as Extras of the Intent, it’s possible since Bitmap is Parcelable . The problem is the bitmaps are too large to transport in an Intent, due to size limitation for IPCs. This is the error I got:
!!! FAILED BINDER TRANSACTION !!!
There are few workarounds for this, including writing the bitmaps into a file and then read them back on the other end. I found the easiest and fastest way will be to just keep them as data members in a common area. I created a static class to contain the bitmaps and all the logic to create and animate them. More on that later.
Show the bitmaps on Activity B
After I start Activity B, disabling any default activity animation using overridePendingTransition(), I create 2 ImageViews to contain the previously created bitmaps, and presenting them on screen. I do that before calling setContentView() to avoid seeing Activity B’s layout ahead of time.
The ImageViews are added directly to the Window of the activity. This allows the ImageViews be on top of the soon-to-be inflated layout and gives more flexibility when deciding the location of each one of them on the screen.
The gravity states where we’ll put our layout in the window. Since we calculated the X,Y position of the bitmaps relative to the top of the screen – we’ll set the gravity to TOP.
Animate the bitmaps
After we created and positioned the bitmaps on Activity B, we can call setContentView() to inflate the Activity’s layout. After the layout is inflated we can start the animation that pushes the 2 bitmaps outwards, thus revealing the Activity’s layout.
mSetAnim = new AnimatorSet();
mTopImage.setLayerType(View.LAYER_TYPE_HARDWARE, null);
mBottomImage.setLayerType(View.LAYER_TYPE_HARDWARE, null);
mSetAnim.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationEnd(Animator animation) {
clean(destActivity);
}
@Override
public void onAnimationCancel(Animator animation) {
clean(destActivity);
}
...
});
// Animating the 2 parts away from each other
Animator anim1 = ObjectAnimator.ofFloat(mTopImage, "translationY", mTopImage.getHeight() * -1);
Animator anim2 = ObjectAnimator.ofFloat(mBottomImage, "translationY", mBottomImage.getHeight());
mSetAnim.setDuration(duration);
mSetAnim.playTogether(anim1, anim2);
mSetAnim.start();
The animation is a simple TranslationY animation that moves every ImageView outside the screen, each one to a different directions. I use hardware acceleration (read my last blog post to learn more about HW accelerated animations) and I do some cleaning after the animation is finished or canceled (removing hardware layer, removing the ImageViews from the window etc.).
How to use my Animation
So I was debating with myself what’s the best way to make it easier to use, without limiting the developer too much. The easiest way was to create a base Activity that the developer can extend and the actions will be taken care of without too much effort. The reason I didn’t do that is because I HATE extending from other base activities just to get some more features. If your application has it’s own base activity it can be very frustrating if every library will demand you to extend from their own branded Activity.
That’s the reason I created a simple class with static methods that do all the work. here’s the API:
/**
* Utility class to create a split activity animation
*
* @author Udi Cohen (@udinic)
*/
public class ActivitySplitAnimationUtil {
/**
* Start a new Activity with a Split animation
*
* @param currActivity The current Activity
* @param intent The Intent needed tot start the new Activity
* @param splitYCoord The Y coordinate where we want to split the Activity on the animation. -1 will split the Activity equally
*/
public static void startActivity(Activity currActivity, Intent intent, int splitYCoord);
/**
* Start a new Activity with a Split animation right in the middle of the Activity
*
* @param currActivity The current Activity
* @param intent The Intent needed tot start the new Activity
*/
public static void startActivity(Activity currActivity, Intent intent);
/**
* Preparing the graphics on the destination Activity.
* Should be called on the destination activity on Activity#onCreate() BEFORE setContentView()
*
* @param destActivity the destination Activity
*/
public static void prepareAnimation(final Activity destActivity);
/**
* Start the animation the reveals the destination Activity
* Should be called on the destination activity on Activity#onCreate() AFTER setContentView()
*
* @param destActivity the destination Activity
* @param duration The duration of the animation
* @param interpolator The interpulator to use for the animation. null for no interpulation.
*/
public static void animate(final Activity destActivity, final int duration, final TimeInterpolator interpolator);
/**
* Start the animation that reveals the destination Activity
* Should be called on the destination activity on Activity#onCreate() AFTER setContentView()
*
* @param destActivity the destination Activity
* @param duration The duration of the animation
*/
public static void animate(final Activity destActivity, final int duration);
/**
* Cancel an in progress animation
*/
public static void cancel();
}
In order to use it, just call this from Activity A when you want to animate to Activity B:
ActivitySplitAnimationUtil.startActivity(Activity1.this, new Intent(Activity1.this, Activity2.class));
And call this on Activity B’s onCreate():
// Preparing the 2 images to be split
ActivitySplitAnimationUtil.prepareAnimation(this);
// Setting the Activity's layout
setContentView(R.layout.act_two);
// Animating the items to be open, revealing the new activity.
// Animation duration of 1 second
ActivitySplitAnimationUtil.animate(this, 1000);
That’s it!
No need to extend anything, just 3 simple calls to static methods.
The code supports API14+ but it can easily be converted to work on older devices using NineOldAndroid.
A week ago I gave a talk about Android performance, presenting some old and should-be-known-to-all-developers methods, aside to new tools introduced in Jellybean. The talk was recorded and I’ll post a link here when it’ll be on the air here is the video:
I know that performance optimization tends to be pushed aside when developing a project, especially if you’re in a start-up company and all you do is pretty much “run” with the product.
On this post I’ll give you the toolsand knowledge to easily do a performance review and solve common issues in your app, rising it up to the challenge of smooth running.
Let’s start:
Overdraw
Overdraw is a simple concept to understand and since Android 4.2 – it’s easy to detect.
Overdraw: drawing something on top of something else.
If you draw a pink background and a button on top of it – you get an overdraw. That is because each pixel on the area of the button is drawn twice. Once in pink, when you draw the background, and another time in the button’s color when you draw the button. You cannot avoid overdraw completely. Overdraw up to 2x (=3 layers) on the whole screen is considered to be OK and depends on the GPU’s ability to draw all those pixels on the screen and still do that in 16ms per frame (thus achieving 60fps).
How to detect?
If you have Android 4.2 installed on your device, you can use the “Show GPU overdraws” under the Developer options. I wrote a small app to illustrate overdraw on my Performance Demo. The layout I created has a background color in white, on its upper half it has another layout with a white background and so on for this layout. The result – white screen, but with the “Show GPU overdraws” enabled we can see what really happens:
The blue color is 1x overdraw – every pixel got drawn twice in this area. The green color is 2x, light red is 3x and overdraw of 4x is on the stronger red color.
As a rule of thumb, you should have only up to small light red areas. If you get some 4x overdraws – you should probably consider reconstructing your layout hierarchy.
How to fix?
Well..it really depends on how your layout is built. You can go through your layout’s hierarchy and see for yourself if you can reconstruct it differently, eliminating some overdraws.
One popular optimization is removing the window background. There’s a default background for every Android app, so if your main layout has it’s own opaque background – there’s no need to draw the default one as well. That’s why on the image from Performance Demo you can see that the bottom half of the screen has 1x overdraw, even though we have only one layer of white background.
The solution is simply removing the background by setting the android:windowBackground attribute to @null on your theme, or calling getWindow().setBackgroundDrawable(null) on the Activity’s onCreate callback.
Another interesting way is to use Tracer for OpenGL that comes with the SDK and can be run from the Device Monitor. Since everything is ultimately translated to OpenGL commands, this tool will show you how your screen is drawn, step-by-step, component-by-component. Here’s an example of how it looks:
This is an example of running the tool on Any.DO’s main layout.
The tree on the left is the layout hierarchy and the OpenGL commands used to draw every component in it. The blue marked lines are the one that let you see the preview on the right, the image that got drawn up to this moment.
Going down the tree, you can spot 2 steps where the image on the right is the same, making you think if drawing the last component was really necessary. You can also spot components that got drawn but then got covered by another component, or “Overdraw”.
This tool requires you to connect a phone with JellyBean to your computer. The process is pretty heavy, but only a few frames are required in order to detect problems. You can read more about the process in the Official Android Blog.
Here are some screenshots that proves nobody is saint:
Detect UI Glitches
If you’re using your app and it feels “un-smooth” but then again you’re not sure if it’s just your imagination – you can profile the GPU rendering of the last ~2 seconds to see if there are any glitches there.
For that, you need to first enable the “Profile GPU rendering” on your JellyBean device’s Developer options. After that you can use your app and whenever you want to get the profiling information, use the following adb command:
adb shell dumpsys gfxinfo com.your_package_name
You’ll get a lot of info about the memory usage of the graphics, the display lists that used to draw this screen and the time, in milliseconds, it took the GPU to render every frame, divided to 3 phases:
The Draw part is the time it took to generate the Display Lists by running the onDraw() methods of the components.
The Process part is the time it took the renderer to execute the display lists. More views = more time.
The Execute part is the time it took to actually send the frame to the compositor. That’s when the back buffer is swapping with the front buffer to actually show the frame you just built.
The Draw+Process+Execute should be <= 16 ms in order to run at 60fps. It’s easier to see that if you copy that table into a spreadsheet and create a stacked columns graph. Here’s a graph that I took from Any.DO:
The X coordinate is the frame number, the Y coordinate is the time in milliseconds it took to render the frame.
On those 2 seconds, taken from our new Any.DO Moment feature, I ran 2 hardware accelerated animations sequentially. We can see they both ran smoothly by the fact that all the frames took < 16ms to render.
Another interesting observation is that the frames on each animation, frames 1-55 and 80-128 don’t have much time spent on Draw. It makes a lot of sense after understanding how Hardware Acceleration works. On these frames the onDraw() is only called when the view is invalidated, which is avoided by the use of Display Lists and hardware layers on the animated component. I highly recommend understanding the way hardware acceleration works for better understanding how your app views are rendered on the screen.
Systrace
Systrace is a great tool to get the execution times for your process and other system processes. It can be started from the DDMS and outputs a cool HTML that allows you to navigate the time line of all the processes that ran at that time.
Since Systrace is a powerful tool that requires experience to identify problems, I won’t elaborate on it here, but you’re welcome to read more about it on the Android site.
Hierarchy Viewer
That’s a must-have tool for anyone who writes any layout on Android. Embedded in the Device Monitor, this tool shows the views tree of the currently presented layout on the device, and lets you analyze the time consumption for each component, and compare it to the other components. There are also good non-performance related information there, such as the components’ properties and the layout’s preview, allowing you to see where each component is positioned on the screen.
Method Profiling with Traceview
Traceview is such an important tool, that I expect from any good Android developer to know how to use it. You kick it from DDMS (“Start method profiling” button) or from code using the Debug class, and after stopping it you’ll get a list of all the methods that ran in that period of time.
The important parts are the percentage of the time consumed by each method. Inclusive % means the running time percentage for this method AND its child functions. The Exclusive % means the same but only for the function itself, without its child functions. You can easily drill down on each function, and see which of its child functions took most of the running time, as demonstrated here:
:
On the picture above we can easily see that the onClick() method on the Main class took 99% percent of the running time, and its child function, findDivisors2(), was the heaviest inside it. We found the problem! now we can go to the function’s algorithm and try to make it to work faster.
The sample code for this experiment is on the Performance Demo project.
But what will happen if your code seems to run just fine, but the Garbage Collection seems to take a lot of CPU time? This can be seen on Traceview by seeing something like this:
This means that our GC is working too hard on cleaning, which could indicate you allocate too many objects for it to handle quickly.
Helping out the GC
How do we know what objects we create too much of? Where should we even begin looking? Let’s get familiar with some useful tools:
Allocation Tracker
The Allocation Tracker comes with DDMS and it’s simple and very powerful:
After you start tracking the allocation, using the “Start Tracking” button, you can get the currently allocated object at any time by clicking the “Get Allocations” button. The list of allocated object will be loaded with sweet info like allocation size, and a stacktrace for the location where each object was allocated, giving you the power to catch that punk who’s creating all those String[] objects.
Eclipse MAT
The Eclipse Memory Analyzer Tool is a tool which gets an HPROF file, and analyze it.
HPROF is a standard for presenting heap memory snapshot from the JVM. You can dump an HPROF file from within the DDMS, or by code. The problem is, There aren’t any good HPROF analyzers for the Dalvik VM heap dumps (which is the one we just got from the DDMS). Alternatively, J2SE, the standard Java for desktops and servers, has been here for a longer period and has great tools to analyze its HPROF dumps. Luckily for us, the Android gods sent us the hprof-conv (bundled in the Android SDK) which converts that alien dump to something J2SE analyzers can read. So, after dumping the heap info using the code or DDMS using this button:
We’ll use the hprof-conv tool to convert from Android’s HPROF file, to a standard HPROF file. After that, we’ll open the file in Eclipse MAT, and we can get some cool reports like this:
We can see all the data in different views: Histogram view allow us to see all the classes and how many objects each one has. That why it’s easy to see if the GC got overdosed by a particularly class.
Dominator tree is showing who has reference to who. It’s also called the keep-alive-tree since the dominating object is the reason all its descendants are not cleaned by the GC.
You can also run queries on the data and search for objects that has some properties (e.g. String objects that has the same string in it).
Bitmaps allocation tips
Since bitmaps are the cause for many memory issues, I decided to bring up a few tips of my own specifically for that:
1. inJustDecodeBounds – This option can be set on the BitmapFactory in order to load just the meta data, like the bitmap’s dimensions. This is useful if you don’t know the size of the bitmap and might need to scale it down to fit your ImageView. This way you avoid allocating a big bitmap just to scale it down later.
2. inBitmap – Another attribute that can be set on the BitmapFactory.Options, allowing you to pass an already allocated bitmap to reuse when decoding a new bitmap. There are some restrictions when doing that, so you better read a little before using it.
3. inSampeSize – This option, when passed a value > 1, will get the bitmap decoder to output a smaller bitmap by the factor of the value you set. It’s good for previews and thumbnails. This is done more efficiently than allocating a bitmap and scaling it down.
Hardware Acceleration
I can write an entire post just about this, but I think it’s better for you all to read about it and watch some talks about it, to fully understand how it works.
When using hardware acceleration, you can use layers to accelerate your animations.
A layer is a texture of the animated component, performing the animation on it will be more efficient because the animation framework doesn’t redraw the component every frame, it only animate the layer we created. Think of it as taking a bitmap of your component and move/fade it instead of doing that to all the views in the component we animate.
You can use layers in software or in hardware. When you’ll use a hardware layer, the texture will be saved inside the GPU, causing all the manipulations on it (move, fade, rotate etc.) run very efficiently. Here’s an example of how to do this:
We set the layer type for our component, mCurrentPanel, and we add a listener to the end of the animation, to remove that layer. The layer needs to be removed in the end because the GPU’s memory is limited, so cleaning is required.
Android performance case study – a blog post about a step-by-step process it took Google framework developer, Romain Guy, to find performance issues on his favorite (and mine) twitter client.
As a busylazy developer, I always try to automate repeating routines. Those sequence of actions are getting annoying after a few times and always make me gasp. That’s why some of my time is dedicated to writing small scripts to make my life easier, and the development process faster and anger-free. Most of them are very specific to the apps I’m working on, and some are more generic. I’ve pushed them to a new repository on GitHub, and it will updated with more scripts when I’ll make some more, or generalize other existing scripts that I use.
ADB Batch Scripts
ADB – Android Debug Bridge, is a very powerful tool. You can control a lot of features on the phone. Furthermore, granting yourself with a ROOT access will bring many rewards, as getting files in and out the file-system, manipulating system files and more. I highly recommend rooting your development phone; it’ll prove itself worthy towards the trouble that it might cause in some devices. I’ll also note that the root access from ADB is limited on production builds (stock ROMs) vs. custom ROMs (e.g. Cyanogenmod), so I prefer to just flash a custom ROM on my development phone, making me the master of its domain!
Most of my repeated ADB commands are for DB access. I need to check the app’s SQLite DB to see that my code did everything right. So I wrote this windows batch script:
First, I request to start ADB with root access, not applicable on stock ROMs (as least not easily), and pulling out the DB file to a temp location. The first time running this will show an error, since the adb root command restarts the ADB daemon on you computer, which causes the next ADB command not to find the device momentarily. The second time running this will be the charm. To open the DB I use SQLite Browser, which is very simple and lite. Running SQL on the DB is buggy, but for simple table viewing – it’s good enough.
If we want to modify the DB on the device, I wrote a small script to receive any SQL statement, and run it directly on a DB inside the device:
Very simple. Using the sqlite3 command, we can get a SQLite prompt that’s running on the device itself. If you don’t have the sqlite3 file in your device, which can happen on stock ROMs mostly, you can use this nice article that helped me do it on my Galaxy Nexus, or just search Google.
Another common thing I do, is executing specific services and activities, great help for my debugging life. The syntax is simple, but here’s an example to show how easy that it:
adb shell am startservice -n <package name>/<Service full class name> [<extras>]
adb shell am start -n <package name>/<Activity full class name> -a android.intent.action.MAIN [<extras>]
I can pass extras, action and even activity attributes as clear-top, no-animation and more. I recommend reviewing all the options for those commands, you might get ideas how to automate some of your routines.
Some tests require installing/uninstalling the app to clear the data fast or to test upgrading code. The adb install and adb uninstall will do the trick here. Very simple to use and fast. I usually install the newest version of Any.DO on my device using an ADB command, rather than from Google Play. It’s just faster!
Python Scripts
Using Python, I could write more complex stuff, like analyzing a system dump, pulling only the important information. If you’re familiar with ADB, you probably heard of “adb shell dumpsys”. This command will print a dump of the system, containing LOTS of data about memory allocations, registered receivers, apps permissions and more. You can call “adb shell dumpsys <service name>” to get a specific service’s information. Some examples:
# All the information about accounts on the device
adb shell dumpsys account
# The battery state
adb shell dumpsys battery
# All the registered alarms on the device
adb shell dumpsys alarm
The problem with the last command – it prints out too much garbage. There are lots of alarms registered on your device at any given moment, and the dump’s printing format is not exactly an eye candy. Since there’s a lot of alarm handling on Any.DO, I needed a clear and easy way to look only at the relevant information. That’s why I wrote this script:
p=subprocess.Popen([r'adb', 'shell', 'dumpsys alarm'],
stdout=PIPE, stderr=PIPE,
shell= True,
cwd='C:\\')
out, err = p.communicate()
p.wait()
pp = pprint.PrettyPrinter(indent=4)
lines= out.split('\n')
alerts = [["RTC TYPE", "When", "Repeat", "pkg", "Type"]]
for i in xrange(len(lines)):
if lines[i].replace(" ","")[:3]=="RTC":
# Extract the information we
rtc_type = lines[i].strip().split()[0]
when=re.findall('when=([0-9a-z+]*)',lines[i+1])[0]
repeat=re.findall('repeatInterval=([0-9a-z+])*',lines[i+1])[0]
intentType=list(re.findall("PendingIntentRecord{(\w+) ([\w\.]+) (\w+)", lines[i+2])[0])
# If the user has passed a package name as an argument
# we'll filter all other packages' alarms
if len(sys.argv) > 1:
if intentType[1] == sys.argv[1]:
alerts.append([rtc_type, when, repeat, intentType[1], intentType[2]])
else:
alerts.append([rtc_type, when, repeat, intentType[1], intentType[2]])
out_lines = [""] * len(alerts)
# Format the data nicely to columns
for column in xrange(len(alerts[0])):
for alert_index in xrange(len(alerts)):
out_lines[alert_index] += str(alerts[alert_index][column])
line_size = max(map(len, out_lines)) + 5
for alert_index in xrange(len(alerts)):
out_lines[alert_index] += " " * (line_size - len(out_lines[alert_index]))
for l in out_lines:
print l
All I do here, is getting the output from the command “adb dumpsys alarms”, and extract the information I need the most:
1. RTC type.
2. When will the alarm go off.
3. The repeat interval of the alarm, if there is one.
4. The intent type that the alarm will invoke. Could be a Service, Activity or a Broadcast.
Here’s an example output:
Passing the package name as an argument will print only its relevant alarms.
Another issue I encountered was activities’ stack handling. All those activities’ attributes, “singleTop”, “singleInstance” and more, can get you utterly confused about what would happen when you press the back button. Will you be navigated to the previous activity? will you be thrown to your main activity? or is it to the launcher screen? Reading the documentation will help you understand what should be, and using my “Activity stack viewer” will help you see what is happening back there. This script is parsing the dumpsys, as the previous script did, and prints the activities’ stack grouped by their package name:
Here I can see that on the Twitter app, I opened the post activity from the home activity. I see all the other paused activities that haven’t been destroyed yet by the operation system. Passing a package name as an argument will print a filtered list;
That’s all for now. I hope I helped at least some of you to do thing better. I’ll keep that GitHub repository updated with new scripts I’ll write. If you have a script to contribute – please comment to this post about it.
This week I decided to publish the code from an old project I did couple of years ago, the FAT32 Sorter. I wrote a little about it in here, and a lot about it in there. As I went through the code, make final adjustments before releasing it to the wild, I saw other old projects of mine. Just by reading those folder names, my mind has started reciting the story behind each and one of them. Ah… memories…
When I started coding, around the age of 14, I wasn’t attracted to write small games, as my classmates were doing from time to time. I wanted to solve problems that I find myself get annoyed by, or to make stuff easier for me. So whenever I got frustrated by something, I immediately started thinking – “How can I create a better experience?”.
And I did.
I decided to release another project to the open source community. Before I’ll introduce it –I’ll explain the story behind it: As a heavy Windows user, I tried to tweak it as much as I can, making the glove better fit my hand. I wanted to enable the “Hide extension for knows file types” property. This helps me rename the file name without messing with its extension. But, I also wanted to be able to rename the file’s extension easily (Yes! I did rename extensions quite often. How did you write .BAT files if not from a .TXT file?!). Since Windows’ file properties didn’t give an option to edit the extension, I created RenameExt, which adds a context menu option for that:
The new option raises a minimal dialog to do the operation I needed
Of course I handled all the cases where you select multiple files, and not necessarily with the same extension. Since Windows Vista, when you rename a file, the file’s extension is excluded from the selection, so it’s easier to rename just the file name. I don’t use RenameExt anymore, but if you want to check out the code – here it is.
Another utility that I wrote, came due to a computer failure, where the only option was to format the hard-drive and start fresh. The problem – I had a big and organized Favorites folder, with all the websites I kept close. Back than, we didn’t have auto-sync to all the favorites, like those spoiled kids have now, so I had to back them up myself. Since I couldn’t get Windows to load, I did that using DOS. The problem: DOS does not support long file names, at least not the DOS I had at that time. This means all the favorites’ titles just got truncated to shit like “HOWSTU~1.url”, which ruins any chance to understand what it links to. The solution: FavoriteOrganizer.
This small utility scans all the .url files, go to the website they refer to, get the title from the HTML file and rename the .url file to that title. It identifies dead links and webhosting service pages, which probably means that this site is no longer exist (Well, excluding some ACTUAL webhosting sites I kept there..). My favorites were saved, only to be completely deleted a few years after that.
There’s also a VB project that I wrote to solve a very specific problem I had with my brother – music. My brother and I have different taste in music, but some genres are common to both of us. To save space, we had one music folder with all the music, but each have his own Winamp playlist with all the songs he listens to. It’s not like today, where I have over 10,000 songs, we had maybe a 100, each and one of them were handpicked. You can’t afford downloading full discographies when you download in a rate of 7 KB/s at best. Downloading new songs and moving them to the common music directory caused a lot of problems, since we forgot to let each other know about new stuff that the other party might find interesting in, causing duplicates and stupid arguments. That’s why I wrote the SongsOrganizer:
It’s in Hebrew, but I’ll explain: The screen on the left side presents all the newly downloaded songs that are still in the download folder, waiting to join their friends in the music folder. Currently – there are no songs to transfer. Each user can see the song’s details and even play it. If the current user wants it, he presses the button that says “Transfer song” which causes this chain of events: Moving the song to the music folder, add the song to the current user’s playlist and save this song’s information in the internal DB. When the other user logs in, He can see all the songs the other user has moved, and click on the “I want too” button, which add this songs to his playlist too. Neat huh? This really made our lives much easier, at least until we each got a computer of his own .
After a while, I got attracted to mobile development. J2ME was the first platform I learned, followed by Symbian and of course – Android. Using the mobile phone, I could solve a different kind of problems I encountered. The first JAVA supporting device I had was the Nokia 3550
It was really cool, it even had colored screen! The first problem I solved with it, was reading the menu at dark bars. We all used the light from our mobile devices, but it kept turning off, and was not bright enough. So I thought – why not create an app to light the screen all the time with white color? And that’s how FlashLight was born. Couple of months after I released it to the internet, I saw other apps do the same, and now we have dozens of those, but back then – I was the first one. No app stores were exist, so I can’t really know that for sure, but I did my research before that.
I also researched for an idea to create an app to keep all my passwords on my mobile device, and be able to sync them with my computer. I wrote the stuff I need to investigate on this To-Do list I created:
Even back then I was into To-Do lists Eventually I didn’t complete this project due to technological difficulties. Today I’m a happy user of KeePass on my PC and Android, and I sync the data using Dropbox. Much easier!
Last but not least, is my University project I did with a close friend of mine. We wrote a chat app called ChatWithME, allowing PC and mobile clients to chat together. We wanted to make something cooler than just a regular server-client chat, so besides writing a beautiful J2ME chat client a person can write in a week, we give the mobile users the option to chat using a server connection or Bluetooth, which saves precious KBs if we want to speak with our classmates during a lecture.
We got an A+ for that project. I also found some small Symbian apps that I wrote, C# projects and more, but they are less interesting than those are.
It’s been a while since I wrote a small project of my own, maybe it’s time? The satisfaction of solving my own problems, my way, is priceless. The feeling that I get from seen my product slowly work, is like a drug, addicting and lifting. But what know? Could it be that I’m more tolerant than I used to? Or is it laziness? Either way – I need a side project. Time? I’ll find some..
Quite recently, we added a sync feature to Any.DO. The users can sync all their tasks to Any.DO’s server, allowing them to access their tasks from our Android, iOS and Chrome clients.
Our data structure is a classic fit to REST API architecture. After getting our server ready, it was now the time to teach the Android client how to “talk the talk”. I didn’t want to use simple HTTP requests, constructed to use our REST API. I wanted to use some library to make my life easy, and my code readable. I also didn’t want to reinvent the wheel, so I did my research. I found some good and simple libraries for Android, as Resty, but then I found a more elegant solution for that – RestAdapter in Retrofit by Square.