Leonids Lib 1.2 – Meteor Shower

I just released an update of Leonids Lib. It includes feedback from previous versions both from github and the workshop I gave at GDGFestDublin.

Changes

From this version on, speed and acceleration are using dips. This makes a lot of sense, since the library should work together with the standard concepts of the Android framework. Animations should me much more consistent among different pixel density screens now.

Previous versions were using pixels, so you may want to review your parameters when you update.

New Features

There are some new configuration options:

  • emitWithGravity: Allows you to emit from a specific side of the View and particles will be emitted along all the edge of the View. i.e. Gravity.BOTTOM will create a rain-like effect. Default is Gravity.CENTER.
  • updateEmitPoint: Allows to dynamically change the point of emission for the particle system (useful to follow the touch along the screen)
  • stopEmitting: Will stop creating new particles, but the existing ones will keep animating (this is different from cancel, which also stops the already spanned ones)
  • emit now has methods to emit from a specific point on the screen given x and y instead of from a View.

New Examples

Also, new examples are being included to showcase the new features:

  • Emit with Gravity: Simulates a rain-like effect using Gravity.BOTTOM.
  • Follow touch: Creates a trail of stars following the touch on the screen.

libdemo_rain

You can also check Leonids Lib github page and/or get Leonids Demo from google play.

KendamApp 2.0

There is a new version of KendamApp – The Kendama App out there. It includes 32 new videos and my favourite feature so far: Self Certification.

MTG Tracker on Google Play

Self Certification

Until now you could track your accuracy per trick, and then see how close you were to pass an exam, but an actual exam… that is another story.

This new feature allows you to try for a self certification. It tracks all the attempts of all the tricks and it tells you if you passed or not the grading.

As in a real exam, you don’t have to keep going with a trick after you’ve completed the required hits, and as in a real exam, you stop as soon as you miss one trick.

It also keeps track of your attempts to the grading. Note that the tricks performed during the self certification are not added to the trick tracking feature, it is a different feature.

An image is worth a thousand words, so here’s a screenshot of the self certification in action.

KendamApp Self Certification

Happy clicking!

Accessing expansion patch files bug (and solution)

You may have used expansion files on Android. They are very handy when your app goes over 50Mb which, for games, happens pretty soon. In my case I have KendamApp – The Kendama App which has an extensive library of videos included.

The expansion files are organized on a main and a patch files. Each of them can be up to 2Gb. Since uploading them can be a pain, you can reuse them from one version to the next.

There are 2 libraries provided with android SDK to help managing expansion files:

  • downloader_library: Which purpose should be obvious.
  • zip_file: Which is a nice utility to manage expansion files via a content provider. You should be using it if you are using videos.

Also, if you are going to use videos, do not compress them when zipping the obb file.

Updating only with a patch file

Essentially, if you are going to add a few assets, it is better to use a patch file and reuse the main file. It will save lots of bandwidth and time.

You don’t have to re-upload the main file and users do not need to re-download it. Everyone wins.

Except that it may not be too straight forward when using the zip_file library.

The first pitfall (a.k.a. the undocumented feature)

First thing first, you should know that if you do not add some meta-data to the AndroidManifest, the library is going to look for the versions that match with the version number of the app. I don’t recall reading this in the documentation. I actually figured it out by reading the code.

So, the content provider on your AndroidManifest should look like this:

<provider android:authorities="com.plattysoft.zipprovider" android:name="com.plattysoft.provider.ZipFileContentProvider" >
   <meta-data android:name="mainVersion" android:value="17"/>
   <meta-data android:name="patchVersion" android:value="18"/>
</provider>

The second pitfall (a.k.a. the terrible bug)

Then, I realized that every time I tried to watch one of the new videos the app was crashing. I checked for the main and patch files and they were properly downloaded and inside the obb directory.

Something weird was going on.

Digging with the debugger, I ended up in a function that is supposed to return an string array with the name of the available expansion files based on the version numbers and after checking that the files do exist.

static String[] getAPKExpansionFiles(Context ctx, int mainVersion, int patchVersion) {
   String packageName = ctx.getPackageName();
   Vector<String> ret = new Vector<String>();
      if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
         // Build the full path to the app's expansion files
         File root = Environment.getExternalStorageDirectory();
         File expPath = new File(root.toString() + EXP_PATH + packageName);

         // Check that expansion file path exists
         if (expPath.exists()) {
            if ( mainVersion > 0 ) {
               String strMainPath = expPath + File.separator + "main." + mainVersion + "." + packageName + ".obb";
               File main = new File(strMainPath);
               if ( main.isFile() ) {
                  ret.add(strMainPath);
               }
            }
            if ( patchVersion > 0 ) {
               String strPatchPath = expPath + File.separator + "patch." + mainVersion + "." + packageName + ".obb";
               File main = new File(strPatchPath);
               if ( main.isFile() ) {
                  ret.add(strPatchPath);
               }
            }
         }
      }
      String[] retArray = new String[ret.size()];
      ret.toArray(retArray);
      return retArray;
}

Except that it was returning a single string and not two. So, paying extra attention I noticed this specific piece of code.

if ( patchVersion > 0 ) {
   String strPatchPath = expPath + File.separator + "patch." + mainVersion + "." + packageName + ".obb";
   File main = new File(strPatchPath);
   if ( main.isFile() ) {
      ret.add(strPatchPath);
   }
}

Of course it couldn’t find the patch expansion file, it is constructing the name using the mainVersion number instead of the patchVersion. Event the File variable is called main!

Copy and paste is an anti-pattern.

I have checked the latest version of this library that comes with the android SDK and the bug is still there. I’d check where the code is and send a push request. In the meantime, you know what you have to change to fix it.

Safe scenarios

You would not encounter this bug if:

  • You are not using the zip_file library.
  • You are not using a patch file.
  • Your main and patch files have the same version number (you update both).

MTG Tracker 5.9

It’s been a while since the app became version 5.X, hopefully this will be the last update before we move to 6.0, which will include material design.

But let’s focus on this release. Commander 2014 is about to hit the shelves and here is another update of MTG Tracker.

MTG Tracker on Google Play

ChangeLog

  • Added Commander 2014
  • Added Duel Deck: Speed Vs. Cunning
  • Improved filters on card lists (notice of filtering and option to clean the list)
  • Fixed CMC sorting (cards with 10+ CMC were out of order)
  • Fixed name of Valor, Call of the Herd & Altar of Dementia

Card Lists in detail

Until now, there was little to none information about if a list was being filtered or not, just the amount of cards displayed Vs. the total cards in the list.

In previous versions, the filter criteria was shared among card lists, which was a bug that has been solved. Now each card list has now its own criteria.

Also, filters are now cleared when you exit the card list. Before this version they were stored even among application runs, bringing lots of confusion. Combined with the previous bug, it was quite confusing. I hope to have solved all that issues.

Finally, there is a new easy & prominent way to clear the filter of a list as soon as some cards are being hidden by the filter.

device-2014-11-07-162517_framed (3)

Happy taping.

GDGFest Dublin & Playful Design

Playful design is a term that comes from the games industry, it means juiciness, it means maximum feedback for minimum input, it means delight the user.

In my talk at GDGFest Dublin,  I talked about animations, transitions and how playful design fits into material design.

Playful design works at subconscious levels on the users, they prefer to use your app to another one, but they won’t be able to tell why.

This has been one of the big differences between Android and iOS: How the default components managed the transitions. It seems minor, but devil is in the details. With material design Google has made a big statement of just how important playful design is.

It is very easy to improve the playfulness of any app with very simple animations that are available on the Android framework. That will make your users happier, without them being able to tell you why.

The slides of “Playful Design: What, Why and How” are available on Google Docs.

IMG_20141101_122952

MTG Tracker 5.7

Another core set is here: Magic 2014 Core Set, and another update of MTG Tracker is here as well.

Apart from the new set, there are a few other improvements:

  • Added Magic 2015 Core Set
  • Improved format validation (deck size & number of cards)
  • Fixes in Tournament mode
  • Minur UI and navigations tweaks
  • Added setting to disable animations on the life counter
  • Stability improvements

In particular, I want to talk about the improvements on format validation.

Improved format validation

Until now the format validation checked if the cards were valid or not. Just that.

With this update it will validate that you don’t have more than 4 copies of any card (except basic lands and *cough* Relentless Rats)

It will also validate that any constructed deck has at least 60 cards, for unknown formats the lower limit is 40 cards.

Finally, for EDH, it will specifically check that you have exactly 100 cards (general included) and that you have one copy of each card (except, again, basic lands and Relentless Rats)

In future updates the restricted list will be added to vintage with proper validation.

MTG Tracker on Google Play

MTG Tracker 5.6

WotC has just released a new set designed for draft: Conspiracy. As any new set, it has new cards, and so, a new version of MTG Tracker is released.

MTG Tracker on Google Play

Changelog:

  • Added Conspiracy
  • Added Modern Event Deck
  • Added option “Import into List” on Card Lists.
  • Minor UI tweaks
  • Improved stability

A bit more in detail

So, in addition to including Conspiracy and Modern Event Deck, other improvements have been done.

MTG Tracker has migrated away from ActionBarSherlock and now uses the official ActionBarCompat and DrawerMenu. This visually only means that the icon on the top left shows three lines when it opens a menu and an arrow when it goes back. Subtle, yet important.

The drawer menu seems to be hard to discover, so now the dashboard adds two new items, one of them called “More…” which opens the side menu. You can compare the old and new dashboards and also see the difference in the action bar icon (arrow Vs. three lines).

dashboard_comparison

Some animations have been added to the card display and the life counter, they are meant to make the user experience more enjoyable with a more playful design.

When we added multiple lists, the functionality to import cards from a text file inside an existing list was missed. It has been added again, now named “Import Into List”

And a few bug fixes, specially crashes when browsing many cards.

cardshark_header

Leonids Particle System Lib

Leonids is a particle system library that works with the standard Android UI. It is Free Software and is available on GitHub.

You can download Leonids Demo from Google Play to check out what can be done with it.

The library is extremely lightweight, it is just a jar file of 18Kb you can add to your project. You can download LeonidsLib.jar from the project page on GitHub.

Why this library?

Particle systems are often used in games for a wide range of purposes: Explosions, fire, smoke, etc. This effects can also be used on normal apps to add an element of “juiciness” or Playful Design.

Precisely because its main use is games, all engines have support for particle systems, but there is no such thing for standard Android UI.

This means that if you are building an Android app and you want a particle system, you have to include a graphics engine and use OpenGL -which is quite an overkill- or you have to implement it yourself.

Leonids is made to fill this gap, bringing particle sytems to developers that use the standard Android UI.

Code examples and features

You can get the code for all the examples on GitHub, but let’s get to the basics.

Simple one shot

Creating and firing a one-shot particle system is very easy, just 3 lines of code.

new ParticleSystem(this, numParticles, drawableResId, timeToLive)
.setSpeedRange(0.2f, 0.5f)
.oneShot(anchorView, numParticles);

When you create the particle system, you tell how many particles will it use as a maximum, the resourceId of the drawable you want to use for the particles and for how long the particles will live.

Then you configure the particle system. In this case we specify that the particles will have a speed between 0.2 and 0.5 pixels per milisecond (support for dips will be included in the future). Since we did not provide an angle range, it will be considered as “any angle”.

Finally, we call oneShot, passing the view from which the particles will be launched and saying how many particles we want to be shot.

This produces a fireworks-like effect as you can see here:

Leonids_one_shot

One Shot – Dust simulation

As an example of something used in production, this dust simulation is almost identical to the one implemented on the game Rabbit and Eggs, but made with Leonids instead of AndEngine.

new ParticleSystem(this, 4, R.drawable.dust, 3000)
.setSpeedByComponentsRange(-0.07f, 0.07f, -0.18f, -0.24f)
.setAcceleration(0.00003f, 30)
.setInitialRotationRange(0, 360)
.addModifier(new AlphaModifier(255, 0, 1000, 3000))
.addModifier(new ScaleModifier(0.5f, 2f, 0, 1000))
.oneShot(findViewById(R.id.emiter_bottom), 4);

It sets an initial rotation range and then 2 modifiers for Alpha and Scale. Using modifiers is the advanced way of managing a particle system. It allows more flexibility about the starting and end times.

The parameters for the modifiers are: initialValue, endValue, startTime and endTime. In this case, we do a scale from 0.5 to 2 in the first 1.5 seconds and a fade out from second 1 to 3.

We also set an external acceleration simulating wind.

And it looks almost exactly like the one in the game, but on a standard Android UI:

leonids_dust

Using emitters – Confeti

Another example we used on Rabbit and Eggs was confeti. This is done using two emitters one on each side of the top of the screen

new ParticleSystem(this, 80, R.drawable.confeti2, 10000)
.setSpeedModuleAndAngleRange(0f, 0.3f, 180, 180)
.setRotationSpeed(144)
.setAcceleration(0.00005f, 90)
.emit(findViewById(R.id.emiter_top_right), 8);

new ParticleSystem(this, 80, R.drawable.confeti3, 10000)
.setSpeedModuleAndAngleRange(0f, 0.3f, 0, 0)
.setRotationSpeed(144)
.setAcceleration(0.00005f, 90)
.emit(findViewById(R.id.emiter_top_left), 8);

Which looks like this:

leonids_confeti

Other details

Leonids requires minSDK 11 because it uses ValueAnimators. It should be very easy, however to use the compatibility library and make it work on Gingerbread.

The library is Free Software, you can use it, extended with no requirement to open source your changes. You can also make paid apps using it.

MTG Tracker 5.5

There is a new set coming out -Journey into Nyx- and as usual there is a new version of MTG Tracker, but it does not only add the cards from Journey Into Nyx and Duel Decks: Jace vs. Vraska, it also has some new features.

MTG Tracker on Google Play

Multiple Card Lists

Many people was using collection and / or wishlist for keeping multiple lists by saving them and importing them again. That is quite inefficient, so now you can have as many card lists as you want.

Want a list for the top priority cards you want? What you have borrowed to someone? The cards in your Drafting Cube? Which ones you are willing to trade? The missing cards for a deck?

Now it is up to you, create a list, name it, and you can use it for whatever you want.

multiple_card_list

Playtest Improvements

Playtest is nice, but there was no way to keep track of what was tapped and what was untapped. For quick tests, you can track it in your head, but that is far from ideal.

From this version you can tap / untap the cards on the battlefield. And yes, they do untap when you click next turn.

playtest_tap

Also, some people complained that they exited playtest by clicking back accidentally. For those cases there is a new setting to display a confirmation dialog before exiting. I know some people will love it.

Notes for Decks

Another feature requested many times is to add notes to decks. There is now a 3rd tab on each deck where you can keep your notes.

More options for prices

Card prices is one of the features people like. To save network traffic the prices are cached for 3 days, but when some cards get banned or unbanned prices may change quickly.

Since this version, you have new settings for how long you want to have the price cached (and to clean all prices manually) and the option to show Normal / Foil or Low / Avg / High (if the price provider has that).

MTG Tracker on Google Play